读取包含嵌入逗号的引用字段的 csv 文件

Posted

技术标签:

【中文标题】读取包含嵌入逗号的引用字段的 csv 文件【英文标题】:Reading csv files with quoted fields containing embedded commas 【发布时间】:2017-03-17 17:56:30 【问题描述】:

我正在 Pyspark 中读取一个 csv 文件,如下所示:

df_raw=spark.read.option("header","true").csv(csv_path)

但是,数据文件中包含带有嵌入逗号的引用字段 不应视为逗号。我如何在 Pyspark 中处理这个问题?我知道 pandas 可以处理这个问题,但 Spark 可以吗?我使用的版本是 Spark 2.0.0。

这是一个在 Pandas 中工作但使用 Spark 失败的示例:

In [1]: import pandas as pd

In [2]: pdf = pd.read_csv('malformed_data.csv')

In [3]: sdf=spark.read.format("org.apache.spark.csv").csv('malformed_data.csv',header=True)

In [4]: pdf[['col12','col13','col14']]
Out[4]:
                    col12                                             col13  \
0  32 XIY "W"   JK, RE LK  SOMETHINGLIKEAPHENOMENON#YOUGOTSOUL~BRINGDANOISE
1                     NaN                     OUTKAST#THROOTS~WUTANG#RUNDMC

   col14
0   23.0
1    0.0

In [5]: sdf.select("col12","col13",'col14').show()
+------------------+--------------------+--------------------+
|             col12|               col13|               col14|
+------------------+--------------------+--------------------+
|"32 XIY ""W""   JK|              RE LK"|SOMETHINGLIKEAPHE...|
|              null|OUTKAST#THROOTS~W...|                 0.0|
+------------------+--------------------+--------------------+

文件内容:

    col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12,col13,col14,col15,col16,col17,col18,col19
80015360210876000,11.22,X,4076710258,,,sxsw,,"32 YIU ""A""",S5,,"32 XIY ""W""   JK, RE LK",SOMETHINGLIKEAPHENOMENON#YOUGOTSOUL~BRINGDANOISE,23.0,cyclingstats,2012-25-19,432,2023-05-17,CODERED
61670000229561918,137.12,U,8234971771,,,woodstock,,,T4,,,OUTKAST#THROOTS~WUTANG#RUNDMC,0.0,runstats,2013-21-22,1333,2019-11-23,CODEBLUE

【问题讨论】:

【参考方案1】:

我注意到您有问题的行本身使用双引号进行转义:

“32 XIY”“W”“JK,RE LK”

应该是解释器

32 XIY "W" JK, RE LK

如RFC-4180,第 2 页所述 -

    如果使用双引号将字段括起来,则出现在字段中的双引号必须通过在其前面加上另一个双引号来进行转义

这就是 Excel 所做的,例如,默认情况下。

虽然在 Spark 中(从 Spark 2.1 开始),默认情况下转义是通过非 RFC 方式完成的,使用反斜杠 (\)。要解决此问题,您必须明确告诉 Spark 使用双引号作为转义字符:

.option("quote", "\"")
.option("escape", "\"")

这可能解释了逗号字符在引用列中的解释不正确。

Apache Spark 网站上没有很好地记录 Spark csv 格式的选项,但这里有一些旧文档,我仍然经常发现它们很有用:

https://github.com/databricks/spark-csv

2018 年 8 月更新:Spark 3.0 可能会将此行为更改为符合 RFC。详情请见SPARK-22236。

【讨论】:

option 的第一个参数不应该用双引号代替单引号吗? 任何一种方式都是正确的。 softwareengineering.stackexchange.com/questions/155176/… 使用 spark 2.3 这会出现以下错误:quote cannot be more than one character 只是一个字符-"(一个双引号字符,不是两个单引号)。没有测试,Spark 2.3应该是一样的 谢谢,这对我有用。但是我有一个问题,即一系列 3 个空格字符保存为 4 个双引号......如果我修剪该值,我会得到空值/空字符串值行为,这是我的 csv 文件中的 2 个双引号。在我看来,只有包含逗号和双引号的值才用引号括起来。这似乎没问题,但这不是我所期望的。似乎任何一个值都应该始终包含在引号参数中,但如果仅在必要时使用引号,我希望 null 和空字符串值仅保存为两个连续的逗号。【参考方案2】:

对于在 Scala 中执行此操作的任何人:Tagar 的回答几乎对我有用(谢谢!);我所要做的就是在设置选项参数时转义双引号:

.option("quote", "\"")
.option("escape", "\"")

我使用的是 Spark 2.3,所以我可以确认 Tagar 的解决方案在新版本下似乎仍然有效。

【讨论】:

【参考方案3】:

对于在使用 Tagar 的解决方案后仍然想知道他们的解析是否仍然无法正常工作的任何人。

Pyspark 3.1.2 .option("quote", "\"") 是默认值,所以这不是必需的,但是在我的情况下,我有多行数据,因此 spark 无法在单个数据点和每一行的末尾自动检测 \n,因此使用 .option("multiline", True) 解决了我的问题with .option('escape', "\"") 所以一般默认使用多行选项会更好

【讨论】:

我想知道这是否会影响性能,因为 Spark 不能在工作人员之间拆分多行值? 我不确定 spark 是否可以在工作人员之间拆分多行值,但如果您确定您的数据没有多行可能不需要,但在我的情况下,我正在处理文本数据,所以我永远无法确定我的数据是否包含“\n”。 确实如此,正如这篇好文章所显示的那样kokes.github.io/blog/2018/05/19/spark-sane-csv-processing.html【参考方案4】:

quotes 中指定的分隔符(comma) 默认会被忽略。 Spark SQL 在 Spark 2.0 中确实有内置的 CSV 阅读器。

df = session.read
  .option("header", "true")
  .csv("csv/file/path")

more about CSV reader here - .

【讨论】:

这似乎不起作用。请参阅我上面提供的示例。

以上是关于读取包含嵌入逗号的引用字段的 csv 文件的主要内容,如果未能解决你的问题,请参考以下文章

将其字段中带有逗号的 .csv 文件转换为 JSON/TXT

Pyspark:读取带有双引号和逗号的字段的csv文件

awk 可以处理在引用字段中包含逗号的 CSV 文件吗?

如何从csv文件中读取包含逗号的列表作为列?

导入包含引号中的逗号的字段的 CSV 文件?

csv 在 pig 中读取,csv 文件包含带引号的逗号