Apache Pig的一些基础概念及用法总结(5)

(41)不能对同一个关系(relation)进行JOIN
假设有如下文件:

1
2
3
4
5
[root@localhost ~] # cat 1.txt
1 a
2 e
3 v
4 n

我想对第一列这样JOIN:

1
2
A = LOAD '1.txt' AS (col1: int , col2: chararray);
B = JOIN A BY col1, A BY col1;

那么当你试图 DUMP B 的时候,会报如下的错:

ERROR org.apache.pig.tools.grunt.Grunt - ERROR 1108: Duplicate schema alias: A::col1 in "B"

这是因为Pig会弄不清JOIN之后的字段名——两个字段均为A::col1,使得一个关系(relation)中出现了重复的名字,这是不允许的。
文章来源:http://www.codelast.com/
要解决这个问题,只需将数据LOAD两次,并且给它们起不同的名字就可以了:

01
02
03
04
05
06
07
08
09
10
grunt> A = LOAD '1.txt' AS (col1: int , col2: chararray);
grunt> B = LOAD '1.txt' AS (col1: int , col2: chararray);
grunt> C = JOIN A BY col1, B BY col1;                  
grunt> DESCRIBE C;
C: {A::col1: int ,A::col2: chararray,B::col1: int ,B::col2: chararray}
grunt> DUMP C;
(1,a,1,a)
(2,e,2,e)
(3,v,3,v)
(4,n,4,n)

从上面的 C 的schema,你可以看出来,如果对同一个关系A的第一列进行JOIN,会导致schema中出现相同的字段名,所以当然会出错。

(42)外部的JOIN(outer JOIN)
初次使用JOIN时,一般人使用的都是所谓的“内部的JOIN”(inner JOIN),也即类似于 C = JOIN A BY col1, B BY col2 这样的JOIN。Pig也支持“外部的JOIN”(outer JOIN),下面就举一个例子。
假设有文件:

1
2
3
4
5
[root@localhost ~] # cat 1.txt
1 a
2 e
3 v
4 n

以及:

1
2
3
4
5
[root@localhost ~] # cat 2.txt
9 a
2 e
3 v
0 n

现在来对这两个文件的第一列作一个outer JOIN:

01
02
03
04
05
06
07
08
09
10
grunt> A = LOAD '1.txt' AS (col1: int , col2: chararray);
grunt> B = LOAD '2.txt' AS (col1: int , col2: chararray);
grunt> C = JOIN A BY col1 LEFT OUTER , B BY col1;
grunt> DESCRIBE C;
C: {A::col1: int ,A::col2: chararray,B::col1: int ,B::col2: chararray}
grunt> DUMP C;
(1,a,,)
(2,e,2,e)
(3,v,3,v)
(4,n,,)

在outer JOIN中,“OUTER”关键字是可以省略的。从上面的结果,我们注意到:如果换成一个inner JOIN,则两个输入文件的第一、第四行都不会出现在结果中(因为它们的第一列不相同),而在LEFT OUTER JOIN中,文件1.txt的第一、四行却被输出了,所以这就是LEFT OUTER JOIN的特点:对左边的记录来说,即使它与右边的记录不匹配,它也会被包含在输出数据中
文章来源:http://www.codelast.com/
同理可知RIGHT OUTER JOIN的功能——把上面的 LEFT 换成 RIGHT,结果如下:

1
2
3
4
(,,0,n)
(2,e,2,e)
(3,v,3,v)
(,,9,a)

可见,与左边的记录不匹配的右边的记录被保存了下来,而左边的记录没有保存下来(两个逗号表明其为空),这就是RIGHT OUTER JOIN的效果,与我们想像的一样。
有人会问,OUTER JOIN在实际中可以用来做什么?举一个例子:可以用来求“不在某数据集中的那些数据(即:不重合的数据)”。还是以上面的两个数据文件为例,现在我要求出 1.txt 中,第一列不在 2.txt 中的第一列的那些记录,肉眼一看就知道,1和4这两个数字在 2.txt 的第一列里没有出现,而2和3出现了,因此,我们要找的记录就是:

1
2
1 a
4 n

要实现这个效果,Pig代码及结果为:

01
02
03
04
05
06
07
08
09
10
grunt> A = LOAD '1.txt' AS (col1: int , col2: chararray);
grunt> B = LOAD '2.txt' AS (col1: int , col2: chararray);
grunt> C = JOIN A BY col1 LEFT OUTER , B BY col1;       
grunt> DESCRIBE C;                
C: {A::col1: int ,A::col2: chararray,B::col1: int ,B::col2: chararray}
grunt> D = FILTER C BY (B::col1 is null );
grunt> E = FOREACH D GENERATE A::col1 AS col1, A::col2 AS col2;
grunt> DUMP E;
(1,a)
(4,n)

可见,我们确实找出了“不重合的记录”。在作海量数据分析时,这种功能是极为有用的。
最后来一个总结:
假设有两个数据集(在1.txt和2.txt中),分别都只有1列,则如下代码:

1
2
3
4
5
6
A = LOAD '1.txt' AS (col1: chararray);
B = LOAD '2.txt' AS (col1: chararray); 
C = JOIN A BY col1 LEFT OUTER , B BY col1;
D = FILTER C BY (B::col1 is null );
E = FOREACH D GENERATE A::col1 AS col1;                
DUMP E;

计算结果为:在A中,但不在B中的记录。

(43)JOIN的优化
请看这个链接:《Apache Pig中文教程(进阶)

(44)GROUP时按所有字段分组可以用GROUP ALL吗
假设你有如下数据文件:

1
2
3
4
5
6
7
8
[root@localhost ~] # cat 3.txt
1 9
2 2
3 3
4 0
1 9
1 9
4 0

现在要找出第1、2列的组合中,每一种的个数分别为多少,例如,(1,9)组合有3个,(4,0)组合有两个,依此类推。
显而易见,我们只需要用GROUP就可以轻易完成这个任务。于是写出如下代码:

1
2
3
4
A = LOAD '3.txt' AS (col1: int , col2: int );
B = GROUP A ALL ;
C = FOREACH B GENERATE group , COUNT (A);
DUMP C;

可惜,结果不是我们想要的:

1
(all,7)

为什么呢?我们的本意是按所有列来GROUP,于是使用了GROUP ALL,但是这实际上变成了统计行数,下面的代码就是一段标准的统计数据行数的代码:

1
2
3
4
A = LOAD '3.txt' AS (col1: int , col2: int );
B = GROUP A ALL ;
C = FOREACH B GENERATE COUNT (A);
DUMP C;

因此,上面的 C = FOREACH B GENERATE group, COUNT(A) 也无非就是多打印了一个group的名字(all)而已——group的名字被设置为“all”,这是Pig帮你做的。
文章来源:http://www.codelast.com/
正确的做法很简单,只需要按所有字段GROUP,就可以了:

1
2
3
4
A = LOAD '3.txt' AS (col1: int , col2: int );
B = GROUP A BY (col1, col2);
C = FOREACH B GENERATE group , COUNT (A);
DUMP C;

结果如下:

1
2
3
4
((1,9),3)
((2,2),1)
((3,3),1)
((4,0),2)

这与我们前面分析的正确结果是一样的。

(45)在Pig中使用中文字符串
有读者来信问我,如何在Pig中使用中文作为FILTER的条件?我做了如下测试,结论是可以使用中文。
数据文件 data.txt 内容为(每一列之间以TAB为分隔符):

1
2
3
4
5
1 北京市 a
2 上海市 b
3 北京市 c
4 北京市 f
5 天津市 e

Pig脚本文件 test.pig 内容为:

1
2
3
A = LOAD 'data.txt' AS (col1: int , col2: chararray, col3: chararray);
B = FILTER A BY (col2 == '北京市' );
DUMP B;

首先,我这两个文件的编码都是UTF-8(无BOM),在Linux命令行下,我直接以本地模式执行Pig脚本 test.pig:

1
pig -x local test.pig

得到的输出结果为:

1
2
3
(1,北京市,a)
(3,北京市,c)
(4,北京市,f)

可见结果是正确的。
文章来源:http://www.codelast.com/
但是,如果我在grunt交互模式下,把 test.pig 的内容粘贴进去执行,是得不到任何输出结果的:

1
2
3
grunt> A = LOAD 'data.txt' AS (col1: int , col2: chararray, col3: chararray);
grunt> B = FILTER A BY (col2 == '北京市' );
grunt> DUMP B;

具体原因我不清楚,但是至少有一点是肯定的:可以使用中文作为FILTER的条件,只要不在交互模式下执行你的Pig脚本即可。

(46)如何统计 tuple 中的 field 数,bag 中的 tuple 数,map 中的 key/value 组数
一句话:用Pig内建的 SIZE 函数:

Computes the number of elements based on any Pig data type.

具体可看这个链接。

(47)一个字符串为null,与它为空不一定等价
在某些情况下,要获取“不为空”的字符串,仅仅用 is not null 来判断是不够的,还应该加上 SIZE(field_name) > 0 的条件:

1
B = FILTER A BY (field_name is not null AND ( SIZE (field_name) > 0L));

注意,这只是在某些情况下需要这样做,在一般情况下,仅用 is not null 来过滤就可以了。我并没有总结出特殊情况是哪些情况,我只能说我我不是第一次遇到此情况了,所以才有了这一个结论。
注意上面使用的是“0L”,因为SIZE()返回的是long类型,如果不加L,在Pig0.10下会出现一个警告,例如:

[main] WARN  org.apache.pig.PigServer - Encountered Warning IMPLICIT_CAST_TO_LONG 1 time(s)

(48)Pig中的各operator(操作符),哪些会触发reduce过程
GROUP:由于GROUP操作会将所有具有相同key的记录收集到一起,所以数据如果正在map中处理的话,就会触发shuffle→reduce的过程。
ORDER:由于需要将所有相等的记录收集到一起(才能 排序),所以ORDER会触发reduce过程。同时,除了你写的那个Pig job之外,Pig还会添加一个额外的M-R job到你的数据流程中,因为Pig需要对你的数据集做采样,以确定数据的分布情况,从而解决数据分布严重不均的情况下job效率过于低下的问题。
DISTINCT:由于需要将记录收集到一起,才能确定它们是不是重复的,因此DISTINCT会触发reduce过程。当然,DISTINCT也会利用combiner在map阶段就把重复的记录移除。
JOIN:JOIN用于求重合,由于求重合的时候,需要将具有相同key的记录收集到一起,因此,JOIN会触发reduce过程。
LIMIT:由于需要将记录收集到一起,才能统计出它返回的条数,因此,LIMIT会触发reduce过程。
COGROUP:与GROUP类似(参看本文前面的部分),因此它会触发reduce过程。
CROSS:计算两个或多个关系的叉积。

(49)如何统计一个字符串中包含的指定字符数
这可以不算是个Pig的问题了,你可以把它认为是一个shell的问题。从本文前面部分我们已经知道,Pig中可以用 STREAM ... THROUGH 来调用shell进行辅助数据处理,所以在这我们也能这样干。
假设有文本文件:

1
2
3
4
[root@localhost ~]$ cat 1.txt
123 abcdef:243789174
456 DFJKSDFJ:3646:555558888
789 yKDSF:00000%0999:2343324:11111:33333

现在要统计:每一行中,第二列里所包含的冒号(“:”)分别为多少?代码如下:

1
2
3
A = LOAD '1.txt' AS (col1: chararray, col2: chararray);
B = STREAM A THROUGH `awk -F ":" '{print NF-1}' ` AS (colon_count: int );
DUMP B;

结果为:

1
2
3
(1)
(2)
(4)

文章来源:http://www.codelast.com/
(50)UDF是区分大小写的
因为UDF是由Java类来实现的,所以区分大小写,就这么简单。

(51)设置Pig job的job name
在Pig脚本开头加上一句:

1
set job.name 'My-Job-Name';

那么,执行该Pig脚本之后,在Hadoop的Job Tracker中看到的“Name”就是“My-Job-Name”了。
如果不设置,显示的name是类似于“
Job6245768625829738970.jar”这样的东西,job多的时候完全没有标识度,建议一定要设置一个特殊的job name。

(52)把纯文本转化为JSON
假设输入文件 a.txt 内容为:

1
2
1 2
9 8

则如下Pig代码将把它转化为JSON格式:

1
2
A = LOAD 'a.txt' AS (col1: chararray, col2: chararray);
B = STORE A INTO 'result' USING JsonStorage();

查看输出文件的内容是:

1
2
{"col1":"1","col2":"2"}
{"col1":"9","col2":"8"}

可见,你LOAD输入数据时定义的字段名,就是输出文件中的JSON字段名。


转载于:https://my.oschina.net/u/1170537/blog/384429

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值