Spark 2 CSV解析器启用multiLine选项时异常行为求助
解决Spark 2 CSV启用multiLine后的解析异常问题
这明显是Spark 2的CSV解析器在处理CRLF换行符(\r\n)+ multiLine选项时的兼容性bug,结合你遇到的列名乱码、BOM污染和列缺失问题,咱们可以从这几个方向解决:
核心问题分析
当启用multiLine后,解析器会尝试识别跨行的字段内容,但在处理Windows风格的CRLF换行时,可能和隐式的BOM字符(U+FEFF)或文件末尾不完整的行产生冲突,导致列名被错误截断(比如LSV_TYPE变成"LSV")YPE)、BOM被混入列名首字符,最终引发AnalysisException。
解决方案1:复用正常解析的Schema(最快见效)
既然df_ok的Schema是完全正确的,咱们可以直接把它传给df_ko的读取配置,强制解析器使用正确的列名和数据类型,绕过列名解析错误的问题:
// 先拿到正确的Schema val correctSchema = df_ok.schema // 用正确的Schema来加载启用multiLine的DataFrame val df_ko_fixed = spark.read.format("csv") .option("header", "true") .option("delimiter", "|") .option("multiLine", "true") .option("lineSep", "\r\n") // 显式指定CRLF为换行符 .schema(correctSchema) // 强制使用正确的Schema .load("/.../20180423_LSV.csv") // 验证是否正常 df_ko_fixed.select($"FILIALE").show()
这个方法的好处是不需要修改原文件,直接用正确的Schema约束解析过程,避免列名被错误解析。
解决方案2:预处理文本移除BOM并修复换行
如果Schema复用还是存在BOM问题,咱们可以先把文件读成文本行,预处理掉BOM字符,再转成CSV格式:
// 读取原始文本,移除每行开头的BOM字符 val cleanedLines = spark.read.textFile("/.../20180423_LSV.csv") .map(line => line.replaceFirst("^\\uFEFF", "")) // 仅移除行首的BOM // 用预处理后的文本加载CSV val df_ko_fixed = spark.read .format("csv") .option("header", "true") .option("delimiter", "|") .option("multiLine", "true") .option("lineSep", "\r\n") .csv(cleanedLines)
这里注意用replaceFirst只移除行首的BOM,避免误删字段里的正常字符。
解决方案3:切换CSV解析库
Spark 2默认使用univocity作为CSV解析库,你可以尝试切换到commons-csv,看是否能解决兼容性问题:
val df_ko_fixed = spark.read.format("csv") .option("header", "true") .option("delimiter", "|") .option("multiLine", "true") .option("parseLib", "commons-csv") // 切换解析库 .option("charset", "UTF-8") .option("lineSep", "\r\n") .load("/.../20180423_LSV.csv")
commons-csv的换行处理逻辑和univocity不同,可能能避开CRLF+multiLine的解析bug。
额外注意事项
- 你的示例文件最后一行是不完整的(末尾只到
500),在multiLine模式下可能被当成上一行的延续,建议先修复文件完整性,或者添加option("ignoreTrailingWhiteSpace", "true")来忽略行尾的无效内容。 - 不要随意设置
quote选项,除非你的字段确实包含引号,否则保持默认值即可。
内容的提问来源于stack exchange,提问作者Fernando Lemos
相关产品推荐
相关产品推荐

