因特网公司对海量数据的按需分析处理目前基本采用Map/Reduce编程模型。尽管如此,Map/Reduce也存在一些限制,它的单输入,两阶段数据流编程模式过于苛刻,对于超出该限制之外的数据分析任务,需要进行一些额外的数据转换。另外,它没有通用操作集,即使是对最通用的操作,如:projection和filtering。这些限制导致Map/Reduce代码重用性和可维护性不高,任务的分析语义不够清晰,将对系统性能优化造成影响。
基于以上问题,Yahoo!开发了一种新的基于数据流的大规模数据分析处理语言-Pig Latin,该语言借鉴了SQL和Map/Reduce两者的优点,既具有类似SQL的灵活可变式性,又有过程式语言的数据流特点。
首先以一个例子来直观感受Pig Latin的特点。安装好Pig之后,tutorial/data/下包含文件excite-small.log。其中每一行记录代表某一用户在某个时刻的一次查询。假设我们将该文件load进一个表query:(userID,time,queryitem)。现在需要查询每个用户的查询次数。如果使用SQL语句,查询语句如下:
- SELECT userID, COUNT(*) FROM query GROUP BY userID;
与上述SQL等价的Pig Latin程序如下:
- log = LOAD ‘tutorial/data/excite-small.log’ AS (userID:chararray, time:long, queryitem:chararray);
- grpd = GROUP log BY userID;
- cntd = FOREACH grpd GENERATE group, COUNT(log);
- STORE cntd INTO ‘output’;
Pig Latin语言在编程风格上与SQL有明显差别,前者凸显了程序的执行数据流,后者只关注最终结果。SQL更适合于编程经验不丰富的程序员,适合小规模数据集;Pig Latin更适合有经验的程序员和大规模数据集。另外,尽管Pig Latin程序提供了显示的操作序列,但实际的执行计划不一定按照该顺序执行,编译器会根据一定的规则对执行顺序进行一定的优化。Pig Latin语言的学习可以参考官方文档。
Pig的安装部署
Pig的运行模式有两种。一种是Local mode,也就是本地模式,这种模式下Pig运行在一个JVM里,访问的是本地的文件系统,只适合于小规模数据集,一般是用来体验Pig。而且,它并没有用到Hadoop的Local runner,Pig把查询转换为物理的Plan,然后自己去执行。在终端下输入pig -x local;就可以进入Local模式了。
还有一种就是Hadoop模式了,这种模式下,Pig才真正的把查询转换为相应的MapReduce Jobs,并提交到Hadoop集群去运行,集群可以是真实的分布式也可以是伪分布式。要想Pig能认识Hadoop,你要告诉它Hadoop的版本以及一些关键daemon的信息(也就是Namenode和Jobtracker的Address和Port)。
我们只是想让Pig在本地模式下运行,所以安装部署很简单:
- 去官网下载Pig,我下载的是最新版本pig-0.10.0.tar.gz。
- 将Pig的bin目录添加环境变量:编辑/etc/profile,添加
- export PIG_HOME=/home/wangxing/Development/pig-0.10.0
- export PATH=$PATH:$PIG_HOME/bin
Pig实例:相似专利发现
(1) 下载专利引用数据集Cite75_99.zip。文本中的每一行代表某一专利引用了其他一个专利一次。某一专利可以引用多篇其他专利。例如下例中,在专利3858241中引用了956203,1324234,3398406三个专利。另外,由于本人的电脑磁盘容量限制,试验中只取了Cite75_99.zip前100万条记录。
3858241,956203 3858241,1324234 3858241,3398406 3858242,1515701
(2) 专利的相似度量:如果两篇专利A,B在其他的专利中超过N次被一起被引用,我们认为专利A,B是相似的。这里N是我们指定的一个阀值。
(3)对于涉及成对计算的应用(例如这里的计算每对专利联合引用的次数),通常很容易想到采用一对嵌套的循环来枚举出所有的专利对,并对每一对进行计数。这样,便产生二阶复杂度。然而我们发现大部分的专利对是不会被同时引用的,让相似度计算仅作用于已知被一起引用的专利对。相似专利发现可以做以下操作:
- 获得每一个专利所引用专利的列表
- 生成这个列表上所有的专利对,并记录
- 统计每个专利对的个数
(4)编写Pig Latin脚本simiralitycite.pig
cite =
LOAD
‘cite75_99_1000000.txt’ USING PigStorage(‘,’)
AS
(citing:
int
, cited:
int
);
cite_grpd =
GROUP
cite
BY
citing;
cite_grpd_dbl = FOREACH cite_grpd GENERATE
group
, cite.cited
AS
cited1,cite.cited
AS
cited2;
cocite = FOREACH cite_grpd_dbl GENERATE FLATTEN(cited1), FLATTEN(cited2);
cocite_fltrd = FILTER cocite
BY
cited1::cited != cited2::cited;
cocite_grpd =
GROUP
cocite_fltrd
BY
*;
cocite_flat = FOREACH cocite_grpd GENERATE FLATTEN(
group
),
COUNT
(cocite_fltrd)
as
cnt;
cocite_final = FILTER cocite_flat
BY
cnt > 1
STORE cocite_final
INTO
‘
output
’;
- 关系cite_grpd通过group让每个专利包含一个包,这个包中是这个专利和引用的专利的组合列表。从这个关系(如图示)我们可以看到专利3601095和3685034在专利3858554中被一起引用。
- 关系cite_grpd_dbl创建了重复的列cited2。cited1和cited2的值是相同的,该重复支持交叉乘操作。cocite对每一行平坦化后再用交叉乘生成专利引用对。
- 关系cocite_fltrd过滤掉自己引用自己的情况,这个是在交叉乘时引进的错误。
- 关系cocite_grpd、cocite_flat对每个专利对计数。
- 关系cocite_final输出相似专利对,这里我们认为一起被引用10次以上,就表示两专利相似。
下面是调试中,ILLUSTRATE cocite_flat的输出信息。ILLUSTRATE命令自己运行数据集的一个样本,并查看每个关系的生成过程。
上部分文章转自: http://www.datalab.sinaapp.com/?p=128
而对于 hadoop in action 书籍中的代码如下:
cite = load '/data/cite/cite75_99.txt' using PigStorage(',') as (citing:int, cited:int);
cite_grpd = group cite by citing;
cite_grpd_dbl = foreach cite_grpd generate group, cite.cited as cited1, cite.cited as cited2;
cocite = FOREACH cite_grpd_dbl GENERATE FLATTEN(cited1) , FLATTEN(cited2) ;
cocite_fltrd = filter cocite by cited1 != cited2;
cocite_grpd = group cocite_fltrd by *;
cocite_cnt = foreach cocite_grpd generate group, COUNT(cocite_fltrd) as cnt;
cocite_flat = foreach cocite_cnt generate flatten(group), cnt;
cocite_cnt_grpd = group cocite_flat by cited1;
cocite_bag = foreach cocite_cnt_grpd generate group, cocite_flat.(cited2, cnt);
cocite_final = FOREACH cocite_cnt_grpd {
similar = FILTER cocite_flat BY cnt > 10;
GENERATE group, similar;
}
STORE cocite_final INTO 'output';
但是运行该部分代码时,会有错误:
ERROR 1025: 4 <line 5, column 32> Invalid field projection. Projected field [cited1] does not exist in schema: cited1::cited:int,cited2::cited:int.
将其中一行代码修改如下:
cocite = FOREACH cite_grpd_dbl GENERATE FLATTEN(cited1) as cited1, FLATTEN(cited2) as cited2;