如何在Spark中组合并聚合列并创建嵌套的Json

时间:2017-03-21 18:25:01

标签: apache-spark group-by apache-spark-sql aggregation

  

我有这样的数据,我想创建以下JSON文档。   我怎样才能在Spark中实现它?在Spark中最有效的方法是什么?

 name|contact           |type
    jack|123-123-1234       |phone
    jack|jack.reach@xyz.com |email
    jack|123 main street    |address
    jack|34545544445        |mobile

       {
         "name" : "jack",
         "contacts":[
         {
           "contact" : "123-123-1234",
           "type" : "phone"
         },
         {
           "contact" : "jack.reach@xyz.com",
           "type" : "email"
         },
        {
           "contact" : "123 main street",
            "type" : "address"
        },
        {
           "contact" : "34545544445",
           "type" : "mobile"
        }
      ]
    }
  

这只是我提供的示例用例。我有大数据集在哪里   我必须通过一些分组将多列行折叠成一行   逻辑。

     

My Current方法是我写一个UDAF,读取每一行,存储在   缓冲并合并它。所以代码将是

val mergeUDAF = new ColumnUDAF

val tempTable = inputTable.withColumn("contacts",struct($"contact",$"type")
val outputTable = tempTable.groupby($"name").agg(mergeUDAF($"contacts").alias("contacts"))
  

我正在试图找出其他方法。我是   尝试使用Spark-SQL实现这一目标。

2 个答案:

答案 0 :(得分:0)

我认为你应该只是创建一个RDD形式的csv数据,分组为" name"比映射到json字符串:

 val data = sc.parallelize(Seq("jack|123-123-1234|phone", "jack|jack.reach@xyz.com |email", "david|123 main street|address", "david|34545544445|mobile")) // change to load your data as RDD

 val result = data.map(_.split('|')).groupBy(a => a(0)).map(a => {
    val contact = a._2.map(c => s"""{"contact": "${c(1)}", "type": "${c(2)}" }""" ).mkString(",")
    s"""{"name": "${a._1}", "contacts":[ ${contact}] }"""
  }).collect.mkString(",")

  val json = s"""[ ${result} ] """ 

答案 1 :(得分:0)

case class contact(contact:String,contactType:String)
case class Person(name:String,contact:Seq[contact])
    object SparkTestGrouping {

      def main(args: Array[String]): Unit = {

        val conf = new SparkConf().setAppName("LocalTest").setMaster("local")
        val sc = new SparkContext(conf)
        val sqlContext = new SQLContext(sc)
        import sqlContext.implicits._


        val inputData=Seq("jack|123-123-1234|phone","jack|jack.reach@xyz.com|email","jack|123 main street|address","jack|34545544445|mobile")


        val finalData = sc.parallelize(inputData)

        val convertData = finalData.map(_.split('|'))
          .map(line => (line(0),Seq(line(1) +"|" +line(2))))
          .reduceByKey((x,y) => x ++: y)

          val output = convertData.map(line => (line._1,line._2.map(_.split('|')).map(obj => contact(obj(0),obj(1)))))

        val finalOutput = output.map(line => Person(line._1,line._2))

        finalOutput.toDF().toJSON.foreach(println)

        sc.stop()

      }

    }
  

您可以使用关键字段从数据中创建元组并使用   reducebyKey对数据进行分组。在上面的例子中,我创建了一个元组   (name,Seq(“contact | contactType”))并使用reducebykey对其进行分组   按名称的数据。数据分组后,您可以使用案例类   如果您需要进一步加入,请转换为DataFrame和DataSet   或者只需要创建json文档。