我对猪很新,对日志解析有疑问。我目前通过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
我正在使用tokenize来生成内袋。
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字符串生成到行李箱地图中?想象有一个猪宏或什么,因为这似乎是一个常见的用例。任何想法都非常感谢。
答案 0 :(得分:0)
好消息和坏消息。好消息是实现这一目标非常简单。坏消息是你无法实现我认为理想的东西 - 单个地图中的所有标记/值对 - 而不需要使用UDF。
首先,一些提示:FLATTEN
STRSPLIT
的结果,以便您的元组中没有无用的嵌套级别,并且FLATTEN
在嵌套的foreach
内1}}以便您以后不需要这样做。此外,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)}])
在您完成拆分标记和值后,group
也会通过标记来获取您的值。然后将其放入地图中。请注意,这假设如果您有两行具有相同ID(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添加某种错误检查代码。
答案 1 :(得分:0)
我想我会更新这个以防将来有人试图这样做。我从来没有让猪拉丁工作,但我去了完整的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值。下游工作只是在eval中调用flatten(tagmap#'key'),与之前的工作相比,它非常轻松。使用它我们可以更快地开发。我们还将数据存储在hcatalog中
querymap<string, array<string>>
它似乎也适用于使用LATERAL VIEW的配置单元查询/视图。谁知道?
很抱歉,如果这对于Q和A网站来说过于自以为是。