如何从复杂的猪数据类型中提取简单的猪数据类型

Posted

技术标签:

【中文标题】如何从复杂的猪数据类型中提取简单的猪数据类型【英文标题】:How to pull simple pig data types out of complex pig data types 【发布时间】:2014-04-29 18:54:05 【问题描述】:

我正在尝试使用内置的 BuildBloomBloom UDF 在 PIG 中编写一个布隆过滤器构建器。调用BuildBloom UDF 的语法是:

define bb BuildBloom('hash_type', 'vector_size', 'false_positive_rate');

向量大小和误报率参数作为 charrarrays 传入。由于我不一定事先知道矢量大小,但在调用 BuildBloom UDF 之前它始终在脚本中可用,我想使用内置的 COUNT UDF 而不是一些硬编码的值。比如:

records = LOAD '$input' using PigStorage();
records = FOREACH records GENERATE 
    (long)     $0 AS value_fld:long, 
    (chararray)$1 AS filter_fld:chararray;
records_fltr = FILTER records by (filter_fld=='$filter_value') AND (value_fld is not null);
records_grp = GROUP records_fltr all;
records_count = FOREACH records_grp GENERATE (chararray) COUNT(records_fltr.value_fld) AS count:chararray;
n = FOREACH records_count GENERATE flatten(count);
define bb BuildBloom('jenkins', n, '$false_positive_rate');

问题是,当我描述n 时,我得到:n: count: chararray。可以预见的是,BuildBloom UDF 调用失败了,因为它得到了一个元组作为输入,它期望一个简单的chararray。我应该如何只提取字符数组(即从COUNT 转换为chararray 的整数返回)并将其分配给n 以用于对BuildBloom(...) 的调用?

编辑:这是我尝试将N::count 传递到BuildBloom(...) UDF 时产生的错误。 describe N 产生:N count: chararray。违规行(第 40 行)为:define bb BuildBloom('jenkins', N::count, '$fpr');

ERROR 1200: <file buildBloomFilter.pig, line 40, column 32>  mismatched input 'N::count' expecting set null

org.apache.pig.impl.logicalLayer.FrontendException: ERROR 1000: Error during parsing. <file buildBloomFilter.pig, line 40, column 32>  mismatched input 'N::count' expecting set null
    at org.apache.pig.PigServer$Graph.parseQuery(PigServer.java:1607)
    at org.apache.pig.PigServer$Graph.registerQuery(PigServer.java:1546)
    at org.apache.pig.PigServer.registerQuery(PigServer.java:516)
    at org.apache.pig.tools.grunt.GruntParser.processPig(GruntParser.java:991)
    at org.apache.pig.tools.pigscript.parser.PigScriptParser.parse(PigScriptParser.java:412)
    at org.apache.pig.tools.grunt.GruntParser.parseStopOnError(GruntParser.java:194)
    at org.apache.pig.tools.grunt.GruntParser.parseStopOnError(GruntParser.java:170)
    at org.apache.pig.tools.grunt.Grunt.exec(Grunt.java:84)
    at org.apache.pig.Main.run(Main.java:604)
    at org.apache.pig.Main.main(Main.java:157)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:197)
Caused by: Failed to parse: <file buildBloomFilter.pig, line 40, column 32>  mismatched input 'N::count' expecting set null
    at org.apache.pig.parser.QueryParserDriver.parse(QueryParserDriver.java:235)
    at org.apache.pig.parser.QueryParserDriver.parse(QueryParserDriver.java:177)
    at org.apache.pig.PigServer$Graph.parseQuery(PigServer.java:1599)
    ... 14 more

【问题讨论】:

【参考方案1】:

如果您使用的是 grunt shell,那么执行此操作的明显方法是调用 DUMP n;,等待作业完成运行,然后将值复制到您的 define bloom... 调用中。

这不是一个非常令人满意的答案,我猜。您很可能希望在脚本中运行它。这是一个非常hacky的方法。您需要 3 个文件:

    'n_start.txt' 包含:

    n='
    

    'n_end.txt' 包含单个字符:

    '
    

    'bloom_build.pig' 包含:

    define bb BuildBloom('jenkins', '$n', '0.0001');
    

一旦你有了这些,你就可以运行这个脚本了:

records = LOAD '$input' using PigStorage();
records = FOREACH records GENERATE 
    (long)     $0 AS value_fld:long, 
    (chararray)$1 AS filter_fld:chararray;
records_fltr = FILTER records by (filter_fld=='$filter_value') 
    AND (value_fld is not null);
records_grp = GROUP records_fltr all;
records_count = FOREACH records_grp GENERATE 
    (chararray) COUNT(records_fltr.value_fld) AS count:chararray;
n = FOREACH records_count GENERATE flatten(count);

--the new part
STORE records_count INTO 'n' USING PigStorgae(',');
--this will copy what you just stored into a local directory
fs -copyToLocal n n
--this will cat the two static files we created prior to running pig
--with the count we just generated.  it will pass it through tr which will
--strip out the newlines and then store it into a file called 'n.txt' which we
--will use as a parameter file
sh cat -s nstart.txt n/part-r-00000 nend.txt| tr -d '\n' > n.txt
--RUN makes pig call one script within another.  Be forewarned that if pig returns 
--a message with an error on a certain line, it is the line number of the expanded script
RUN -param_file n.txt bloom_bulid.pig;

在此之后,您可以像之前打算的那样致电bb。它很丑陋,可能更精通 unix 的人可以摆脱 n_start.txt 和 n_end.txt 文件。

另一个更简洁但涉及更多的选项是编写一个新的 UDF,它(如 BuildBloom)扩展了 BuildBloomBase.java,但有一个空的构造函数,并且可以处理 exec() 方法中的所有内容。

【讨论】:

在仔细查看 BuildBloomBase UDF 之后,我认为这里的真正问题是 BuildBloom UDF 依赖于不动态确定大小(需要猪将所有数据推送到单个node) 以便它可以设置大小相等的过滤器,在键的子集上训练它们,然后对生成的org.apache.hadoop.util.bloom.BloomFilter 对象使用“or()”方法。感谢您提供解决方法。【参考方案2】:

在 BuildBloom udf 中,您发送“n”作为元组参数。可能“n::columnname”会起作用。试试这个。

【讨论】:

感谢您的建议。请参阅我对原始帖子的编辑,我尝试了您的解决方案并得到了我一段时间以来看到的相同错误。 您的关系名称是“n”而不是“N”。需要从 u 那里知道的一件事是,您为作为元组的分组记录计算 count(),然后将其传递给您的 udf,它期望一个值而不是元组。我认为您需要属于所有组的元组中的所有值,因为将元组作为参数并从中获取每个值然后执行您的操作。即使您不希望所有值只从该元组中获取一个值并执行您的处理。 当我测试你的建议时,它是“N”。我已经多次编辑代码。如果这是我的 UDF,我会按照你的建议去做。 BuildBloom 是一个内置的 UDF (org.apache.pig.builtin.BuildBloom)。它实现了代数接口,它是从脚本中调用的构造函数,而不是exec 方法。

以上是关于如何从复杂的猪数据类型中提取简单的猪数据类型的主要内容,如果未能解决你的问题,请参考以下文章

EMR 上的猪:如何在 EXTRACT 函数的正则表达式参数中包含分号

无法从 S3 存储桶(镶木地板文件)将数据加载到 EMR 上的猪中

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

使用大象鸟罐子的猪 JsonLoader() 处理 twitter 的复杂 json 对象时出错

PIG 加载 CSV - 地图类型错误

Group by 上的猪优化