为什么 SparkSQL 在 SQL 查询中需要两个文字转义反斜杠?

Why does SparkSQL require two literal escape backslashes in the SQL query?

当我 运行 来自 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 和 then 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)

正则表达式字符转义

spark.sql("""SELECT split('What is this? A string I think', '\Q?\E') AS result""").show(false)

Pattern.quote

假设您的字符串在 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]|
+------------------------------+---------------------------------+

有关详细信息,请参阅 this post

请不要将您的 Spark 2.1 行为与您同事的 Spark 1.5 进行比较;当谈到转义字符时,它们的行为应该有所不同。引用自 Spark docs:

Since Spark 2.0, string literals (including regex patterns) are unescaped in our SQL parser.

There is a SQL config 'spark.sql.parser.escapedStringLiterals' that can be used to fallback to the Spark 1.6 behavior regarding string literal parsing.

因此请通过 spark.conf.get('spark.sql.parser.escapedStringLiterals') 检查您的设置,并根据 true/false 使用 single/double 转义字符。