Spark SQL - 로우 분리하기

데이터를 다루다보면 하나의 로우를 여러개로 분리해야하는 상황이 온다. 다음은 explode 를 활용한 예

spark < 2.4

val data = sc.parallelize(Seq(
    """{"userId": 1, "someString": "example1",
        "Date": [20190101, 20190102, 20190103], "val": [1, 2, 9]}""",
    """{"userId": 2, "someString": "example2",
        "Date": [20190101, 20190103, 20190105], "val": [9, null, 6]}"""
))

val df = spark.read.json(data)

df.printSchema
/*
root
 |-- Date: array (nullable = true)
 |    |-- element: long (containsNull = true)
 |-- someString: string (nullable = true)
 |-- userId: long (nullable = true)
 |-- val: array (nullable = true)
 |    |-- element: long (containsNull = true)
*/

define zip udf:

import org.apache.spark.sql.functions.{udf, explode}

val zip = udf((xs: Seq[Long], ys: Seq[Long]) => xs.zip(ys))

df.withColumn("result", explode(zip('Date, 'val))).
  select('userId, 'someString,
    $"result._1".alias("date"), $"result._2".alias("value")).
    show
/*
   +------+----------+--------+-----+
   |userId|someString|    date|value|
   +------+----------+--------+-----+
   |     1|  example1|20190101|    1|
   |     1|  example1|20190102|    2|
   |     1|  example1|20190103|    9|
   |     2|  example2|20190101|    9|
   |     2|  example2|20190103| null|
   |     2|  example2|20190105|    6|
   +------+----------+--------+-----+
*/

spark > = 2.4

이미 구현된 arrays_zip을 사용하면 간단.

df.withColumn("result", explode(arrays_zip($"date", $"val"))).
  select($"userId", $"someString", $"result.date", $"result.val").
  show

댓글남기기