PySpark split函数未保留剩余字符串问题:Databricks版本差异
Spark split函数空字符串模式+limit参数的行为变化问题
我尝试将字符串"23220"拆分为数组[2,3,2,20],执行以下代码:
from pyspark.sql import functions as f df = spark.createDataFrame([('23220',)], ['s',]) df.select(f.split(str=df.s, pattern='', limit=4).alias('s')).show()
但返回结果为[2,3,2,2],不符合预期。根据Spark官方文档说明:
limit > 0:生成的数组长度不超过limit,且最后一个元素包含匹配模式之后的所有输入内容。
该现象仅出现在Databricks 11.3 LTS(含Apache Spark 3.3.0、Scala 2.12)及更高版本中,Databricks 10.4 LTS(Spark 3.2.1)中表现正常。
问题原因
这是Spark 3.3.0对split函数处理空字符串模式的逻辑做了调整:
- Spark 3.2.1及之前,空字符串
''会被当作"字符间的分隔符",当设置limit时,最后一次分割会将剩余所有字符归入最后一个元素; - Spark 3.3.0之后,空字符串模式的分割逻辑更严格,每次分割都会消耗一个"空位置",导致最后一个元素仅截取单个字符,而非剩余全部内容。
解决方案
方案1:手动截取构造数组(推荐,性能最优)
针对固定长度的字符串,直接用substring和array函数精准构造目标数组:
from pyspark.sql import functions as f df = spark.createDataFrame([('23220',)], ['s',]) df.select( f.array( f.substring(df.s, 1, 1), f.substring(df.s, 2, 1), f.substring(df.s, 3, 1), f.substring(df.s, 4, 2) ).alias('s') ).show()
执行结果:
+------------+ | s| +------------+ |[2, 3, 2, 20]| +------------+
方案2:正则替换插入分隔符后拆分
通过正则表达式匹配字符串结构,插入分隔符后再用split拆分:
from pyspark.sql import functions as f df = spark.createDataFrame([('23220',)], ['s',]) df.select( f.split( f.regexp_replace(df.s, '^(.)(.)(.)(..)$', '$1,$2,$3,$4'), ',' ).alias('s') ).show()
此方法适合有固定格式的字符串拆分,灵活性较强。
方案3:自定义UDF(仅适合复杂场景)
如果需要通用的自定义拆分逻辑,可以编写UDF实现,但会牺牲部分性能:
from pyspark.sql import functions as f from pyspark.sql.types import ArrayType, StringType def custom_split(s, split_count): if not s: return [] # 前split_count-1个元素取单个字符,最后一个元素取剩余所有 parts = list(s[:split_count-1]) parts.append(s[split_count-1:]) return parts custom_split_udf = f.udf(custom_split, ArrayType(StringType())) df = spark.createDataFrame([('23220',)], ['s',]) df.select(custom_split_udf(df.s, f.lit(4)).alias('s')).show()
内容的提问来源于stack exchange,提问作者Lazloo Xp
相关产品推荐
相关产品推荐

