加入两个DataFrame,使一个的条目附加到另一个的数组

时间:2017-09-26 16:34:40

标签: java apache-spark join spark-dataframe

我有以下数据框:

 |-- k1: array (nullable = true)
 |    |-- element: long (containsNull = true)
 |-- k2: string (nullable = true)
 |-- k3: array (nullable = true)
 |    |-- element: long (containsNull = true)

 |-- k1: long (nullable = true)
 |-- k2: string (nullable = true)
 |-- k3: long (nullable = true)

请注意,列名称和类型是相同的,只是第一个数据框的k1k3是数组。我想在k2上加入这两个数据帧,以便第二个数据帧的条目被附加到第一个数据帧中的数组。例如,如果数据帧是

+---------+---+------------+
|    k1   |k2 |      k3    |
+---------+---+------------+
|[1, 2, 3]|foo|   [4, 5, 6]|
|[7, 8, 9]|bar|[10, 11, 12]|
+---------+---+------------+

+-----+---+------+
|k1   |k2 |k3    |
+-----+---+------+
|    4|foo|     7|
|   10|bar|    13|
+-----+---+------+

然后连接的结果应该是

+---+-------------+----------------+
|key|    click    |      search    |
+---+-------------+----------------+
|foo|[1, 2, 3, 4] |   [4, 5, 6, 7] | 
|bar|[7, 8, 9, 10]|[10, 11, 12, 13]| 
+---+-------------+----------------+

我的第一个方法是进行内连接以获得

+---+---------+------------+-----+------+
|key|    click|      search|click|search|
+---+---------+------------+-----+------+
|foo|[1, 2, 3]|   [4, 5, 6]|    3|     6|
|bar|[7, 8, 9]|[10, 11, 12]|    9|    12|
+---+---------+------------+-----+------+

然后对结果数据框执行foreach以将所需的行条目附加到数组,然后最后删除后两列。但我无法让打字工作为foreach工作。

我在Java 1.6.1中使用Java 8。我是Spark的新手,所以我们非常感谢任何指导。

2 个答案:

答案 0 :(得分:2)

使用java有点棘手。

假设两个数据帧都注册为t1,则t2表然后使用udf将两个数组合并。

sql.udf().register("unionArray", (Seq<Long> arr1, Seq<Long> arr2) -> {
            List<Long> output =new ArrayList<Long>();
            //Convert Seq object to java list and add to output
            output.addAll(scala.collection.JavaConversions.asJavaList(arr1));
            output.addAll(scala.collection.JavaConversions.asJavaList(arr2));
            //Convert java list output scala Seq
            return Option.apply(scala.collection.JavaConverters.asScalaIterableConverter(output).asScala().toSeq());
        }, DataTypes.createArrayType(DataTypes.LongType));

        sql.sql("select t1.k2 as key,unionArray(t1.k1,t2.k1) as click, unionArray(t1.k3,t2.k3) as search from t1 join t2 on t1.k2 = t2.k2").show();

希望这会有所帮助。

答案 1 :(得分:1)

这不是Java中的解决方案,但是使用UDF添加列的Scala中的以下方法可以作为参考:

val df1 = Seq(
  (Seq(1, 2, 3), "foo", Seq(4, 5, 6)),
  (Seq(7, 8, 9), "bar", Seq(10, 11, 12))
).toDF("k1", "k2", "k3")

val df2 = Seq(
 (4, "foo", 7),
 (10, "bar", 13)
).toDF("k1", "k2", "k3")

def appendCol = udf(
  (a: Seq[Int], x: Int) => a :+ x
)

val df3 = df1.join( df2, Seq("k2") ).
  withColumn( "click", appendCol(df1("k1"), df2("k1")) ).
  withColumn( "search", appendCol(df1("k3"), df2("k3")) )

df3.select( col("k2").as("key"), col("click"), col("search") ).show
+---+-------------+----------------+
|key|        click|          search|
+---+-------------+----------------+
|foo| [1, 2, 3, 4]|    [4, 5, 6, 7]|
|bar|[7, 8, 9, 10]|[10, 11, 12, 13]|
+---+-------------+----------------+