Apache pig ApachePig-url解析为映射

Apache pig ApachePig-url解析为映射,apache-pig,Apache Pig,我对pig很陌生,对日志解析有疑问。目前,我通过regex_extract解析url字符串中的重要标记,但我认为应该将整个字符串转换为一个映射。我正在使用0.10处理一组样本数据,但我开始真正迷失方向。实际上,我的url字符串有重复的标记。所以我的地图应该是一个以包为值的地图。然后我就可以用flatte来写任何后续的作业了 这是我的测试数据。最后一个条目显示了我重复标记的问题 `pig -x local` grunt> cat test.log test1 user=3553&

我对pig很陌生,对日志解析有疑问。目前,我通过regex_extract解析url字符串中的重要标记,但我认为应该将整个字符串转换为一个映射。我正在使用0.10处理一组样本数据,但我开始真正迷失方向。实际上,我的url字符串有重复的标记。所以我的地图应该是一个以包为值的地图。然后我就可以用flatte来写任何后续的作业了

这是我的测试数据。最后一个条目显示了我重复标记的问题

`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)
所以这并不可怕。我认为这很接近,但并不完美。我更关心的是,我需要对标记进行分组,因为最后一行有两个“friend”标记,至少在我将其添加到地图之前是这样

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'
grunt>G=foreach C{
>>H=foreach标记列表生成*;
>>I=H组乘以1美元;
>>生成I;
>> }
2013-01-18 14:56:31434[main]ERROR org.apache.pig.tools.grunt.grunt-ERROR 1200:语法错误,意外符号位于或接近“H”

有人知道如何更接近于将这个URL字符串生成到行李地图中吗?我想可能会有一个pig宏之类的东西,因为这似乎是一个常见的用例。非常感谢您的任何想法。

好消息和坏消息。好消息是实现这一点非常简单。坏消息是,如果不使用UDF,您将无法实现我认为最理想的结果——在单个映射中的所有标记/值对

首先,有几个技巧:
展平
STRSPLIT
的结果,这样在元组中就不会有无用的嵌套级别,并且
在嵌套的
foreach
中再次展平
,这样以后就不必再做了。另外,
STRSPLIT
还有一个可选的第三个参数,用于提供最大输出字符串数。使用它来保证其输出的模式。以下是脚本的修改版本:

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)}])
完成标记和值的拆分后,
也按标记分组
,以获取您的值包。然后把它放到地图上。请注意,这假设如果有两行具有相同id(
test2
,此处),则需要将它们合并。如果不是这样,则需要为该行构造唯一标识符

不幸的是,显然没有办法在不使用UDF的情况下组合地图,但这应该是所有可能的UDF中最简单的。类似(未经测试):


请注意,在这个UDF中,如果任何一个输入映射的键有重叠,一个将覆盖另一个,并且无法提前知道哪个将“获胜”。如果这可能是一个问题,您需要在UDF中添加某种错误检查代码。

我想我会更新此代码,以防将来有人尝试这样做。我从来没有让猪拉丁语工作,但我走了整个UDF路线。遗憾的是,我并不是一个真正的程序员,所以java示例让我迷失了一段时间。但我设法拼凑了一个迄今为止一直有效的python UDF。仍然需要去清理它来处理错误等等,但是现在这是可用的。我相信还有更好的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
我非常喜欢我们的URL查询以这种方式存储,因为每个键都可以有0,1,N个值。下游工作在评估中称之为flatte(tagmap#'key'),与我之前所做的相比,它相当轻松。我们可以用它更快地开发。我们还将数据存储在hcatalog中

querymap<string, array<string>> 
querymap
对于使用横向视图的配置单元查询/视图,它似乎也能正常工作。谁知道呢


抱歉,如果这对问答网站来说太固执己见了

+1:出色地解释了问题,展示了您的尝试,并提供了简单说明问题的示例输入。谢谢。这给了我一些可以合作的东西。我真的很感激。对我来说,test1和test2不是真正的键,它们只是我的博客中的其他字段。我只是用它们来更好地显示这是一个内袋。在这种情况下,您可以将整行包含在
group by
字段中,理想情况下这是唯一的,然后忽略它。实际上,最好的解决方案是编写一个UDF,类似于我所展示的那样,在没有所有
组和
TOMAP
s等的情况下制作地图。这是有道理的。奇怪的是,它不是由别人写和出版的。似乎是一个非常常见的用例。谢谢
#!/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
querymap<string, array<string>>