Spark Scala - 拆分字符串语法问题
Posted
技术标签:
【中文标题】Spark Scala - 拆分字符串语法问题【英文标题】:Spark Scala - splitting string syntax issue 【发布时间】:2019-01-07 23:49:03 【问题描述】:我正在尝试使用 SparkSQL 和 Scala 在 DataFrame 列中拆分字符串, 并且拆分条件对两者的工作方式似乎有所不同
使用 Scala,
这行得通-
val seq = Seq("12.1")
val df = seq.toDF("val")
Scala 代码 ->
val seq = Seq("12.1")
val df = seq.toDF("val")
val afterSplit = df2.withColumn("FirstPart", split($"val", "\\.")).select($"FirstPart".getItem(0).as("PartOne"))
afterSplit.show(false)
但是,在我使用 Spark SQL 时,firstParkSQL 显示空白。
df.registerTempTable("temp")
val s1 = sqlContext.sql("select split(val, '\\.')[0] as firstPartSQL from temp")
相反,当我使用这个(单独的条件表示为 [.] 而不是 \. 出现预期值。
val s1 = sqlContext.sql("select split(val, '[.]')[0] as firstPartSQL from temp")
任何想法为什么会发生这种情况?
【问题讨论】:
那是因为SQL需要额外的转义,即select split(val, '\\\\.')[0] as firstPartSQL from temp
【参考方案1】:
当你在 spark-sql 中使用带有双引号 spark.sql(".....")
的正则表达式模式时,它被认为是另一个字符串中的字符串,所以会发生两件事。考虑一下这个
scala> val df = Seq("12.1").toDF("val")
df: org.apache.spark.sql.DataFrame = [val: string]
scala> df.withColumn("FirstPart", split($"val", "\\.")).select($"FirstPart".getItem(0).as("PartOne")).show
+-------+
|PartOne|
+-------+
| 12|
+-------+
scala> df.createOrReplaceTempView("temp")
使用 df(),用于拆分的正则表达式字符串直接传递给拆分字符串,因此您只需要单独转义反斜杠 (\)。
但是当涉及到 spark-sql 时,模式首先被转换为字符串,然后再次作为字符串传递给 split() 函数,
所以你需要在 spark-sql 中使用 \\.
之前得到它
获得它的方法是再添加 2 个\
scala> "\\."
res12: String = \.
scala> "\\\\."
res13: String = \\.
scala>
如果你只是在 spark-sql 中传递"\\."
,首先它会被转换为\.
,然后是“.”,在正则表达式上下文中它会变成 (.)“任何”字符
即拆分任何字符,并且由于每个字符彼此相邻,因此您会得到一个空字符串数组。
字符串“12.1”的长度是四,并且它也匹配字符串的最终边界“$”。所以直到 split(val, '\.')[4],你会得到
空字符串。当你发出 split(val, '\.,')[5] 时,你会得到null
要验证这一点,您可以将相同的分隔符字符串 "\\."
传递给 regex_replace() 函数,看看会发生什么
scala> spark.sql("select split(val, '\\.')[0] as firstPartSQL, regexp_replace(val,'\\.','9') as reg_ex from temp").show
+------------+------+
|firstPartSQL|reg_ex|
+------------+------+
| | 9999|
+------------+------+
scala> spark.sql("select split(val, '\\\\.')[0] as firstPartSQL, regexp_replace(val,'\\\\.','9') as reg_ex from temp").show
+------------+------+
|firstPartSQL|reg_ex|
+------------+------+
| 12| 1291|
+------------+------+
scala>
如果您仍想在 df 和 sql 之间使用相同的模式,请使用原始字符串,即三引号。
scala> raw"\\."
res23: String = \\.
scala>
scala> spark.sql("""select split(val, '\\.')[0] as firstPartSQL, regexp_replace(val,'\\.','9') as reg_ex from temp""").show
+------------+------+
|firstPartSQL|reg_ex|
+------------+------+
| 12| 1291|
+------------+------+
scala> spark.sql("""select split(val, "\\.")[0] as firstPartSQL, regexp_replace(val,"\\.",'9') as reg_ex from temp""").show
+------------+------+
|firstPartSQL|reg_ex|
+------------+------+
| 12| 1291|
+------------+------+
scala>
【讨论】:
以上是关于Spark Scala - 拆分字符串语法问题的主要内容,如果未能解决你的问题,请参考以下文章
SPARK 数据框错误:在使用 UDF 拆分列中的字符串时无法转换为 scala.Function2
如何在 Spark Scala 数据框中拆分逗号分隔的字符串并获取 n 个值?