使用pig,如何将混合格式行解析为元组和一包元组?

c9qzyr3d  于 2021-06-25  发布在  Pig
关注(0)|答案(1)|浏览(362)

我是新来的Pig,我有一个问题解析我的输入,并把它转换成一种格式,我可以使用。输入文件包含同时具有固定场和kv对的线,如下所示:
ff1 | ff2 | ff3 | ff4 | kvp1 | kvp2 |…| kvpn
我的目标是计算每个kv对的唯一固定场组合的数量。因此,考虑到以下输入行:

1|2|3|4|key1=value1|key2=value2
2|3|4|5|key1=value7|key2=value2|key3=value3

完成后,我希望能够生成以下结果(此时输出格式并不重要,我只是向您展示我希望的结果):

key1=value1 : 1
key1=value7 : 1
key2=value2 : 2
key3=value3 : 1

看起来我应该可以通过将固定场分组并将一袋kv线对展平来生成叉积
我试着用这样的方式来阅读这篇文章:

data = load 'myfile' using PigStorage('|');
A = foreach data generate $0 as ff1:chararray, $1 as ff2:long, $2 as ff3:chararray, $3 as ff4:chararray, TOBAG($4..) as kvpairs:bag{kvpair:tuple()};
B = foreach A { sorted = order A by ff2; lim = limit sorted 1; generate group.ff1, group.ff4, flatten( lim.kvpairs ); };
C = filter B by ff3 matches 'somevalue';
D = foreach C generate ff1, ff4, flatten( kvpairs ) as kvpair;
E = group D by (ff1, ff4, kvpair);
F = foreach E generate group, COUNT(E);

这将生成具有以下架构的记录:
a:{date:long,hms:long,id:long,ff1:chararray,ff2:long,ff3:chararray,ff4:chararray,kvpairs:{kvpair:(null)}}
虽然这让我得到了我想要的模式,但有几个问题我似乎无法解决:
通过将tobag与..一起使用,没有任何模式可以应用于我的kvpairs,因此我无法对kvpair进行筛选,而且我似乎无法在任何时候强制转换这个,因此这是一个all or nothing查询。
不管我使用什么值,语句“c”中的筛选器似乎都不返回任何数据,即使我使用“.*”或“.+”之类的值。我不知道这是因为没有模式,还是这实际上是pig中的一个bug。如果我从语句b中转储一些数据,我肯定会在那里看到与这些表达式匹配的数据。
因此,我尝试以不同的方式处理问题,通过使用以下方式加载数据:

data = load 'myfile' using PigStorage('\n') as (line:chararray);
init_parse = foreach data generate FLATTEN( STRSPLIT( line, '\\|', 4 ) ) as (ff1:chararray, ff2:chararray, ff3:chararray, ff4:chararray, kvpairsStr:chararray);
A = foreach mc_bk_data generate ff1, ff2, ff3, ff4, TOBAG( STRSPLIT( kvpairsStr, '\\|', 500 ) ) as kvpairs:bag{t:(kvpair:chararray)};

这里的问题是tobag(strsplit(…))结果是一个包含单个元组的包,其中每个kvpairs都是该元组中的一个字段。我真的需要包包含,每个单独的kvpairs作为一个字段的元组,这样当我压平包时,我得到包和我感兴趣的组的叉积。
我对其他解决这个问题的方法也持开放态度,但我似乎可以找到一个好方法,将多个字段的元组转换为一个元组包,每个元组都有一个字段。
我使用的是ApachePig版本0.11.1.1.3.0.0-107
提前谢谢。

v09wglhw

v09wglhw1#

你的第二种方法是正确的。不幸的是,您将需要一个udf来将一个元组转换为一个包,据我所知,没有内置的实现方法。不过,写一篇是件很简单的事。
您不想在固定字段上分组,而是在键值对本身上分组。所以您只需要保留键值对的元组;可以完全忽略固定字段。
udf非常简单。在java中,您可以在自己的 exec 方法:

DataBag b = new DefaultDataBag();
Tuple t = (Tuple) input.get(0);
for (int i = 0; i < t.size(); i++) {
    Object o = t.get(i);
    Tuple e = TupleFactory.getInstance().createTuple(o);
    b.add(e);
}

return b;

一旦你有了它,把元组从 STRSPLIT 把它放进一个袋子里,压平,然后进行分组和计数。

相关问题