Spark Scala-拆分字符串语法问题

时间:2019-01-07 23:49:04

标签: apache-spark apache-spark-sql

我正在尝试使用SparkSQL和Scala在DataFrame列中拆分String, 而且拆分条件对两者的作用方式似乎有所不同

使用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")

任何想法为什么会这样?

1 个答案:

答案 0 :(得分: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(),将split的正则表达式字符串直接传递到split字符串,因此您只需要转义反斜杠(\)。

但是当涉及spark-sql时,该模式首先转换为字符串,然后再次作为字符串传递给split()函数, 因此,您需要先获取\\.才能在spark-sql中使用

获取方法是再添加2个\

scala> "\\."
res12: String = \.

scala> "\\\\."
res13: String = \\.

scala>

如果仅在spark-sql中传递"\\.",则首先将其转换为\.,然后转换为“。”,在正则表达式上下文中它变成(。)“ any”字符 即在任何字符上分割,并且由于每个字符彼此相邻,因此会得到一个空字符串数组。 字符串“ 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>