在Apache Spark中解析/查询异构CSV数据的最佳方法?

时间:2018-08-22 04:01:33

标签: apache-spark apache-spark-sql

我有大量的日志数据,这些数据是半结构化为CSV数据。但是,每行的列取决于行的类型,由特定列指示。

示例数据:

8/01/2018, person, 1, Bob, Loblaw 32
8/01/2018, person, 2, Roger, McRoger, 55
8/03/2018, dog, Bella,  9, 1
8/05/2018, person, 3, Charlie, McCharles, 23
8/07/2018, dog, Scout, 5, 3

此特定示例显示了一个半结构文件,其中散布了两个模式,大致等于以下案例类:

case class Person(id: Int, firstName: String, lastName: String, age: Int)
case class Dog(name: String, age: Int, ownerId: Int)

我正在尝试找出通过Spark有效解析这些散布数据的最佳方法,以便我可以查询数据集,并可能在各种行类型之间进行连接。

当所有行都相同时,我可以将CSV数据加载到结构化架构中,但是这些文件中的行的异质性使我感到困惑。我认为我可以使用Spark读取以文本开头的数据,然后对“类型”列执行某种groupBy操作,这时我可以分别解析每个组,但是我已经之所以无法编写代码,是因为DataFrame的语义似乎与标准Scala集合完全不同,例如:据我所知,Spark中的groupBy不等同于Scala集合groupBy。

我意识到我可以在使用Spark规范化数据之前使用某种ETL处理这些文件,但似乎应该可以跳过这一步,让Spark按原样查询数据。我是从根本上走错了路吗?

1 个答案:

答案 0 :(得分:1)

在大规模情况下,数据通常会被规范化(嵌套结构,类型不匹配,多余/缺失的字段等)。强制将半结构化数据强制标准化为DataFrame可能很麻烦,尤其是对于数十亿条记录而言。

我建议研究开源Rumble引擎,它是Spark之上的额外一层。它是专门为这种异构数据场景而设计的(免责声明:我是团队的成员)。

例如,可以浏览文档,并将其转换为可以随意查询的JSON对象(不必遵循模式)的混合序列。语言是JSONiq:

let $my-heterogeneous-list :=
  (: first we convert each CSV line to a JSON object, switching on person/dog :)
  for $i in text-file("/path/to/heterogeneous-csv.txt")
  let $j := tokenize($i, ", ")
  let $person := $j[2] eq "person"
  return if($person)
       then {
         "kind" : "person",
         "date" : $j[1],
         "id" : $j[3],
         "first" : $j[4],
         "last" : $j[5],
         "age" : $j[6]
       } else {
         "kind" : "dog",
         "date" : $j[1],
         "name" : $j[3],
         "age" : $j[4],
         "owner" : $j[5]
       }
(: now we can query and re-arrange :)
return
  for $dog in $my-heterogeneous-list[$$.kind eq "dog"]
  return {|
      project($dog, ("date", "name")), 
      { "owner" : $my-heterogeneous-list[$$.id eq $dog.owner] }
  |}

哪个返回其嵌套所有者(已规范化)的狗的列表:

{ 
  "date" : "8\/03\/2018",
  "name" : "Bella",
  "owner" : { 
    "kind" : "person", 
    "date" : "8\/01\/2018", 
    "id" : "1", 
    "first" : "Bob", 
    "last" : "Loblaw", 
    "age" : "32" 
  } 
}
{
  "date" : "8\/07\/2018",
  "name" : "Scout",
  "owner" : {
    "kind" : "person",
    "date" : "8\/05\/2018",
    "id" : "3",
    "first" : "Charlie",
    "last" : "McCharles",
    "age" : "23"
  } 
}