(31)使用三目运算符“ ? : ”有时候必须加括号
假设有以下数据文件:
1
2
3
4
|
[root@localhost ~]
# cat a.txt
5 8 9
6 0
4 3 1
|
其中,第二行的第二列数据是有缺失的,因此,加载数据之后,它会成为null。顺便废话一句,在处理海量数据时,数据有缺失是经常遇到的现象。
现在,我们如果要把所有缺失的数据填为 -1, 可以使用三目运算符来操作:
1
2
3
|
A =
LOAD
'a.txt'
AS
(col1:
int
, col2:
int
, col3:
int
);
B = FOREACH A GENERATE col1, ((col2
is
null
)? -1 : col2), col3;
DUMP B;
|
输出结果为:
1
2
3
|
(5,8,9)
(6,-1,0)
(4,3,1)
|
((col2 is null)? -1 : col2) 的含义不用解释你也知道,就是当col2为null的时候将其置为-1,否则就保持原来的值,但是注意,它最外面是用括号括起来的,如果去掉括号,写成 (col2 is null)? -1 : col2,那么就会有语法错误:
ERROR org.apache.pig.tools.grunt.Grunt - ERROR 1000: Error during parsing. Encountered " "is" "is "" at line 1, column 36.
Was expecting one of (后面省略)
错误提示有点不直观。所以,有时候使用三目运算符是必须要使用括号的。
(32)如何补上缺失的数据
通过前面的文章,我们已经知道了如何按自己的需求补上缺失的数据,那么这里还有一个例子,可以让你多了解一些特殊的情况。
数据文件如下:
1
2
3
4
5
6
|
[root@localhost ~]
# cat 1.txt
1 (4,9)
5
8 (3,0)
5 (9,2)
6
|
这些数据的布局比较怪,我们要把它加载成什么样的schema呢?答:第一列为一个int,第二列为一个tuple,此tuple又含两个int。加载成这样的模式不是为了制造复杂度,而是为了说明后面的问题而设计的。
同时,我们也注意到,第二列数据是有缺失的。
问题:怎样求在第一列数据相同的情况下,第二列数据中的第一个整数的和分别为多少?
例如,第一列为1的数据只有一行(即第一行),因此,第二列的第一个整数的和就是4。
但是对最后一行,也就是第一列为6时,由于其第二列数据缺失,我们希望它输出的结果是0。
先来看看Pig代码:
1
2
3
4
5
|
A =
LOAD
'1.txt'
AS
(a:
int
, b:tuple(x:
int
, y:
int
));
B = FOREACH A GENERATE a, FLATTEN(b);
C =
GROUP
B
BY
a;
D = FOREACH C GENERATE
group
,
SUM
(B.x);
DUMP D;
|
结果为:
1
2
3
4
|
(1,4)
(5,9)
(6,)
(8,3)
|
我们注意到,(5,9) 这一行是由数据文件 1.txt 的第 2、4行计算得到的,其中,第2行数据有缺失,但这并不影响求和计算,因为另一行数据没有缺失。你可以这样想:一个包(bag)中有多个数,当其中一个为 null,而其他不为null时,把它们相加会自动忽略null。
然而,第三行 (6,) 是不是太刺眼了?没错,因为数据文件 1.txt 的最后一行缺失了第二列,所以,在 SUM(B.x) 中的 B.x 为null就会导致计算结果为null,从而什么也输出不了。
这就与我们期望的输出有点不同了。我们希望这种缺失的数据不要空着,而是输出0。该怎么做呢?
文章来源:http://www.codelast.com/
想法1:
1
|
D = FOREACH C GENERATE
group
, ((IsEmpty(B.x)) ? 0 :
SUM
(B.x));
|
输出结果为:
1
2
3
4
|
(1,4)
(5,9)
(6,)
(8,3)
|
可见行不通。从这个结果我们知道,IsEmpty(B.x) 为false,即B.x不是empty的,所以不能这样做。
想法2:
1
|
D = FOREACH C GENERATE
group
, ((B.x
is
null
) ? 0 :
SUM
(B.x));
|
输出结果还是与上面一样!仍然行不通。这更奇怪了:B.x既非empty,也非null,那么它是什么情况?按照我的理解,当group为6时,它 应该是一个非空的包(bag),里面有一个null的东西,所以,这个包不是empty的,它也非null。我不知道这样理解是否正确,但是它看上去就像 是这样的。
想法3:
1
2
3
|
D = FOREACH C GENERATE
group
,
SUM
(B.x)
AS
s;
E = FOREACH D GENERATE
group
, ((s
is
null
) ? -1 : s);
DUMP E;
|
输出结果为:
1
2
3
4
|
(1,4)
(5,9)
(6,-1)
(8,3)
|
可见达到了我们想要的结果。这与本文前面部分的做法是一致的,即:先得到含null的结果,再把这个结果中的null替换为指定的值。
有人会问:就没有办法在生成数据集D的时候,就直接通过判断语句来实现这个效果吗?据我目前所知是不行的,如果哪位读者知道,不妨告知。
(33)DISTINCT操作用于去重,正因为它要把数据集合到一起,才知道哪些数据是重复的,因此,它会产生reduce过程。同时,在map阶段,它也会利用combiner来先去除一部分重复数据以加快处理速度。
(34)如何将Pig job的优先级设为HIGH
嫌Pig job运行太慢?只需在Pig脚本的开头加上一句:
1
|
set job.priority HIGH;
|
即可将Pig job的优先级设为高了。
(35)“Scalars can be only used with projections”错误的原因
这个错误提示比较不直观,光看这句话是不容易发现错误所在的,但是,只要你一Google,可能就找到原因了,例如这个链接里的反馈。
在这里,我也想用一个简单的例子给大家用演示一下产生这个错误的原因之一。
假设有如下数据文件:
1
2
3
4
5
6
7
8
9
|
[root@localhost ~]$
cat
1.txt
a 1
b 8
c 3
c 3
d 6
d 3
c 5
e 7
|
现在要统计:在第1列的每一种组合下,第二列为3和6的数据分别有多少条?
例如,当第1列为 c 时,第二列为3的数据有2条,为6的数据有0条;当第1列为d时,第二列为3的数据有1条,为6的数据有1条。其他的依此类推。
Pig代码如下:
1
2
3
4
5
6
7
8
|
A =
LOAD
'1.txt'
AS
(col1:chararray, col2:
int
);
B =
GROUP
A
BY
col1;
C = FOREACH B {
D = FILTER A
BY
col2 == 3;
E = FILTER A
BY
col2 == 6;
GENERATE
group
,
COUNT
(D),
COUNT
(E);
};
DUMP C;
|
输出结果为:
1
2
3
4
5
|
(a,0,0)
(b,0,0)
(c,2,0)
(d,1,1)
(e,0,0)
|
可见结果是正确的。
文章来源:http://www.codelast.com/
那么,如果我在上面的代码中,把“D = FILTER A BY col2 == 3”不小心写成了“D = FILTER B BY col2 == 3”,就肯定会得到“Scalars can be only used with projections”的错误提示。
说白了,还是要时刻注意你每一步生成的数据的结构,眼睛睁大,千万不要用错了relation。
(36)什么是嵌套的FOREACH/内部的FOREACH
嵌套的(nested)FOREACH和内部的(inner)FOREACH是一个意思,正如你在本文第(35)条中所见,一个FOREACH可以对每一条记录施以多种不同的关系操作,然后再GENERATE得到想要的结果,这就是嵌套的/内部的FOREACH。
(37)错误“Could not infer the matching function for org.apache.pig.builtin.CONCAT”的原因之一
如果你遇到这个错误,那么有可能是你在多级CONCAT嵌套的时候,没有写对语句,例如“CONCAT(CONCAT(CONCAT(a, b), c), d)”这样的嵌套,由于括号众多,所以写错了是一点也不奇怪的。我遇这个错误的时候,是由于CONCAT太多,自己多写了一个都没有发现。希望我的提醒能 给你一点解决问题的提示。
(38)用Pig加载HBase数据时遇到的错误“ERROR 2999: Unexpected internal error. could not instantiate 'com.twitter.elephantbird.pig.load.HBaseLoader' with arguments XXX”的原因之一
请看这个链接:《Apache Pig中文教程(进阶)》
(39)错误“ERROR 1039: In alias XX, incompatible types in EqualTo Operator left hand side:XXX right hand side:XXX”的原因
其实这个错误提示太明显了,就是类型不匹配造成的。上面的XXX可以指代不同的类型。
这说明,前面可能有一个类型为long的字段,后面你却把它当chararray来用了,例如:
1
2
3
4
5
|
A =
LOAD
'1.txt'
AS
(col1:
int
, col2: long);
B = FILTER A
BY
col2 ==
'123456789'
;
C =
GROUP
B
ALL
;
D = FOREACH C GENERATE
COUNT
(B);
DUMP D;
|
就会出错:
ERROR 1039: In alias B, incompatible types in EqualTo Operator left hand side:long right hand side:chararray
只要把col2强制类型转换一下(或者一开始就将其类型指定为chararray)就可以解决问题。
文章来源:http://www.codelast.com/
不仅在进行数据比较中,在JOIN时也经常出现数据类型不匹配导致的错误问题。我在实际工作中发现,有的同学写了比较长的Pig代码,出现了这样的错误却 不会仔细去看错误提示,而是绞尽脑汁地逐句去检查语法(语法是没有错的),结果费了很大的劲才知道是类型问题,得不偿失,还不如仔细看错误提示想想为什 么。
(40)在grunt交互模式下,如何在编辑Pig代码的时候跳到行首和行末/行尾
在grunt模式下,如果你写了一句超长的Pig代码,那么,你想通过HOME/END键跳到行首和行末是做不到的。
按HOME时,Pig会在你的光标处插入一个“1~”:
1
|
A =
LOAD
'1.txt'
AS
(col: int1~);
|
按END时,Pig会在你的光标处插入一个“4~”:
1
|
A =
LOAD
'1.txt'
AS
(col: int4~);
|
正确的做法是:按Ctrl+A 和 Ctrl+E 代替 HOME 和 END,就可以跳到行首和行末了。