我是 Pig 的新手,我想将一袋元组转换为一个映射,每个元组中的特定值作为键。基本上我想改变:
{(id1, value1),(id2, value2), ...}
进入 [id1#value1, id2#value2]
我在网上找了一段时间,但似乎找不到解决方案。我试过了:
<span style="color:#444444"><span style="background-color:#f6f6f6">bigQMap = FOREACH bigQFields GENERATE TOMAP(queryId, queryStart);</span></span>
但我最终得到了一袋地图(例如 {[id1#value1], [id2#value2], ...}
),这不是我想要的。如何从一袋键值元组中构建地图?
以下是我尝试运行的特定脚本,以防相关
<span style="color:#444444"><span style="background-color:#f6f6f6">rawlines = LOAD <span style="color:#880000">'...'</span>使用 PigStorage( <span style="color:#880000">'`'</span> );
bigQFields = FOREACH bigQLogs GENERATE GFV(*, <span style="color:#880000">'queryId'</span> )
<span style="color:#333333"><strong>as</strong></span> queryId, GFV(*, <span style="color:#880000">'queryStart'</span> )
<span style="color:#333333"><strong>as</strong></span> queryStart;
大QMap = ?? 如何制作<span style="color:#333333"><strong>以</strong></span>queryId<span style="color:#333333"><strong>为</strong></span>键、queryStart<span style="color:#333333"><strong>为</strong></span><span style="color:#333333"><strong>值的</strong></span><span style="color:#333333"><strong>地图</strong></span>?; </span></span>
TOMAP
接受一系列对并将它们转换为地图,因此它的用途如下:
<span style="color:#444444"><span style="background-color:#f6f6f6">-- Schema: A:{foo:chararray, bar:int, bing:chararray, bang:int}
-- 数据: (John, <span style="color:#880000">27</span> , Joe, <span style="color:#880000">30</span> )
B = FOREACH A 生成 TOMAP(foo, bar, bing, bang) AS m ;
-- 架构: B:{m: map[]}
-- 数据: (John <span style="color:#888888">#27,Joe#30)</span></span></span>
如您所见,语法不支持将包转换为地图。据我所知,没有办法将包转换为您必须在纯猪中映射的格式。但是,您可以明确地编写一个 java UDF 来执行此操作。
注意:我对 java 不太熟悉,所以这个 UDF 可以很容易地改进(添加异常处理,如果一个键添加两次会发生什么等)。但是,它确实可以完成您需要的工作。
<span style="color:#444444"><span style="background-color:#f6f6f6">打包 myudfs;
<span style="color:#333333"><strong>导入</strong></span>java.io.IOException;
<span style="color:#333333"><strong>导入</strong></span>org.apache.pig.EvalFunc;
<span style="color:#333333"><strong>导入</strong></span>java.util。<span style="color:#397300">地图</span>;
<span style="color:#333333"><strong>导入</strong></span>java.util.HashMap;
<span style="color:#333333"><strong>导入</strong></span>java.util。<span style="color:#397300">迭代器</span>;
<span style="color:#333333"><strong>导入</strong></span>org.apache.pig.data.Tuple;
<span style="color:#333333"><strong>导入</strong></span>org.apache.pig.data.DataBag;
公共<span style="color:#333333"><strong>类</strong></span> <span style="color:#880000"><strong>ConvertToMap</strong></span> <span style="color:#333333"><strong>扩展</strong></span> <span style="color:#880000"><strong>EvalFunc</strong></span> <<span style="color:#880000"><strong>地图</strong></span>>
{
公共<span style="color:#397300">地图</span>执行(元组输入)抛出 IOException {
DataBag 值 = (DataBag) 输入。<span style="color:#333333"><strong>得到</strong></span>(<span style="color:#880000">0</span>);
<span style="color:#397300">映射</span><<span style="color:#397300">对象</span>,<span style="color:#397300">对象</span>> m = <span style="color:#333333"><strong>new</strong></span> HashMap<<span style="color:#397300">对象</span>,<span style="color:#397300">对象</span>>();
<span style="color:#333333"><strong>for</strong></span> ( <span style="color:#397300">Iterator</span> <Tuple> it = values.iterator(); it.hasNext();) {
元组 t = it.next();
m.put(t.get ( <span style="color:#333333"><strong>0</strong></span> ) <span style="color:#880000">,</span> t.get <span style="color:#333333"><strong>(</strong></span> 1 <span style="color:#880000">)</span> );
}
<span style="color:#333333"><strong>返回</strong></span>米;
}
}</span></span>
将脚本编译到 jar 中后,可以像这样使用它:
<span style="color:#444444"><span style="background-color:#f6f6f6">注册 myudfs.jar ;
<span style="color:#888888">-- A 正在加载我制作的一些样本数据</span>
A = <span style="color:#333333"><strong>LOAD </strong></span> <span style="color:#880000">'foo.in' </span> <span style="color:#333333"><strong>AS</strong></span> (foo:{T:( <span style="color:#333333"><strong>id</strong></span> :chararray, <span style="color:#333333"><strong>value</strong></span> :chararray)}) ;
B = FOREACH A GENERATE myudfs.ConvertToMap(foo) AS bar;</span></span>
内容 foo.in
:
<span style="color:#444444"><span style="background-color:#f6f6f6">{(<span style="color:#333333"><strong>打开</strong></span>,阿帕奇),(<span style="color:#333333"><strong>阿帕奇</strong></span>,hadoop)}
{( <span style="color:#333333"><strong>foo</strong></span> ,bar),( <span style="color:#333333"><strong>bar</strong></span> ,foo),( <span style="color:#333333"><strong>open</strong></span> ,what)}</span></span>
输出 B
:
<span style="color:#444444"><span style="background-color:#f6f6f6">([打开<span style="color:#bc6060">#apache</span>,apache <span style="color:#bc6060">#hadoop</span> ])
([bar <span style="color:#bc6060">#foo</span> ,open <span style="color:#bc6060">#what</span> ,foo <span style="color:#bc6060">#bar</span> ])</span></span>
另一种方法是使用 python 创建 UDF :
myudfs.py
<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#888888">#!/usr/bin/python</span>
<span style="color:#1f7199">@outputSchema("foo:map[]") </span>
<span style="color:#333333"><strong>def </strong></span> <span style="color:#880000"><strong>BagtoMap </strong></span>(bag):
d = {}
<span style="color:#333333"><strong>对于</strong></span>键,<span style="color:#333333"><strong>包</strong></span>中的值:
d[键] = 值
<span style="color:#333333"><strong>返回</strong></span>d</span></span>
这是这样使用的:
<span style="color:#444444"><span style="background-color:#f6f6f6">使用 jython 作为 myfuncs 注册“myudfs.py”;
<span style="color:#888888">-- A 仍然只是加载我的一些测试数据</span>
A = <span style="color:#333333"><strong>LOAD </strong></span> <span style="color:#880000">'foo.in' </span> <span style="color:#333333"><strong>AS</strong></span> (foo:{T:( <span style="color:#333333"><strong>key</strong></span> :chararray, <span style="color:#333333"><strong>value</strong></span> :chararray)}) ;
B = FOREACH A GENERATE myfuncs.BagtoMap(foo) ;</span></span>
并产生与 Java UDF 相同的输出。
奖励:由于我不太喜欢地图,这里有一个链接,解释了如何仅使用键值对来复制地图的功能。由于您的键值对在一个包中,因此您需要在嵌套中执行类似地图的操作 FOREACH
:
<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#888888">-- A 是一个包含 kv_pairs 的模式,形式为 {(id, value)} 的包</span>
B = FOREACH A {
temp = FOREACH kv_pairs GENERATE (key== <span style="color:#880000">'foo'</span> ?value:NULL) ;
<span style="color:#888888">-- 输出类似于:({(),(thevalue),(),()})</span>
<span style="color:#888888">-- MAX 将从过滤后的包中提取最大值,</span>
<span style="color:#888888">如果键匹配,则为 --value(字符数组)。否则它将返回 NULL。</span>
GENERATE MAX(temp) as kv_pairs_filtered ;
}</span></span>
本文含有隐藏内容,请 开通VIP 后查看