Spark Shell中HiveContext内Lateral View explode是否失效?结果不符预期
搞定Spark HiveContext中Lateral View explode结果不符的问题
我来帮你排查这个预期6条实际8条的问题,大概率是数据或者split函数的行为导致的,咱们一步步来:
先明确问题场景
你创建了Hive外部表aa,字段col1是字符串类型,存储逗号分隔的值;用Spark的HiveContext执行带LATERAL VIEW explode(split(col1, ','))的查询时,结果比预期多了2条。
最可能的原因:split出了空元素
这种情况几乎都是因为原始数据里的col1存在以下情况:
- 部分行末尾带逗号,比如
"1,2,",用split(col1, ',')会得到["1","2",""],explode后就多了一条空值记录 - 存在
col1是空字符串的行,split后得到[""],explode也会生成一条记录 - 还有可能是连续逗号,比如
"a,,b",split后得到["a","","b"],多出来一个空元素
先验证问题所在
你可以在Spark Shell里先跑这条SQL,看看split后的数组是不是有问题:
sql("select col1, split(col1, ',') as split_result from aa").show()
如果输出的split_result里包含空字符串,那就是这个问题无疑了。
解决办法:过滤空元素或者优化split逻辑
给你两种实用的解决方式,根据你的业务数据选就行:
方式1:过滤数组里的空元素
用Spark的filter函数在explode前把空值去掉,SQL写法如下:
select col1, elem from aa lateral view explode(filter(split(col1, ','), x -> x != '')) tmp_table as elem
方式2:优化split的正则表达式
如果是首尾逗号或者连续逗号导致的,可以先清理数据再split:
-- 处理首尾逗号 + 正常分割 select col1, elem from aa lateral view explode(split(regexp_replace(col1, '^,|,$', ''), ',')) tmp_table as elem -- 或者直接匹配一个或多个逗号,自动忽略连续逗号 select col1, elem from aa lateral view explode(split(col1, ',+')) tmp_table as elem
注意:第二种正则方式会把连续逗号(比如a,,b)当成一个分隔符,得到["a","b"];而第一种清理首尾的方式会保留中间的空元素,根据你的业务需求选。
用DataFrame API实现(更直观)
如果你习惯用Scala代码而不是SQL,也可以这么写:
import org.apache.spark.sql.functions._ // 加载Hive表 val aaDF = sql("select col1 from aa") // 拆分、展开、过滤空值 val vasOtherDF = aaDF .withColumn("elem", explode(split(col1, ','))) .filter(col("elem") =!= "") // 查看结果数量 vasOtherDF.count() // 应该就是你预期的6了
额外排查:对比Hive和Spark的行为
如果在Hive CLI里跑同样的SQL得到6条,但Spark里还是8条,那可能是Spark的Hive兼容配置问题。可以检查下Spark版本(比如1.x和2.x的HiveContext行为有差异),或者是否设置了spark.sql.hive.convertMetastoreOrc这类影响解析的参数。
内容的提问来源于stack exchange,提问作者ankitbaldua




