您的位置:首页 > 运维架构 > Apache

  Apache Pig中文教程(进阶)go on

2015-03-09 00:00 141 查看
(3)重载(overloading)一个UDF
类似于C++的函数重载,pig中也可以重载UDF,例如一个函数ADD可以对两个int进行操作,也可以对两个double进行操作,那么我们可以为该函数实现getArgToFuncMapping方法,该函数返回一个List<FuncSpec>对象,这个对象中包含了参数的类型信息。具体怎么实现,可以看这个链接(搜索“OverloadingUDFs”定位到所需章节)。

(4)pig运行不起来,提示“org.apache.hadoop.ipc.Client-Retryingconnecttoserver:localhost/127.0.0.1:9000.Alreadytried1time(s)”错误的解决办法
发生这个错误时,请先检查Hadoop的各个进程是否都运行起来了,例如,在我的一次操作中,遇到这个错误时,我发现Hadoopnamenode进程没有启动起来:

1
ps
-ef|
grep
java|
grep
NameNode
应该有两个进程启动起来了:

org.apache.hadoop.hdfs.server.namenode.NameNode
org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode

如果没有,那么你要到Hadoop安装目录下的“logs”目录下,查看NameNode的日志记录文件(视用户不同,日志文件的名字也会有不同),例如,我的NameNone日志文件hadoop--namenode-root-XXX.log的末尾,显示出有如下错误:

ERRORorg.apache.hadoop.hdfs.server.namenode.NameNode:org.apache.hadoop.hdfs.server.common.InconsistentFSStateException:Directory/tmp/hadoop-root/dfs/nameisinaninconsistentstate:storagedirectorydoesnotexistorisnotaccessible.

文章来源:http://www.codelast.com/
我到它提示的地方一看,果然不存在最后一级目录(我是伪分布式运行的Hadoop,不要觉得奇怪),于是手工创建了这个目录,然后停掉Hadoop:

1
stop-all.sh
稍候一会儿再重新启动Hadoop:

1
start-all.sh
然后再去看一下NameNode的日志,又发现了新的错误信息:

ERRORorg.apache.hadoop.hdfs.server.namenode.NameNode:java.io.IOException:NameNodeisnotformatted.

这表明NameNode没有被格式化。于是将其格式化:

1
[root@localhostbin]
#hadoopnamenode-format
命令行问你是否要格式化的时候,选择YES即可。格式化完后会提示:

common.Storage:Storagedirectory/tmp/hadoop-root/dfs/namehasbeensuccessfullyformatted.

说明成功了。这个时候,再像前面一样重启Hadoop进程,再去看NameNode的日志文件的最后若干行,应该会发现前面的那些错误提示没了。这个时候,再检查Hadoop各进程是否都成功地启动了,如果是的话,那么这个时候你就可以在Hadoop的伪分布式模式下启动pig:

1
[root@localhosthome]
#pig
而不用以本地模式来运行pig了(pig-xlocal)。
总之,配置一个伪分布式的Hadoop来调试pig在某些情况下是很有用的,但是比较麻烦,因为还牵涉到Hadoop的正确配置,但是最好搞定它,以后大有用处啊。

(5)用Pig加载HBase数据时遇到的错误“ERROR2999:Unexpectedinternalerror.couldnotinstantiate'com.twitter.elephantbird.pig.load.HBaseLoader'withargumentsXXX”的原因之一
你也许早就知道了:Pig可以加载HBase数据,从而更方便地进行数据处理。但是在使用HBase的loader的时候,可能会遇到这样那样的问题,我这里就遇到了一例,给大家分析一下原因。
使用org.apache.pig.backend.hadoop.hbase.HBaseStorage()可以加载HBase数据,例如:

1
A=
LOAD
'hbase://table_name'
USINGorg.apache.pig.backend.hadoop.hbase.HBaseStorage(
'column_family_name:qualifier_name'
,
'-loadKeytrue-limit100'
)
AS
(col1:chararray,col2:chararray);
其中,table_name是你要加载数据的HBase表名,column_family_name:qualifier_name是表的columnfamily:qualifier(当然,可以有多个columnfamily:qualifier,以空格隔开即可),-loadKeytrue-limit100是加载数据时指定的参数,支持的参数如下:

-loadKey=(true|false)Loadtherowkeyasthefirstcolumn

-gt=minKeyVal

-lt=maxKeyVal

-gte=minKeyVal

-lte=maxKeyVal

-limit=numRowsPerRegionmaxnumberofrowstoretrieveperregion

-delim=chardelimitertousewhenparsingcolumnnames(defaultisspaceorcomma)

-ignoreWhitespace=(true|false)ignorespaceswhenparsingcolumnnames(defaulttrue)

-caching=numRowsnumberofrowstocache(fasterscans,morememory).

-noWAL=(true|false)Setsthewriteaheadtofalseforfasterloading.

Tobeusedwithextremecaution,sincethiscouldresultindataloss

(seehttp://hbase.apache.org/book.html#perf.hbase.client.putwal).
由这些参数的解释,可知我上面的-loadKeytrue使得加载出来的数据的第一列是HBase表的rowkey;-limit100使得从每一个region加载的最大数据行数为100(当你有N个region时,总共加载的数据是不是N*region总数条,我没有试验)。
org.apache.pig.backend.hadoop.hbase.HBaseStorage()包含在Pig的jar包中,所以你不需要REGISTER额外的jar包。
我遇到的问题是:在按上面的代码加载HBase数据之后,在grunt中一回车,马上报错:

ERROR2999:Unexpectedinternalerror.couldnotinstantiate'com.twitter.elephantbird.pig.load.HBaseLoader'withargumentsXXX
Detailsatlogfile:XXX

这个时候,你当然应该去查看logfile,以确定具体问题是什么。
logfile内容较多,在其尾部,有下面的内容:

Causedby:java.lang.NoSuchMethodError:org.apache.hadoop.hbase.HBaseConfiguration.create()Lorg/apache/hadoop/conf/Configuration;

atorg.apache.pig.backend.hadoop.hbase.HBaseStorage.<init>(HBaseStorage.java:185)

文章来源:http://www.codelast.com/
好吧,到了这里,只能去看看pig的源码了。打开HBaseStorage.java文件,找到提示的185行,看到如下代码:

1
m_conf=HBaseConfiguration.create();
可见它调用了HBase代码中的一个类HBaseConfiguration的create方法。按上面的提示,它是找不到这个方法,于是我们再看看使用的HBase的HBaseConfiguration.java里的代码,找遍全文,都找不到create方法!那么,我们再看看更新一点的版本的HBase的相同文件中是否有这个方法呢?下载0.90.4版本的HBase,果然在HBaseConfiguration.java中找到了create方法:

1

2

3

4

5

6

7

8
/**


*CreatesaConfigurationwithHBaseresources


*@returnaConfigurationwithHBaseresources


*/

public
static
Configurationcreate(){


Configurationconf=
new
Configuration();


return
addHbaseResources(conf);

}
所以,问题就在这里了:Pig的HBaseloader不能使用某些版本的HBase,升级HBase吧!
另外,就算HBase版本适用了,你也得让Pig知道HBase的参数配置(要不然怎么可以指定一个HBase表名就可以加载其数据了呢),具体你可以看这个链接的说明。

(6)JOIN的优化
如果你对N个关系(relation)的某些字段进行JOIN,也就是所谓的“多路的”(multi-way)JOIN——我不知道用中文这样描述是否正确——在这种情况下,请遵循这样的原则来写JOIN语句:
JOIN用到的key所对应的记录最多的那个关系(relation)应该被排在最后。例如:

1
D=
JOIN
A
BY
col1,B
BY
col1,C
BY
col1;
在这里,假设C这个relation就是上面所说的那种情况,所以把它排在最后。
文章来源:http://www.codelast.com/
为什么要遵循这样的原则?这是由Pig处理JOIN的方式来决定的。在JOIN的n个关系中,前面的n-1个关系的处理结果会被cache在内存中,然后才会轮到第n个关系,因此,把最占内存的放在最后,有时候是能起到优化作用的。

(7)错误“Backenderror:org.apache.pig.data.BinSedesTuplecannotbecasttoorg.apache.pig.data.DataBag”的原因
如果你正在使用Pig0.8,那么要注意了:出现这个错误,可能是Pig的bug导致的,详见这个链接。
说得简单点就是:此bug会导致无法解引用一个tuple中的bag。通常我们取一个tuple中的bag,是为了FLATTEN它,将记录展开,但是此bug使得你根本连tuple中的bag都输出不了。
此bug并不会影响你的Pig脚本语法解析,也就是说,你的Pig脚本只要写对了,就能运行起来,但是它执行到后面会报错。

(8)如何加载LZO压缩的纯文本数据
如果你的数据是纯文本经由LZO压缩而成,那么你可以用elephant-bird的com.twitter.elephantbird.pig.store.LzoPigStorage来加载它:

1
A=
LOAD
'/user/codelast/text-lzo-file'
USINGcom.twitter.elephantbird.pig.store.LzoPigStorage()
AS
(col1:chararray,col2:
int
);
注意,这里没有写REGISTERjar包的命令,你需要自己补上。

(9)如何用Pig设置map端的并行度(map数)
这个链接中的第(9)条,我们知道,无法通过PARALLEL来设置Pigjobmap端的并行度,但是,有没有什么办法可以间接实现这一点呢?
在Java编写的MapReduce程序中,你可以像这个链接中的第(25)点所说的一样,通过FileInputFormat.setMinInputSplitSize()来间接更改map的数量,其实它就与设置mapred.min.split.size参数值的效果是一样的。
在Pig中,我们是可以通过set命令来设置job参数的,所以,我们如果在Pig脚本的开头写上:

1
set
mapred.
min
.split.
size
2147483648;
将使得对map来说,小于2G的文件将被作为一个split输入,从而一个小于2G的文件将只有一个map。假设我们的Pigjob是一个纯map的job,那么,map数的减少将使得输出文件的数量减少,在某些情况下,这种功能还是很有用的。
注意:上面的命令中,set的参数的单位是字节,所以2G=2*1024*1024*1024=2147483648。

(10)Pig调用现存的静态Java方法
不是每个人都会开发UDF,或者每个人都愿意去写一个UDF来完成一件极其简单的操作的,例如,把一个编码过的URL解码,如果我只想临时用一下这个功能,那么我还要去写一个UDF,累不累啊?
我们知道,java.net.URLDecoder.decode这个静态方法已经实现了URL解码功能:

staticStringdecode(Strings,Stringenc)

使用指定的编码机制对application/x-www-form-urlencoded字符串解码

那么,如何在Pig中使用这个现成的静态方法呢?为了展示这个使用过程,我造了一个数据文件:

1

2

3
[root@localhost~]$
cat
a.txt

http:
//zh
.wikipedia.org
/zh/
%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E
就一行,这个URL解码之后应该是:http://zh.wikipedia.org/wiki/搜索引擎因为里面含中文,所以被编码了。
处理此文件的Pig脚本url.pig如下:

1

2

3

4
DEFINEDecodeURLInvokeForString(
'java.net.URLDecoder.decode'
,
'StringString'
);

A=
LOAD
'a.txt'
AS
(url:chararray);

B=FOREACHAGENERATEDecodeURL(url,
'UTF-8'
);

STOREB
INTO
'url'
;
文章来源:http://www.codelast.com/
用pig-xlocalurl.pig执行这个脚本,完成后我们查看输出目录下的part-m-00000文件内容,可见它确实被解码成了正确的字符串。
这样,我们就利用了现存的静态Java方法来偷了个懒,很方便。
需要注意的是:只能调用静态方法,并且此调用比同样的UDF实现速度要慢,这是因为调用器没有使用Accumulator或Algebraic接口。根据这位兄台的测试,百万条的记录规模下,调用Java静态方法比UDF大约要慢一倍。至于这样的cost能不能接受,就看你自己的判断了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  pig进阶