不知何故,我得到了filename.log,例如(分隔标签)
Name:Peter Age:18
Name:Tom Age:25
Name:Jason Age:35
因为key列的值可能不同我加载文本时无法定义架构,如
a = load 'filename.log' as (Name:chararray,Age:int);
我也不想像
那样按位置调用b = foreach a generate $0,$1;
我想要做的是,仅从filename.log开始,可以通过键调用每个值,例如
a = load 'filename.log' using PigStorage('\t');
b = group b by Name;
c = foreach b generate group, COUNT(b);
dump c;
为此目的,我写了一些Java UDF,它分隔键:值并获取元组中每个字段的值,如下所示
public class SPLITALLGETCOL2 extends EvalFunc<Tuple>{
@Override
public Tuple exec(Tuple input){
TupleFactory mTupleFactory = TupleFactory.getInstance();
ArrayList<String> mProtoTuple = new ArrayList<String>();
Tuple output;
String target=input.toString().substring(1, input.toString().length()-1);
String[] tokenized=target.split(",");
try{
for(int i=0;i<tokenized.length;i++){
mProtoTuple.add(tokenized[i].split(":")[1]);
}
output = mTupleFactory.newTupleNoCopy(mProtoTuple);
return output;
}catch(Exception e){
output = mTupleFactory.newTupleNoCopy(mProtoTuple);
return output;
}
}
}
我应该如何改变这种方法来获得我想要的东西?或者我应该如何编写其他UDF才能到达那里?
答案 0 :(得分:0)
无论你做什么,都不要使用元组来存储输出。元组用于存储固定数量的字段,您可以在其中了解每个字段包含的内容。由于您不知道密钥将在Name,Age表单中(或者甚至存在,或者不会有更多),因此您应该使用bag。包是无序的元组。只要元组具有相同的模式,它们就可以包含任意数量的元组。这些都是架构B: {T:(key:chararray, value:chararray)}
的有效行李:
{(Name,Foo),(Age,Bar)}
{(Age,25),(Name,Jim)}
{(Name,Bob)}
{(Age,30),(Name,Roger),(Hair Color,Brown)}
{(Hair Color,),(Name,Victor)} -- Note the Null value for Hair Color
然而,听起来你真的想要一张地图:
<强> myudf.py 强>
@outputSchema('M:map[]')
def mapize(the_input):
out = {}
for kv in the_input.split(' '):
k, v = kv.split(':')
out[k] = v
return out
<强> myscript.pig 强>
register '../myudf.py' using jython as myudf ;
A = LOAD 'filename.log' AS (total:chararray) ;
B = FOREACH A GENERATE myudf.mapize(total) ;
-- Sample usage, grouping by the name key.
C = GROUP B BY M#'Name' ;
使用#
运算符,您可以使用您提供的密钥从地图中提取所有值。您可以阅读有关地图here的更多信息。