在Hive SQL中-以没有UDF的间隔加入

时间:2018-12-21 10:19:43

标签: sql join hive bigdata hiveql

我遇到过一个练习,该练习要求将一个表中与事件相关的IP与另一表中的国家IP范围进行匹配。即它可能看起来像这样(简化):

table: events

event_id  |  source_ip
----------------------
12345678  |  3.15.49.5
31234314  |  7.1.8.190

table: geoips

country  |  start_ip  |  end_ip
-----------------------------------
us       |  1.0.0.0   |  1.127.255.255
us       |  1.128.0.0 |  1.255.255.255
us       |  3.0.0.0   |  3.255.255.255

我们想要得到:

event_id  |  source_ip  |  country
----------------------------------
12345678  |  3.15.49.5  |  us
31234314  |  7.1.8.190  |  uk

假设,我们可以将IP转换为整数以简化比较(或转换为零填充字符串,以便可以按字母顺序对它们进行比较)。

所以就像联接on event_ip >= start_ip and event_ip <= end_ip。但是据我所知,在Hive中,“仅支持平等联接”是行不通的。

(在本练习中)最常见的建议是使用UDF-据我了解,只有在包含范围的表适合内存的情况下才有可能。

尽管我确实知道如何编写UDF,但我对这种方法并不满意。特别是因为它没有说如果范围表很大(当然不是这种情况)并且不容易放入内存,该怎么办。

直觉上看来,除了Hive之外,如果我们两个表都按IP排序,我们可以一遍解决问题,保持“当前范围”并将所有即将到来的IP与其匹配,然后更新到下一个范围。这甚至应该足够容易并行化...

所以我想知道(也许在Hive的更高版本中)是否有依赖HQL本身的解决方案。

1 个答案:

答案 0 :(得分:1)

在Hive中不允许使用不相等的联接。没有条件条件的联接是交叉联接,它将乘以行,并且应用于结果数据集的Where子句将过滤大量行,例如x195(国家/地区数),这将导致性能问题。

但是,在这种情况下,您可以尝试将CROSS join转换为map-join,因为country表可以容纳在内存中。解决方案是MAP-JOIN。小表将广播到每个映射器,并加载到内存中并用于连接。 EXPLAIN应该在计划中反映MAP-JOIN,请检查它。 Mapjoin将快速运行。

使用Tez,向量化执行,mapjoin和cbo:

set hive.cbo.enable=true;
set hive.execution.engine=tez;
set hive.vectorized.execution.enabled = true;
set hive.vectorized.execution.reduce.enabled = true;
set hive.compute.query.using.stats=true;
set hive.stats.fetch.column.stats=true;
set hive.stats.fetch.partition.stats=true;
set hive.optimize.ppd=true;
--enable mapjoin
set hive.auto.convert.join=true;

select e.event_id, e.source_ip, i.country
    from events e 
         cross join geoips i 
   where e.event_ip >= i.start_ip and e.event_ip <= i.end_ip;