2017-08-07 45 views
1

我需要將具有字符串列的數據框連接到具有字符串數組的一個數據框,以便如果數組中的某個值匹配,則這些行將連接。Spark:加入數組

我試過這個,但我想這不是支持。 任何其他方式來做到這一點?

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 and array)。;;

回答

3

一種選擇是建立您的加盟條件創建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| 
+----+------+----+ 
+0

謝謝!這與爆炸相比如何?性能明智嗎? – aclokay

+1

嗯,我猜這個解決方案稍好一點,但我不確定,因爲UDF可能會很慢。但是,內存方面,這個解決方案肯定會比另一個佔用更少的空間。 –

+1

我想我會更好地知道如果我會嘗試兩種方式。謝謝。 – aclokay

3

您可以在連接前的Array列上使用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| 
+------+----+--------------+ 

然後,您可以輕鬆地加入第一個數據集。

+0

謝謝!這與以下答案相比如何?性能明智嗎? – aclokay

+0

@aclokay我認爲我的答案較慢,特別是如果數組變大,因爲您必須爲數組中的每個元素創建(即重複)一行。 – Fabich

+0

我也想到了這種方式,但我希望火花會做某種魔術來優化這種方式。雖然謝謝! – aclokay