转换一组键值元组以映射到Apache Pig

Pen*_*tor 8 map apache-pig

我是Pig的新手,我想将一个元组转换为每个元组中具有特定值的映射作为键.基本上我想改变:

{(id1, value1),(id2, value2), ...}[id1#value1, id2#value2]

我一直在网上寻找一段时间,但我似乎无法找到解决方案.我试过了:

bigQMap = FOREACH bigQFields GENERATE TOMAP(queryId, queryStart);
Run Code Online (Sandbox Code Playgroud)

但我最终得到了一袋地图(例如{[id1#value1], [id2#value2], ...}),这不是我想要的.如何从一袋键值元组中建立一张地图?

下面是我正在尝试运行的特定脚本,以防它相关

rawlines = LOAD '...' USING PigStorage('`');
bigQFields = FOREACH bigQLogs GENERATE GFV(*,'queryId')
   as queryId, GFV(*, 'queryStart')
   as queryStart;
bigQMap = ?? how to make a map with queryId as key and queryStart as value ?? ;
Run Code Online (Sandbox Code Playgroud)

mr2*_*ert 11

TOMAP 采用一系列对并将它们转换为地图,因此它的用途如下:

-- Schema: A:{foo:chararray, bar:int, bing:chararray, bang:int}
-- Data:     (John,          27,      Joe,            30)
B = FOREACH A GENERATE TOMAP(foo, bar, bing, bang) AS m ;
-- Schema: B:{m: map[]}
-- Data:     (John#27,Joe#30)
Run Code Online (Sandbox Code Playgroud)

因此,您可以看到语法不支持将包转换为地图.据我所知,没有办法转换你必须在纯猪中绘制的格式的包.但是,您可以明确地编写java UDF来执行此操作.

注意:我对java不太熟悉,所以可以很容易地改进这个UDF(添加异常处理,如果一个键添加两次会发生什么等).但是,它确实可以满足您的需求.

package myudfs;
import java.io.IOException;
import org.apache.pig.EvalFunc;

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.pig.data.Tuple;
import org.apache.pig.data.DataBag;

public class ConvertToMap extends EvalFunc<Map>
{
    public Map exec(Tuple input) throws IOException {
        DataBag values = (DataBag)input.get(0);
        Map<Object, Object> m = new HashMap<Object, Object>();
        for (Iterator<Tuple> it = values.iterator(); it.hasNext();) {
            Tuple t = it.next();
            m.put(t.get(0), t.get(1));
        }
        return m;
    }
}
Run Code Online (Sandbox Code Playgroud)

将脚本编译成jar后,可以使用它:

REGISTER myudfs.jar ;
-- A is loading some sample data I made
A = LOAD 'foo.in' AS (foo:{T:(id:chararray, value:chararray)}) ;
B = FOREACH A GENERATE myudfs.ConvertToMap(foo) AS bar;
Run Code Online (Sandbox Code Playgroud)

内容foo.in:

{(open,apache),(apache,hadoop)}
{(foo,bar),(bar,foo),(open,what)}
Run Code Online (Sandbox Code Playgroud)

输出来自B:

([open#apache,apache#hadoop])
([bar#foo,open#what,foo#bar])
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用python创建UDF:

myudfs.py

#!/usr/bin/python

@outputSchema("foo:map[]")
def BagtoMap(bag):
    d = {}
    for key, value in bag:
        d[key] = value
    return d
Run Code Online (Sandbox Code Playgroud)

使用方式如下:

Register 'myudfs.py' using jython as myfuncs;
-- A is still just loading some of my test data
A = LOAD 'foo.in' AS (foo:{T:(key:chararray, value:chararray)}) ;
B = FOREACH A GENERATE myfuncs.BagtoMap(foo) ;
Run Code Online (Sandbox Code Playgroud)

并生成与Java UDF相同的输出.


奖励: 因为我不太喜欢地图,所以 这里有一个链接,解释了如何使用键值对来复制地图的功能.由于您的键值对在一个包中,您需要在嵌套中执行类似地图的操作FOREACH:

-- A is a schema that contains kv_pairs, a bag in the form {(id, value)}
B = FOREACH A {
    temp = FOREACH kv_pairs GENERATE (key=='foo'?value:NULL) ;
    -- Output is like: ({(),(thevalue),(),()})

    -- MAX will pull the maximum value from the filtered bag, which is 
    -- value (the chararray) if the key matched. Otherwise it will return NULL.
    GENERATE MAX(temp) as kv_pairs_filtered ;
}
Run Code Online (Sandbox Code Playgroud)