Hive 中的 LEFT SEMI JOIN 與 JOIN ON


hive 的 join 類型有好幾種,其實都是把 MR 中的幾種方式都封裝實現了,其中 join on、left semi join 算是里邊具有代表性,且使用頻率較高的 join 方式。

1、聯系

他們都是 hive join 方式的一種,join on 屬於 common join(shuffle join/reduce join),而 left semi join 則屬於 map join(broadcast join)的一種變體,從名字可以看出他們的實現原理有差異。

2、區別

(1)Semi Join,也叫半連接,是從分布式數據庫中借鑒過來的方法。它的產生動機是:對於reduce side join,跨機器的數據傳輸量非常大,這成了join操作的一個瓶頸,如果能夠在map端過濾掉不會參加join操作的數據,則可以大大節省網絡IO,提升執行效率。
實現方法很簡單:選取一個小表,假設是File1,將其參與join的key抽取出來,保存到文件File3中,File3文件一般很小,可以放到內存中。在map階段,使用DistributedCache將File3復制到各個TaskTracker上,然后將File2中不在File3中的key對應的記錄過濾掉,剩下的reduce階段的工作與reduce side join相同。
由於 hive 中沒有 in/exist 這樣的子句(新版將支持),所以需要將這種類型的子句轉成 left semi join。left semi join 是只傳遞表的 join key 給 map 階段 , 如果 key 足夠小還是執行 map join, 如果不是則還是 common join。關於 common join(shuffle join/reduce join)的原理請參考文末 refer。

(2)left semi join 子句中右邊的表只能在 ON 子句中設置過濾條件,在 WHERE 子句、SELECT 子句或其他地方過濾都不行。

(3)對待右表中重復key的處理方式差異:因為 left semi join 是 in(keySet) 的關系,遇到右表重復記錄,左表會跳過,而 join on 則會一直遍歷。

最后的結果是這會造成性能,以及 join 結果上的差異。

(4)left semi join 中最后 select 的結果只許出現左表,因為右表只有 join key 參與關聯計算了,而 join on 默認是整個關系模型都參與計算了。

3、兩種 join 的“坑”

  由於HIVE中都是等值連接,在JOIN使用的時候,有兩種寫法在理論上是可以達到相同的效果的,但是由於實際情況的不一樣,子表中數據的差異導致結果也不太一樣。 

寫法一: left semi join

select
         a.bucket_id
        ,a.search_type
        ,a.level1
        ,a.name1
        ,a.level2
        ,a.name2
        ,cast((a.alipay_fee) as double) as zhuliu_alipay
        ,cast(0 as double) as total_alipay
        from tmall_data_fdi_search_zhuliu_alipay_cocerage_bucket_1 a
     left semi join
     tmall_data_fdi_dim_main_auc b
     on (a.level2 = b.cat_id2
         and a.brand_id = b.brand_id
         and b.cat_id2 > 0
         and b.brand_id > 0
         and b.max_price = 0
     )

結果是 3121 條

寫法二: join on

select
     a.bucket_id 
    ,a.search_type 
    ,a.level1 
    ,a.name1 
    ,a.level2 
    ,a.name2 
    ,cast((a.alipay_fee) as double) as zhuliu_alipay 
    ,cast(0 as double) as total_alipay
from tmall_data_fdi_search_zhuliu_alipay_cocerage_bucket_1 a
join   tmall_data_fdi_dim_main_auc b
on       (a.level2 = b.cat_id2
     and a.brand_id = b.brand_id)
where  b.cat_id2 > 0
     and b.brand_id > 0
     and b.max_price = 0

 

結果是 3142 條

這兩種寫法帶來的值居然不是相等的,我一直以為理解這兩種方式的寫法是一樣的, 但是統計的結果卻是不一樣的。 
經過一層一層的查找,發現是由於子表(tmall_data_fdi_dim_main_auc)中存在重復的數據,當使用JOIN ON的時候,A,B表會關聯出兩條記錄,應為ON上的條件符合; 
而是用LEFT SEMI JOIN 當A表中的記錄,在B表上產生符合條件之后就返回,不會再繼續查找B表記錄了,所以如果B表有重復,也不會產生重復的多條記錄。 

大多數情況下 JOIN ON 和 left semi on 是對等的,但是在上述情況下會出現重復記錄,導致結果差異,所以大家在使用的時候最好能了解這兩種方式的原理,避免掉“坑”。

 

其他參考:

demo1:

What is difference between natural join and semi join?

The result of the natural join is the set of all combinations of tuples in R and S that are equal on their common attribute names.

The result of the semijoin is only the set of all tuples in R for which there is a tuple in S that is equal on their common attribute names.

The point is that natural join is a set of all combinations and semijoin is only the tuples from the first relation not a combination between the two.

R1   R2

A B  B C

1 2  2 3
 
1 3  3 4

1 4  5 3
R1 (natural join) R2 =

A B C


1 2 3

1 3 4

whereas R1(semijoin) R2 =

A B

1 2

1 3

So in a way semijoin selects and returns a table of only the tuples from R1 that have an equal attribute with R2

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM