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

hjqgdpho  于 2023-03-30  发布在  Scala
关注(0)|答案(3)|浏览(344)

当我从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 * 编写的一些非常相似的代码,使用一个(literal)backslash*。但是如果我在Spark 2.1中只使用一个literal反斜杠,我会从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。

tquggr8v

tquggr8v1#

可能是因为反斜杠是一个特殊的符号,用于连接多行SQL。

sql_1 = spark.sql("SELECT \
    1 AS `col1`, '{0}' AS `col2`".format(var_1))
rsaldnfx

rsaldnfx2#

以下是获得相同结果的一些不同方法:

三重引号

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)

样式.引号

假设你的字符串在一个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

gtlvzcf8

gtlvzcf83#

请不要将您的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使用单/双转义字符。

相关问题