收集到蜂巢中的地图

时间:2014-07-18 13:45:02

标签: hadoop hive

我有一个Hive表,例如

id  |  value
-------------
A      1
A      2
B      3
A      4
B      5

基本上,我想模仿Python的defaultdict(list),并创建一个以id为键,value为值的地图。

查询:

select COLLECT_TO_A_MAP(id, value)
from table

输出:

{A:[1,2,4], B:[3,5]}

我尝试使用klout's CollectUDAF(),但似乎这不会将值附加到数组,它只会更新它们。有什么想法吗?

修改 这是一个更详细的描述,所以我可以避免引用我在Hive文档中尝试函数的答案。假设我有一张桌子

num    |id    |value
____________________
1       A      1
1       A      2
1       B      3
2       A      4
2       B      5
2       B      6

我正在寻找的是提供此输出的UDAF

num     |new_map
________________________
1       {A:[1,2], B:[3]}
2       {A:[4], B:[5,6]}

此查询

select num
      ,COLLECT_TO_A_MAP(id, value) as new_map
from table
group by num

有一种解决方法可以实现这一目标。可以通过在查询中使用 Klout的(参见上面引用的UDAF)CollectUDAF()来模仿它,例如

add jar '~/brickhouse/target/brickhouse-0.6.0.jar'
create temporary function collect as 'brickhouse.udf.collect.CollectUDAF';

select num
       ,collect(id_array, value_array) as new_map
from (
      select collect_list(id) as id_array
            ,collect_list(value) as value_array
            ,num
      from table
      group by num
     ) A
group by num

但是,我宁愿不写一个嵌套查询。

编辑#2

(正如我在原始问题中所提到的)我已经尝试过使用 Klout的 CollectUDAF(),即使在你传递两个参数并创建一个地图的实例中也是如此。该输出是(如果应用于我的第一次编辑中的数据集)

1    {A:2, B:3}
2    {A:4, B:6}

正如我在原始问题中所述,它不会将值收集到它只收集最后一个数组的数组中(或更新数组)。

5 个答案:

答案 0 :(得分:2)

在Brickhouse中使用collect UDF(http://github.com/klout/brickhouse

这正是您所需要的。 Brickhouse'收集'如果使用了一个参数,则返回一个列表;如果使用两个参数,则返回一个映射。

答案 1 :(得分:1)

Brickhouse中的CollectUDAF(http://github.com/klout/brickhouse)会帮助你。

关于您的评论编辑#2

首先,将值收集到列表中,然后将k,v对收集到地图中:

select
    num,
    collectUDAF(id, values) as new_map
from
    (
    SELECT
        num,
        id,
        collect_set(value) as values
    FROM
        tbl
    GROUP BY
        num,
        id
    ) as sub
GROUP BY
    num

将返回

num  | new_map
________________________
1      {A:[1,2], B:[3]}
2      {A:[4], B:[5,6]}

答案 2 :(得分:-1)

如果您不关心值的显示顺序,可以使用Hive附带的collect_set()UDAF。

SELECT id, collect_set(value) FROM table GROUP BY id;

这可以解决您的问题。

答案 3 :(得分:-1)

您的当前查询按内部和外部查询中的num分组 - 您需要在内部查询中按id分组才能完成您尝试执行的操作。

答案 4 :(得分:-1)

https://github.com/klout/brickhouse/blob/master/src/main/java/brickhouse/udf/collect/CollectUDAF.java#L55

请参见Brickhouse udaf,当args num大于1时,将使用MapCollectUDAFEvaluator。

add jar */brickhouse.jar ;
create temporary function collect  as 'brickhouse.udf.collect.CollectUDAF';
select 
collect(a,b)
from( select 1232123 a,21 b 
    union all select 123 a,23 b)a;


result:{1232123:21,123:23}