Spark:加入数组

时间:2017-08-07 11:47:35

标签: scala apache-spark apache-spark-sql

我需要将一个带有字符串列的数据框连接到一个带有字符串数组的数组,这样如果数组中的一个值匹配,那么这些行就会加入。

我试过了,但我猜它不支持。 还有其他办法吗?

import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession

val sparkConf = new SparkConf().setMaster("local[*]").setAppName("test")
val spark = SparkSession.builder().config(sparkConf).getOrCreate()

import spark.implicits._

val left = spark.sparkContext.parallelize(Seq(1, 2, 3)).toDF("col1")
val right = spark.sparkContext.parallelize(Seq((Array(1, 2), "Yes"),(Array(3),"No"))).toDF("col1", "col2")

left.join(right,"col1")

抛出:

  

org.apache.spark.sql.AnalysisException:无法解析'(col1   = col1)'由于数据   类型不匹配:'(col1 =

中的不同类型      

col1)' (int和array)。;;

3 个答案:

答案 0 :(得分:7)

一个选项是创建一个UDF来构建连接条件:

import org.apache.spark.sql.functions._
import scala.collection.mutable.WrappedArray

val left = spark.sparkContext.parallelize(Seq(1, 2, 3)).toDF("col1")
val right = spark.sparkContext.parallelize(Seq((Array(1, 2), "Yes"),(Array(3),"No"))).toDF("col1", "col2")

val checkValue = udf { 
  (array: WrappedArray[Int], value: Int) => array.contains(value) 
}
val result = left.join(right, checkValue(right("col1"), left("col1")), "inner")

result.show

+----+------+----+
|col1|  col1|col2|
+----+------+----+
|   1|[1, 2]| Yes|
|   2|[1, 2]| Yes|
|   3|   [3]|  No|
+----+------+----+

答案 1 :(得分:3)

您可以在加入之前在Array列上使用explode。 Explode为数组中的每个元素创建一个新行:

right = right.withColumn("exploded_col",explode(right("col1")))
right.show()

+------+----+--------------+
|  col1|col2|exploded_col_1|
+------+----+--------------+
|[1, 2]| Yes|             1|
|[1, 2]| Yes|             2|
|   [3]|  No|             3|
+------+----+--------------+

然后,您可以轻松加入第一个数据集。

答案 2 :(得分:1)

最简洁的方法是使用array_contains spark sql表达式,如下所示,即我已将其性能与执行爆炸和联接的性能进行了比较,如上一个答案和爆炸所示似乎更有表现。

import org.apache.spark.sql.functions.expr
import spark.implicits._

val left = Seq(1, 2, 3).toDF("col1")

val right = Seq((Array(1, 2), "Yes"),(Array(3),"No")).toDF("col1", "col2").withColumnRenamed("col1", "col1_array")

val joined = left.join(right, expr("array_contains(col1_array, col1)")).show

+----+----------+----+
|col1|col1_array|col2|
+----+----------+----+
|   1|    [1, 2]| Yes|
|   2|    [1, 2]| Yes|
|   3|       [3]|  No|
+----+----------+----+

请注意,您不能直接使用org.apache.spark.sql.functions.array_contains函数,因为它要求第二个参数是文字而不是列表达式。