8

Pig は初めてで、タプルのバッグを各タプルの特定の値をキーとしてマップに変換したいと考えています。基本的に私は変更したい:

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

しばらくの間、オンラインで調べてみましたが、解決策が見つからないようです。私はもう試した:

bigQMap = FOREACH bigQFields GENERATE TOMAP(queryId, queryStart);

{[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 ?? ;
4

2 に答える 2

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)

ご覧のとおり、構文はバッグからマップへの変換をサポートしていません。私の知る限り、純粋な豚でマッピングする必要がある形式でバッグを変換する方法はありません。ただし、これを行うためにJava UDFを確実に作成できます。

注:私は Java の経験があまりないので、この UDF は簡単に改善できます (例外処理の追加、キーが 2 回追加された場合など)。ただし、必要なことは実現します。

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;
    }
}

スクリプトを 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;

の内容foo.in:

{(open,apache),(apache,hadoop)}
{(foo,bar),(bar,foo),(open,what)}

からの出力B:

([open#apache,apache#hadoop])
([bar#foo,open#what,foo#bar])

もう 1 つの方法は、Python を使用して UDF を作成することです。

myudfs.py

#!/usr/bin/python

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

これは次のように使用されます:

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) ;

そして、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 ;
}
于 2013-07-25T08:23:17.467 に答える