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-Scala 中将单个字符串列拆分为多列

SPARK 数据框错误:在使用 UDF 拆分列中的字符串时无法转换为 scala.Function2

如何在 Spark Scala 数据框中拆分逗号分隔的字符串并获取 n 个值?

如何基于多个空格字符将文本文件拆分为 2 列作为 scala spark 的分隔符

Spark记录-Scala基础语法

如何使用scala拆分字符串?