1

私は豚にかなり慣れていないので、ログの解析について質問があります。現在、regex_extractを使用してURL文字列内の重要なタグを解析していますが、文字列全体をマップに変換する必要があると考えています。0.10を使用してデータのサンプルセットに取り組んでいますが、本当に迷子になり始めています。実際には、私のURL文字列にはタグが繰り返されています。したがって、私のマップは実際には値としてバッグを含むマップである必要があります。次に、flattenを使用して後続のジョブを作成できます。

これが私のテストデータです。最後のエントリは、繰り返されるタグに関する私の問題を示しています。

`pig -x local`
grunt> cat test.log
test1   user=3553&friend=2042&system=262
test2   user=12523&friend=26546&browser=firfox
test2   user=205&friend=3525&friend=353

トークン化を使用してインナーバッグを生成しています。

grunt> A = load 'test.log' as (f:chararray, url:chararray);
grunt> B = foreach A generate f, TOKENIZE(url,'&') as attr;
grunt> describe B;
B: {f: chararray,attr: {tuple_of_tokens: (token: chararray)}}

grunt> dump B;
(test1,{(user=3553),(friend=2042),(system=262)})
(test2,{(user=12523),(friend=26546),(browser=firfox)})
(test2,{(user=205),(friend=3525),(friend=353)})

これらの関係にネストされたforeachを使用しますが、私が気付いていないいくつかの制限があると思います。

grunt> C = foreach B {
>> D = foreach attr generate STRSPLIT($0,'=');
>> generate f, D as taglist;
>> }

grunt> dump C;
(test1,{((user,3553)),((friend,2042)),((system,262))})
(test2,{((user,12523)),((friend,26546)),((browser,firfox))})
(test2,{((user,205)),((friend,3525)),((friend,353))})

grunt> G = foreach C {
>> H = foreach taglist generate TOMAP($0.$0, $0.$1) as tagmap;
>> generate f, H as alltags;
>> }

grunt> describe G;
G: {f: chararray,alltags: {tuple_of_tokens: (tagmap: map[])}}

grunt> dump G;
(test1,{([user#3553]),([friend#2042]),([system#262])})
(test2,{([user#12523]),([friend#26546]),([browser#firfox])})
(test2,{([user#205]),([friend#3525]),([friend#353])})

grunt> MAPTEST = foreach G generate f, flatten(alltags.tagmap);
grunt> describe MAPTEST;
MAPTEST: {f: chararray,null::tagmap: map[]}

grunt> res = foreach MAPTEST generate $1#'user';
grunt> dump res;
(3553)
()
()
(12523)
()
()
(205)
()
()

grunt> res = foreach MAPTEST generate $1#'friend';
grunt> dump res;
()
(2042)
()
()
(26546)
()
()
(3525)
(353)

だからそれはひどいことではありません。近いと思いますが、完璧ではありません。私のより大きな懸念は、少なくともマップに追加する前に、最後の行に「友達」のタグが2つあるため、タグをグループ化する必要があることです。

grunt> dump C;
(test1,{((user,3553)),((friend,2042)),((system,262))})
(test2,{((user,12523)),((friend,26546)),((browser,firfox))})
(test2,{((user,205)),((friend,3525)),((friend,353))})

ネストされたforeachをグループで試しましたが、エラーが発生します。

grunt> G = foreach C {
>> H = foreach taglist generate *;
>> I = group H by $1;
>> generate I;
>> }
2013-01-18 14:56:31,434 [main] ERROR org.apache.pig.tools.grunt.Grunt - ERROR 1200:   <line 34, column 10>  Syntax error, unexpected symbol at or near 'H'

このURL文字列をバッグのマップに生成する方法を知っている人はいますか?これは一般的なユースケースのように思われるので、豚のマクロか何かがあると考えました。どんなアイデアでも大歓迎です。

4

2 に答える 2

0

良いニュースと悪いニュース。良いニュースは、これを達成するのは非常に簡単なことです。悪いニュースは、UDFに頼らなければ、理想的なもの、つまり1つのマップ内のすべてのタグと値のペアを実現できないことです。

まず、いくつかのヒント:タプルに無駄なレベルのネストがないようにするためFLATTENの結果と、後で行う必要がないようにネストされた内部に戻すことです。また、出力文字列の最大数を指定するオプションの3番目の引数があります。これを使用して、出力のスキーマを保証します。スクリプトの修正バージョンは次のとおりです。STRSPLITFLATTENforeachSTRSPLIT

A = load 'test.log' as (f:chararray, url:chararray);
B = foreach A generate f, TOKENIZE(url,'&') as attr;
C = foreach B {
    D = foreach attr generate FLATTEN(STRSPLIT($0,'=',2)) AS (key:chararray, val:chararray);
    generate f, FLATTEN(D);
};
E = foreach (group C by (f, key)) generate group.f, TOMAP(group.key, C.val);
dump E;

出力:

(test1,[user#{(3553)}])
(test1,[friend#{(2042)}])
(test1,[system#{(262)}])
(test2,[user#{(12523),(205)}])
(test2,[friend#{(26546),(3525),(353)}])
(test2,[browser#{(firfox)}])

タグと値の分割が完了したら、タグごとgroupに値のバッグを取得します。次に、それを地図に入れます。これは、同じID(、ここ)を持つ2つの行がある場合test2、それらを結合することを前提としていることに注意してください。そうでない場合は、その行の一意の識別子を作成する必要があります。

残念ながら、UDFを使用せずにマップを組み合わせる方法は明らかにありませんが、これは可能なすべてのUDFの中で最も単純なものである必要があります。(テストされていない)のようなもの:

public class COMBINE_MAPS extends EvalFunc<Map> {
    public Map<String, DataBag> exec(Tuple input) throws IOException {
        if (input == null || input.size() != 1) { return null; }

        // Input tuple is a singleton containing the bag of maps
        DataBag b = (DataBag) input.get(0);

        // Create map that we will construct and return
        Map<String, Object> m = new HashMap<String, Object>();

        // Iterate through the bag, adding the elements from each map
        Iterator<Tuple> iter = b.iterator();
        while (iter.hasNext()) {
            Tuple t = iter.next();
            m.putAll((Map<String, Object>) t.get(0));
        }

        return m;
    }
}

このようなUDFを使用すると、次のことができます。

F = foreach (group E by f) generate COMBINE_MAPS(E.$1);

このUDFでは、入力マップのいずれかがキーでオーバーラップしている場合、一方が他方を上書きし、どちらが「勝つ」かを事前に判断する方法がないことに注意してください。これが問題になる可能性がある場合は、UDFに何らかのエラーチェックコードを追加する必要があります。

于 2013-01-18T23:11:01.547 に答える
0

将来誰かがこれを行おうとした場合に備えて、これを更新すると思いました。ピッグラテンを機能させることはありませんでしたが、完全なUDFルートを使用しました。悲しいことに、私は実際にはプログラマーではないので、Javaの例ではしばらくの間私を失ってしまいました。しかし、私はこれまで機能していたPythonUDFを一緒にハックすることができました。エラーなどを処理するためにクリーンアップする必要がありますが、これは今のところ使用可能です。これを行うためのより良いJavaの方法もあると確信しています。

#!/usr/bin/python
@outputSchema("tagmap:map[{(value:chararray)}]")

def inst_url_parse(url_query):
        query_vals = url_query.split("&")
        url_query_map = {}
        for each_val in query_vals:
                kv = each_val.split("=")
                if kv[0] in url_query_map:
                        url_query_map[kv[0]].append(kv[1])
                else:
                        url_query_map[kv[0]] = [kv[1]]

        return url_query_map

各キーが0、1、Nの値を持つ可能性があるため、URLクエリがこのように保存されるのが本当に気に入っています。ダウンストリームジョブは、evalでflatten(tagmap#'key')を呼び出すだけで、以前行っていたものと比べてかなり苦痛がありません。これを使用すると、はるかに高速に開発できます。また、データをhcatalogに次のように保存します。

querymap<string, array<string>> 

また、LATERALVIEWを使用したハイブクエリ/ビューでも正常に機能するようです。誰かわかったね?

これが質疑応答サイトに対してあまりにも意見が分かれている場合は申し訳ありません。

于 2013-02-02T02:57:54.887 に答える