当我从Spark 2.0 REPL(Spark shell)运行下面的Scala代码时,它会按照我的预期运行,用一个简单的正则表达式分割字符串。
import org.apache.spark.sql.SparkSession
// Create session
val sparkSession = SparkSession.builder.master("local").getOrCreate()
// Use SparkSQL to split a string
val query = "SELECT split('What is this? A string I think', '\\?') AS result"
println("The query is: " + query)
val dataframe = sparkSession.sql(query)
// Show the result
dataframe.show(1, false)
给出预期输出
+---------------------------------+
|result |
+---------------------------------+
|[What is this, A string I think]|
+---------------------------------+
但我对是否需要用双反斜杠来转义字面上的问号感到困惑(这里表示为四个反斜杠,因为在Scala中,当不使用三重引用时,我们当然必须转义反斜杠)。
我确认,我的一位同事为Spark 1.5编写的一些非常相似的代码使用单个(文字)反斜杠可以很好地工作。但是,如果我在Spark 2.1中只使用一个字面反斜杠,我会从JVM的正则表达式引擎"Dangling meta character '?' near index 0"
中得到错误。我知道这意味着问号没有正确转义,但它闻起来像是反斜杠本身必须首先对Scala和进行转义,然后对SQL进行转义。
我猜这对于将控制字符(如换行符)插入SQL查询本身可能很有用。我只是很困惑,这是不是从Spark 1.5变成了2.1?
我在谷歌上搜索了很多,但没有找到任何东西。要么是某些东西发生了变化,要么是我同事的代码以一种意想不到的方式工作。
我也在Python/pyspark中尝试过,同样的条件也适用——SQL中需要双反斜杠。
有人能解释一下吗?
我在Windows上运行的是一个相对简单的设置,包括Spark 2.1.0、JDK 1.8.0_111和Hadoop winutils.exe。
可能是因为反斜杠是一个特殊的符号,用于连接多行SQL。
sql_1 = spark.sql("SELECT
1 AS `col1`, '{0}' AS `col2`".format(var_1))
以下是获得相同结果的一些不同方法:
三重报价
spark.sql("""SELECT split('What is this? A string I think', '\?') AS result""").show(false)
Regex字符转义
spark.sql("""SELECT split('What is this? A string I think', '\Q?\E') AS result""").show(false)
图案报价
假设您的字符串在DataFrame中。
val df = Seq(
("What is this? A string I think")
).toDF("your_string")
您可以利用Java正则表达式引用函数来分割字符串,如下所示:
import java.util.regex.Pattern
import org.apache.spark.sql.functions._
df
.withColumn("split_string", split($"your_string", Pattern.quote("?")))
.show(false)
这是输出:
+------------------------------+---------------------------------+
|your_string |split_string |
+------------------------------+---------------------------------+
|What is this? A string I think|[What is this, A string I think]|
+------------------------------+---------------------------------+
请参阅这篇文章了解更多信息。
请不要将您的Spark 2.1行为与您同事的Spark 1.5进行比较;当涉及到转义字符时,他们的行为应该有所不同。引用Spark文档:
自Spark 2.0以来,字符串文字(包括正则表达式模式)在我们的SQL解析器中是不带注释的。
和
有一个SQL配置"spark.SQL.parser.escapedStringLiterals",可用于回退到spark 1.6关于字符串文本解析的行为。
因此,请通过spark.conf.get('spark.sql.parser.escapedStringLiterals')
检查您的设置,并根据true/false使用单/双转义符。