Spark 1.6与Spark 2.2中rlike行为差异原因咨询
Spark 1.6与Spark 2.2中rlike过滤行为相反的原因
这个差异的核心是Spark 2.0版本对SQL字符串的转义规则做了根本性调整,导致你写的两个过滤表达式在两个版本中被解析成了完全相反的正则逻辑:
1. 转义规则的核心变化
- Spark 1.6(基于HiveQL):HiveQL将反斜杠视为SQL层面的转义字符,因此要在正则表达式中表示一个Java正则所需的反斜杠(比如
\x这种十六进制转义序列),你需要在Scala字符串中写四个反斜杠(最终正则引擎才能得到一个反斜杠)。 - Spark 2.2(ANSI SQL兼容):Spark 2.x切换为ANSI SQL解析器,反斜杠直接作为正则引擎的转义字符,因此在Scala字符串中写两个反斜杠就能让正则引擎得到一个反斜杠。
2. 你的代码在两个版本中的解析过程
对于filter = "col1 rlike '[\\x00-\\x1F\\x7F]'"
- Spark 1.6:Scala编译后字符串变为
"[\x00-\x1F\x7F]",直接包含ASCII控制字符的正则范围。由于你的col1是数字,转成字符串后没有控制字符,所以过滤结果为0。 - Spark 2.2:Scala编译后同样得到
"[\x00-\x1F\x7F]",但此时ANSI SQL解析器传递给正则引擎时,\x未被正确识别为十六进制转义(或被解析为无效范围),导致正则表达式意外匹配了所有数字字符串,因此返回4。
对于filter2 = "col1 rlike '[\\\\x00-\\\\x1F\\\\x7F]'"
- Spark 1.6:Scala编译后字符串变为
"[\\x00-\\x1F\\x7F]",HiveQL解析时将每个\\转成单个\,此时正则引擎得到的表达式被解析为匹配包含数字的字符范围,因此所有行都被匹配,返回4。 - Spark 2.2:Scala编译后得到
"[\\x00-\\x1F\\x7F]",ANSI SQL解析器将其传递给正则引擎,正确识别为匹配ASCII控制字符的范围,而你的col1字符串中没有这些字符,所以返回0。
总结
简单来说,两个版本对SQL字符串中反斜杠的转义处理逻辑完全相反,导致你写的两个过滤表达式在不同版本中实际生效的正则规则颠倒,最终出现结果相反的情况。如果要在两个版本中得到一致的结果,需要根据版本调整转义的反斜杠数量:
- Spark 1.6:使用四个反斜杠表示正则中的一个反斜杠
- Spark 2.2:使用两个反斜杠表示正则中的一个反斜杠
内容的提问来源于stack exchange,提问作者Selnay
相关产品推荐
相关产品推荐

