2017-10-16 35 views
0

我有一個數據幀像這樣:處理加入上或星火

+---+---+---+---+---+ 
|AId| A1| A2| A3| A4| 
+---+---+---+---+---+ 
| 1| *| a| b| c| 
| 2| *| *| b| c| 
| 3| c| a| b| c| 
| 4| *| *| *| c| 
| 5| *| *| *| *| 
+---+---+---+---+---+ 

,我想加入的:

+---+---+---+---+---+----+ 
|BId| B1| B2| B3| B4|Code| 
+---+---+---+---+---+----+ 
| 1| c| a| b| c| AO| 
| 2| b| a| b| c| AS| 
| 3| b| b| b| c| AT| 
| 4| a| d| d| c| BO| 
| 5| d| a| c| b| BS| 
| 6| a| b| b| c| BT| 
| 7| d| d| d| c| CO| 
| 8| d| d| d| d| CS| 
+---+---+---+---+---+----+ 

一個ID與規則匹配。但是,*是通配符。它會匹配任何東西。在上面的例子中,AId == 1將匹配BId 1和2,AId == 3只匹配BId 1,AId == 4匹配除5和8之外的所有匹配,並且AId == 5匹配全部8.

什麼是最好的方法來解決這個問題?在Spark中查詢看起來很昂貴,而且Spark沒有內置OR。另一種方法似乎是做了一個例子 - 當A1-A4設置一個標誌時,然後返回並加入。棘手的一點是,通配符可以在第一個表格的任何列中出現1-4次,儘管它們不出現在第二個表格中。

回答

0

可以表達的連接條件爲:

(A1 = * | (A1 = B1)) AND (A2 = * | (A2 = B2)) AND ... AND (AN = * | (AN = BN)) 

隨着PySpark等效表達可以例如產生這樣

from pyspark.sql.functions import col 
from functools import reduce 
from operator import and_ 

expr = reduce(
    and_, 
    ((col("A{}".format(i)) == "*") | (col("A{}".format(i)) == col("B{}".format(i))) 
    for i in range(1, 5))) 
Column<b'(((((A1 = *) OR (A1 = B1)) AND ((A2 = *) OR (A2 = B2))) AND ((A3 = *) OR (A3 = B3))) AND ((A4 = *) OR (A4 = B4)))'> 

並用crossJoin使用:

a.crossJoin(b).where(expr) 

spark.conf.set("spark.sql.crossJoin.enabled", "true") 

a.join(b, expr) 

不幸的是,這相當昂貴,由於笛卡爾產品。對於少量列(4可能是一個邊界案例),您可以嘗試生成列的功率集並創建優化計劃,但顯然它不會擴展到更大數量的列。