在 Spark 中读取最后一列作为值数组的 CSV(并且值在括号内并用逗号分隔)

Posted

技术标签:

【中文标题】在 Spark 中读取最后一列作为值数组的 CSV(并且值在括号内并用逗号分隔)【英文标题】:Read CSV with last column as array of values (and the values are inside parenthesis and separated by comma) in Spark 【发布时间】:2018-10-12 06:16:30 【问题描述】:

我有一个 CSV 文件,其中最后一列在括号内,值用逗号分隔。最后一列中值的数量是可变的。当我将它们作为具有如下一些列名的 Dataframe 读取时,我得到Exception in thread "main" java.lang.IllegalArgumentException: requirement failed: The number of columns doesn't match。我的 CSV 文件如下所示

a1,b1,true,2017-05-16T07:00:41.0000000,2.5,(c1,d1,e1)
a2,b2,true,2017-05-26T07:00:42.0000000,0.5,(c2,d2,e2,f2,g2)
a2,b2,true,2017-05-26T07:00:42.0000000,0.5,(c2)
a2,b2,true,2017-05-26T07:00:42.0000000,0.5,(c2,d2)
a2,b2,true,2017-05-26T07:00:42.0000000,0.5,(c2,d2,e2)
a2,b2,true,2017-05-26T07:00:42.0000000,0.5,(c2,d2,e2,k2,f2)

我最终想要的是这样的:

root
 |-- MId: string (nullable = true)
 |-- PId: string (nullable = true)
 |-- IsTeacher: boolean(nullable = true)
 |-- STime: datetype(nullable = true)
 |-- TotalMinutes: double(nullable = true)
 |-- SomeArrayHeader: array<string>(nullable = true)

到目前为止,我已经编写了以下代码:

val infoDF =
  sqlContext.read.format("csv")
    .option("header", "false")
    .load(inputPath)
    .toDF(
      "MId",
      "PId",
      "IsTeacher",
      "STime",
      "TotalMinutes",
      "SomeArrayHeader")

我想在不给出列名的情况下阅读它们,然后将第 5 列之后的列转换为数组类型。但是后来我遇到了括号问题。有没有一种方法可以在读取并告诉括号内的字段实际上是数组类型的一个字段时做到这一点。

【问题讨论】:

这不是一个正确的csv内容,最后一列必须用双引号引起来..你不能用csv读取arraytype..将检查是否有任何解决方法 是的,我知道。但我的文件看起来只是这样。如果它在引号中,则 csv-read 没有问题,但它不在引号中。 【参考方案1】:

好的。该解决方案仅适用于您的情况。下面的一个对我有用

  val df = spark.read.option("quote", "(").csv("in/staff.csv").toDF(
    "MId",
    "PId",
    "IsTeacher",
    "STime",
    "TotalMinutes",
    "arr")
  df.show()
  val df2 = df.withColumn("arr",split(regexp_replace('arr,"[)]",""),","))
  df2.printSchema()
  df2.show()

输出:

+---+---+---------+--------------------+------------+---------------+
|MId|PId|IsTeacher|               STime|TotalMinutes|            arr|
+---+---+---------+--------------------+------------+---------------+
| a1| b1|     true|2017-05-16T07:00:...|         2.5|      c1,d1,e1)|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|c2,d2,e2,f2,g2)|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|            c2)|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|         c2,d2)|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|      c2,d2,e2)|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|c2,d2,e2,k2,f2)|
+---+---+---------+--------------------+------------+---------------+

root
 |-- MId: string (nullable = true)
 |-- PId: string (nullable = true)
 |-- IsTeacher: string (nullable = true)
 |-- STime: string (nullable = true)
 |-- TotalMinutes: string (nullable = true)
 |-- arr: array (nullable = true)
 |    |-- element: string (containsNull = true)

+---+---+---------+--------------------+------------+--------------------+
|MId|PId|IsTeacher|               STime|TotalMinutes|                 arr|
+---+---+---------+--------------------+------------+--------------------+
| a1| b1|     true|2017-05-16T07:00:...|         2.5|        [c1, d1, e1]|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|[c2, d2, e2, f2, g2]|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|                [c2]|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|            [c2, d2]|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|        [c2, d2, e2]|
| a2| b2|     true|2017-05-26T07:00:...|         0.5|[c2, d2, e2, k2, f2]|
+---+---+---------+--------------------+------------+--------------------+

【讨论】:

谢谢!引号在那里做什么?我有 GB 的大文件,这有什么性能问题吗? "quote" 是 csv 解析器中的一项功能 - 当出现该引号字符时,解析器会将内容读取到下一个引号字符到单个列中。因此,我们可以在数据中使用分隔符,只要它们被引号字符包围。默认引号字符是“- 双引号。CSV 解析器不允许引号功能超过一个字符。在我们的例子中,我们有 ( 和 ),所以我在阅读时给出了 "(",在 df2 中,我删除了 " )"。我们很幸运,这一列在最后,所以一直读到行尾。 所以quote here会将默认引号(“)也视为引号之一?它也会将“(”视为引号之一,是吗? 在我们的例子中,我们用“(”覆盖,你只能有一个引号字符..

以上是关于在 Spark 中读取最后一列作为值数组的 CSV(并且值在括号内并用逗号分隔)的主要内容,如果未能解决你的问题,请参考以下文章

读取 CSV 文件并将值存储到数组中

spark 2.x 正在使用 csv 函数将整数/双列作为字符串读取

在 Pyspark 中使用正确的数据类型读取 CSV

将 csv 文件作为浮点数读取到 pandas 数据帧

读取 CSV 后具有奇怪值的 Spark 数据帧

java操作csv文件