在这篇文章中,我们将介绍以下几点:
PIG 并不依赖安装路径,换句话说你可以将 PIG 安装在任意路径。但需要注意一点,正如 Apache 的项目是运行在 Linux/Unix 环境上,PIG 也是需要运行在装有 Linux\Unix 环境的主机上,在你正式安装PIG Latin之前,你需要确保你的设备上已经安装了Java,并正确配置了JAVA_HOME。你可以使用命令
java –version
以及
jps
检测你自己的系统是否已经安装了Java并且配置正确。在我们的示例中,我们使用了包含三个节点的集群,以下是集群各节点的信息。
主机名 | IP 地址 | 任务 |
ISCASTest 01 | 192.168.145.100 | NameNode, SecondaryNameNode, JobTracker |
ISCASTest 02 | 192.168.145.101 | TaskTracker, QuorumPeerMain, DataNode |
ISCASTest 03 | 192.168.145.102 | TaskTracker, QuorumPeerMain, DataNode |
我们计划将 PIG 安装在 ISCASTest 01 节点上,假如你自己的资源足够多的话,建议将它安装在与 hadoop 无关的节点上,并将该节点加入到 hadoop 集群的网络中。这样做的好处显而易见,因为 namenode 需要承担整个集群的管理,所以应该避免由于自己的误操作而导致整个集群崩溃。另外不建议放置于 DataNode 的原因也是显而易见,如果集群需要不停的运行 Map/Reduce 任务,那么DataNode 就会承担繁重的数据处理任务。
不过在我们的实验环境下,因为资源有限,所以我们将 PIG 安装到了 NameNode 上,也就是 ISCASTest 01 节点上。你需要先从 apache 的官网上下载 PIG 安装包,并且将它解压在合适的位置。
tar pig-0.12.1.tar.gz -C /home/hadoop/
安装好之后,需要配置JAVA环境,因为 PIG 依赖 JVM 环境。所以你可以通过修改 /etc/profile 或者 $PIG_HOME/bin/pig 达到这一目的。如果修改 /etc/profile 你需要在末尾增加一行:
export JAVA_HOME=/usr/java/jdk1.8.0_05/
并使用 source /etc/profile 使设置生效。或者,另一种方法是修改 bin/pig 文件。在这段代码前加入 JAVA_HOME。
# some Java parameters
JAVA_HOME=/usr/java/jdk1.8.0_05/ #添加内容
if [ "$JAVA_HOME" != "" ]; then
#echo "run java in $JAVA_HOME"
JAVA_HOME=$JAVA_HOME
fi
if [ "$JAVA_HOME" = "" ]; then
echo "Error: JAVA_HOME is not set."
exit 1
fi
JAVA=$JAVA_HOME/bin/java
JAVA_HEAP_MAX=-Xmx1000m
如果在本地运行PIG,可以使用如下命令启动伪分布式模式:
pig -x local
如果在集群上运行PIG,可以使用如下命令启动分布式模式:
pig -x mapreduce
当你启动了集群模式,很有可能会收到类似的错误消息:
which: no hadoop in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/java/jdk1.8.0_05//bin/:/usr/java/jdk1.8.0_05//jre//bin/:/home/hadoop/bin)
2014-05-30 14:21:33,863 [main] INFO org.apache.pig.Main - Apache Pig version 0.12.1 (r1585011) compiled Apr 05 2014, 01:41:34
2014-05-30 14:21:33,864 [main] INFO org.apache.pig.Main - Logging error messages to: /home/hadoop/pig-0.12.1/bin/pig_1401430893858.log
2014-05-30 14:21:33,897 [main] INFO org.apache.pig.impl.util.Utils - Default bootup file /home/hadoop/.pigbootup not found
2014-05-30 14:21:34,024 [main] ERROR org.apache.pig.Main - ERROR 4010: Cannot find hadoop configurations in classpath (neither hadoop-site.xml nor core-site.xml was found in the classpath). If you plan to use local mode, please put -x local option in command line
Details at logfile: /home/hadoop/pig-0.12.1/bin/pig_1401430893858.log
通常出现这样消息的原因,是因为PIG Latin没有找到Hadoop的位置。所以你需要在环境中增加Hadoop的目录
HADOOP_HOME=/home/hadoop/hadoop/
HADOOP_BIN=${HADOOP_HOME}/bin/
export PATH=${PATH}:${JAVA_BIN}:${JRE_BIN}:${HADOOP_BIN}
为了方便,你还可以把PIG Latin的目录也加入至PATH中
PIG_HOME=/home/hadoop/pig/
PIG_BIN=${PIG_HOME}/bin
export PATH=${PIG_BIN}
并使用source命令,更新环境,如你将这些配置写入在.bashrc中
source .bashrc
之后再次启动,就应该不会出现这样的报错了。当你启动 PIG 后,就会进入到 PIG 脚本模式,类似于使用 python 进入 python 脚本命令模式,而退出 PIG 脚本模式的方法是使用 quit 命令。不过为了确认 pig 是否运行在 MapReduce 模式下,可以使用命令确认集群的状况。
hadoop dfsadmin -report
如果没有意外,你应该能收到这样的信息:
Configured Capacity: 75117592576 (69.96 GB)
Present Capacity: 56736980992 (52.84 GB)
DFS Remaining: 55587463168 (51.77 GB)
DFS Used: 1149517824 (1.07 GB)
DFS Used%: 2.03%
Under replicated blocks: 20
Blocks with corrupt replicas: 0
Missing blocks: 0
-------------------------------------------------
Datanodes available: 2 (2 total, 0 dead)
Name: 192.168.145.102:50010
Decommission Status : Normal
Configured Capacity: 37558796288 (34.98 GB)
DFS Used: 574758912 (548.13 MB)
Non DFS Used: 9190391808 (8.56 GB)
DFS Remaining: 27793645568(25.88 GB)
DFS Used%: 1.53%
DFS Remaining%: 74%
Last contact: Wed Jun 04 16:39:49 CST 2014
Name: 192.168.145.101:50010
Decommission Status : Normal
Configured Capacity: 37558796288 (34.98 GB)
DFS Used: 574758912 (548.13 MB)
Non DFS Used: 9190219776 (8.56 GB)
DFS Remaining: 27793817600(25.89 GB)
DFS Used%: 1.53%
DFS Remaining%: 74%
Last contact: Wed Jun 04 16:39:49 CST 2014
接下来,你需要准备测试所需的数据。这里的例程都是从 Alan Gates 的书中《Programming Pig》中获得的,你可以直接下载数据和代码,亦或者这本书的电子版。
当你把数据从网上下载之后,你需要将这些数据再次上传到 Hadoop 集群上,使用命令:
hadoop fs -put NYSE_dividends /NYSE_dividends
该命令表示将当前目录下的文件($example/data/NYSE_dividends)上传至 HDFS 文件系统下的根目录中。上传成功后,你可以使用该命令查看
hadoop fs -ls /
输出的结果中应该有你已经上传的文件名字
-rw-r--r-- 3 hadoop supergroup 17697 2014-06-04 16:21 /NYSE_dividends
接下来我们进入到 PIG 的脚本命令模式:
pig -x mapreduce
执行如下的命令
-- 从文件中读取数据, 并且声明该文件中包含4列数据
dividends = load '/NYSE_dividends' as (exchange, symbol, date, dividend);
-- 将列按照 symbol 进行分组
grouped = group dividends by symbol;
-- 计算每一组的平均数
avg = foreach grouped generate group, AVG(dividends.dividend);
-- 输出结果,并将数据存入 average_dividend 中
store avg into '/average_dividend';
计算完毕后,你可以在PIG的脚本模式下使用命令 ls / 查看生成了什么
hdfs://ISCASTest01:8020/NYSE_dividends<r 3> 17697
hdfs://ISCASTest01:8020/average_dividend <dir>
再 cd 进入到 /average_dividend 目录下,并使用 ls 命令可以查看生成的文件
hdfs://ISCASTest01:8020/average_dividend/_SUCCESS<r 3> 0
hdfs://ISCASTest01:8020/average_dividend/_logs <dir>
hdfs://ISCASTest01:8020/average_dividend/part-r-00000<r 3> 1863
之后使用 cat ./part-r-00000 可以查看数据的计算结果,能看到如下内容
CA 0.04
CB 0.35
CE 0.04
CF 0.1
CI 0.04
CL 0.43
CM 0.7779999999999999
CP 0.22125
CR 0.2
CS 0.096
CV 0.23
CW 0.08
CAE 0.02675
CAG 0.1925
CAH 2.083
CAS 0.06
CAT 0.42
CBC 0.05
CBD 0.15733333333333333
CBE 0.25
CBK 0.06
CBL 0.145
CBS 0.05
CBT 0.18
CBU 0.22
当看见这些数据后,恭喜你,你已经运行了你的第一个 PIG 程序。
PIG Latin 包含以下关键字,除了UDF以外,其余部分是大小写不敏感。
Order | Keywords |
A | and, any, all, arrange, as, asc, AVG |
B | bag, BinStorage, by, bytearray |
C | cache, cat, cd, chararray, cogroup, CONCAT, copyFromLocal, copyToLocal, COUNT, cp, cross |
D | %declare, %default, define, desc, describe, DIFF, distinct, double, du, dump |
E | e, E, eval, exec, explain |
F | f, F, filter, flatten, float, foreach, full |
G | generate, group |
H | help |
I | if, illustrate, inner, input, int, into, is |
J | join |
K | kill |
L | l, L, left, limit, load, long, ls |
M | map, matches, MAX, MIN, mkdir, mv |
N | not, null |
O | or, order, outer, output |
P | parallel, pig, PigDump, PigStorage, pwd |
Q | quit |
R | register, right, rm, rmf, run |
S | sample, set, ship, SIZE, split, stderr, stdin, stdout, store, stream, SUM |
T | TextLoader, TOKENIZE, through, tuple |
U | union, using |
V, W, X, Y, Z |
此外,PIG Latin还有自己的计算符。
操作符 | 说明 | 示例 |
+ | 加法运算符 | addition = FOREACH tables GENERATE dataItem+1; |
- | 减法运算符 | substruction = FOREACH tables GENERATE dataItem-1; |
乘法运算符 | multiplication = FOREACH tables GENERATE dataItem10; | |
/ | 除法运算符 | division = FOREACH tables GENERATE dataItem/10; |
% | 求模运算 | modulo = FOREACH tables GENERATE dataItem%10; |
?: | 条件运算符 | X = FOREACH A GENERATE f2, (f2==1?1:0); |
AND | 布尔运算符 | PIG Latin不支持布尔类型,但支持布尔运算。 |
OR | 布尔运算符 | 在条件选择中,可以使用这些运算符。 |
NOT | 布尔运算符 | X = FILTER A BY (f1==8) OR (NOT (f2+f3 > f1)); |
== | 对比运算符 | X = FILTER A BY (f1 == 8); X = FILTER A BY (f2 == ‘apache’); |
!= | 对比运算符 | X = FILTER A BY (f1 != 8); |
< | 对比运算符 | X = FILTER A BY (f1 < 8); |
> | 对比运算符 | X = FILTER A BY (f1 > 8); |
<= | 对比运算符 | X = FILTER A BY (f1 <= 8); |
>= | 对比运算符 | X = FILTER A BY (f1 >= 8); |
MATCHES | 正则表达式 | X = FILTER A BY (f1 MATCHES ‘.apache.‘); |
IS NULL | Null Operators | X = FILTER A BY f1 is null; |
IS NOT NULL | Null Operators | X = FILTER A BY f1 is not null; |
+ | 正负符号 | A = LOAD ‘data’ as (x, y, z); |
- | 正负符号 | B = FOREACH A GENERATE -x, y; |
并且也支持正则表达式
glob | comment |
? | Matches any single character. |
* | Matches zero or more characters. |
[abc] | Matches a single character from character set (a,b,c). |
[a-z] | Matches a single character from the character range (a..z), inclusive. The first character must be lexicographically less than or equal to the second character. |
[^abc] | Matches a single character that is not in the character set (a, b, c). The ^ character must occur immediately to the right of the opening bracket. |
[^a-z] | Matches a single character that is not from the character range (a..z) inclusive. The ^ character must occur immediately to the right of the opening bracket. |
\c | Removes (escapes) any special meaning of character c. |
{ab,cd} | Matches a string from the string set {ab, cd} |
此外,PIG Latin还有自己的数据类型
数据类型 | 说明 | 声明方式 |
int | 整数 | as(a:int) |
long | 长整数 | as(a:long) |
float | 浮点数 | as(a:float) |
double | 双精度浮点数 | as(a:double) |
chararray | 字符串数组,支持格式为UTF8 | as(a:chararray) |
bytearray | 字节数组,用于二进制数据 | as(a:bytearray) |
以及复合数据类型
数据类型 | 说明 | 示例 |
tuple | 代表特定序列和数目的资料结构 | (“Jos Stam”, “Stable Fluids”, 1999) |
map | 代表关系映射的资料结构 | [“name”#”Jos Stam”, “paper”#”Stable Fluids”, “year”#1999] |
bag | 无序的tuple集合 | {(‘bob’, 55), (‘sally’, 52), (‘john’, 25)} |
需要注意的是示例中的括号(圆括号、中括号、花括号)是不能省略的,并且 Map 中,表示关系和数据之间映射关系的 # 符号是不能遗忘的。
在某些特定情况下,你可能只希望引用数据表中某些列,而不希望为了使用这些列写过多的代码。因此,PIG Latin 提供了像其他语言那样对这些列数据的直接访问。
类型 | 符号 | 说明 |
tuple | tuple.id 或者 tuple.(id, …) | 当需要引用tuple中某列或某些列的数据,可以使用tuple.id或者tuple.(id0, id1),也可以使用 $0。 |
bag | bag.id 或者 bag.(id, …) | 当需要引用tuple中某列或某些列的数据,可以使用bag.id或者bag.(id0, id1),也可以使用 $0。 |
map | map#’key’ | 需要访问map中的某些数据,只能通过$0#’key’或者field_name#’key’访问。 |
另外,在Grunt模式下,可以像Linux Console里一样,对文件进行操作。
命令 | 示例 | 说明 |
mv | mv filename1 filename2 | 修改或者移动文件 |
cd | cd directory | 切换当前的工作路径 |
mkdir | mkdir directory | 创建新的目录 |
rm | rm directory | 移除文件,或者目录 |
ls | ls /Data/ | 显示目录下的文件 |
quit | 退出 Grunt Shell | |
cat | cat finename | 显示文件的内容 |
copyFromLocal | copyFromLocal localfile hdfsfile | 将本地文件上载至HDFS中 |
copyToLocal | copyToLocal hdfsfile localfile | 将HDFS文件下载至本地磁盘 |
run | run xxx.pig | 在Grunt中执行脚本 |
为了处理大量的数据,比如日志文件。首先需要将待处理的数据上传至 hadoop 集群,因此你可以使用
hadoop fs -put localFileLocation hdfsFileLocation
或者使用 Pig Latin 的命令
copyFromLocal localFileLocation hdfsFileLocation
如果在HDFS上有数据需要下载至本地磁盘中,你可以使用如下命令
copyToLocal hdfsFileLocation localFileLocation
在我们的例子中,我们将从 Alan Gates 那儿获得的,以及自己想要处理的数据都放置在了 HDFS 上的 /Sample/ 文件目录下。现在,我们希望对 /Sample/NYSE_dividends 这个数据进行处理,希望得到每一支股票的平均股息。而现在,我们暂时不考虑时间,于是我们有了这样的一段代码。
dividends = load '/Sample/NYSE_dividends' as (exchange, symbol, date, dividend);
grouped = group dividends by symbol;
avg = foreach grouped generate group, AVG(dividends.dividend);
store avg into '/Results';
你可以在 Grunt 命令行模式下,将这些代码一行一行的贴在命令行里执行,并查看输出结果,也可以像执行其他脚本语言一样,将代码写在文件里,将文件作为 Pig Latin 的输入,如:
pig -x mapreduce xxx.pig
接下来分析一下这段代码。首先,与某些语言相似,Pig Latin 对关键字的大小写并不敏感,而只对变量名敏感。因此,你可以看见不同的人使用不同的风格编写 Pig Latin。我们这里建议,当你使用 PIG Latin 的关键字时,请使用大写形式,而对变量的命名以及使用这些变量时,请使用小写形式。
dividends = LOAD '/Sample/NYSE_dividends' AS (exchange, symbol, date, dividend);
grouped = GROUP dividends BY symbol;
avg = FOREACH grouped GENERATE group, AVG(dividends.dividend);
STORE avg INTO '/Results';
处理数据前需要先载入数据,因此可以使用 LOAD 命令,LOAD 与 AS 进行搭配,可以指定每一列数据的标识,默认数据之间的分隔符是’\t’。因此,当你的分隔符是其他的标识,那么可以使用 USING 命令,并使用内置的 UDF(自定义函数) PigStorage。
一般形式:
data = LOAD '/Sample/NYSE_dividends'
指定映射关系:
data = LOAD '/Sample/NYSE_dividends' AS (exchange, symbol, date, dividend);
指定映射关系,并指定分隔符形式
data = LOAD '/Sample/data' USING PigStorage('\t') AS (exchange, symbol, date, dividend);
Hadoop 并不支持对数据的删改,因此当你使用PIG Latin计算出新的结果后,需要将这些数据存入Hadoop中。如果数据需要写入到文件中,那么这样的命令是:
STORE processed INTO '/Results';
或者将数据写入HBase中:
STORE processed INTO 'processed' using HBaseStorage();
又或者使用PigStorage,为列指定特殊的分隔符号:
STORE processed INTO 'processed' using PigStorage(',');
除此之外,还可以使用 DUMP 命令,直接将数据打印至控制台。
DUMP processed;
与SQL语句中Order by相似,PIG Latin也提供了排列数据顺序的命令ORDERED。默认的排序是升序排列。
--OrderCarHead10.pig
tables = LOAD 'subdata' USING PigStorage(',') AS (carno, date, addno);
ordered = ORDER tables BY carno, date;
subtables = LIMIT ordered 10;
DUMP subtables;
那如果需要降序排列时,可以使用命令DESC。
--DescOrderCarHead10.pig
tables = LOAD 'subdata' USING PigStorage(',') AS (carno, date, addno);
ordered = ORDER tables BY carno, date DESC;
subtables = LIMIT ordered 10;
DUMP subtables;
对数据表进行逐行处理是十分重要的功能,因此PIG Latin提供了FOREACH命令。通过一组表达式对数据流中的每一行进行运算,产生的结果就是用于下一个算子的数据集。下面的语句加载整个数据,但最终结果B中只保留其中的user和id字段:
A = LOAD 'input' AS (user:chararray, id:long, address:chararray, phone:chararray, preferences:map[]);
B = FOREACH A GENERATE user, id;
在foreach中可以使用$+数字代表某个位置的列。下面语句中gain与gain2的值一样:
prices = LOAD 'NYSE_daily' AS (exchange, symbol, date, open, high, low, close,volume, adj_close);
gain = FOREACH prices GENERATE close - open;
gain2 = FOREACH prices GENERATE $6 - $3;
表达式中可以使用“*”代表全部列,还可以使用“..”表示范围内的列,这对简化命令文本很有用:
prices = LOAD 'NYSE_daily' AS (exchange, symbol, date, open,high, low, close, volume, adj_close);
beginning = FOREACH prices GENERATE ..open; -- exchange, symbol, date, open
middle = FOREACH prices GENERATE open..close; -- open, high, low, close
end = FOREACH prices GENERATE volume..; -- volume, adj_close
使用FILTER可以对数据表中的数据进行过滤工作。该关键字经常与 BY 一起联用,对表中对应的特征值进行过滤,例如:
original = LOAD 'data' AS (name, number, ino);
flitered_data = FILTER original BY number > 1000;
比如,某一段时间的股票交易数据,我们只对平均股息在0.5以上的股票感兴趣,那么就可以加入这样一段代码:
dividends = LOAD '/Sample/NYSE_dividends' USING PigStorage('\t') AS (exchange, symbol, date, dividend);
grouped = GROUP dividends BY symbol;
avg = FOREACH grouped GENERATE group, AVG(dividends.dividend);
filtered = FILTER avg by $1 > 0.5;
STORE filtered INTO '/Results/filtered';
观察以上的代码,其中 $1 > 0.5 标识表中第二列的数据大于0.5,该值为真时,将作为一行数据写入 filtered。PIG Latin中,列的下标,与其他编程语言相似,可以通过$符号进行访问,第一列下标从0开始。
与过滤相似的另一个功能,是只显示数据表中某些列。
--DisplaySomeRaws.pig
tables = LOAD 'subdata' USING PigStorage(',') AS (carno, date, addno);
raws = FOREACH tables GENERATE carno, addno;
DUMP raws;
按照键值相同的规则归并数据。在SQL中,group操作必然与聚集函数组合使用,而在pig中,group操作将产生与键值有关的bag。
daily = LOAD 'NYSE_daily' AS (exchange, stock);
grpd = GROUP daily BY stock;
cnt = FOREACH grpd GENERATE group, COUNT(daily);
这里的group是默认的变量,表示使用GROUP聚合后得到的数据组,再通过 FOREACH 对每一组数据进行单独处理。
daily = LOAD 'NYSE_daily' AS (exchange, stock);
grpd = GROUP daily by stock;
STORE grpd INTO 'by_group';
另外,也可以将聚合后得到的数据组存储起来,用于下次处理。此外,还可以针对多个字段进行分组。
daily = LOAD 'NYSE_daily' AS (exchange, stock, date, dividends);
grpd = GROUP daily BY (exchange, stock);
avg = FOREACH grpd GENERATE group, AVG(daily.dividends);
甚至可以针对全字段进行分组。
daily = LOAD 'NYSE_daily' AS (exchange, stock);
grpd = GROUP daily ALL;
cnt = FOREACH grpd GENERATE COUNT(daily);
数据表中若存在重复项,并且需要剔除这些数据,那么可以使用DISTINCT命令,剔除数据表中重复项,该方法与SQL中的用法一致。
daily = LOAD 'NYSE_daily' AS (exchange:chararray, symbol:chararray);
uniq = DISTINCT daily;
Union 的作用与 SQL 中的 Union 相似,使用该操作符,可以将不同的数据表,组合成同一的数据表。假设我们有数据表A和表B,都记录了行车数据:
A = LOAD 'table1' USING PigStorage(',') as (carno:int,date:chararray,addno:long);
B = LOAD 'table2' USING PigStorage(',') as (carno:int,date:chararray,addno:long);
X = UNION A, B;
DUMP X;
将多个数据集中的数据按照字段名进行同值组合,形成笛卡尔积
daily = load 'NYSE_daily' as (exchange:chararray, symbol:chararray, date:chararray, open:float, high:float, low:float, close:float, volume:int, adj_close:float);
divs = load 'NYSE_dividends' as (exchange:chararray, symbol:chararray, date:chararray, dividends:float);
crossed = cross daily, divs;
tjnd = filter crossed by daily::date < divs::date;
连接一组key:
jnd = JOIN daily BY symbol, divs BY symbol;
连接两组key:
jnd = JOIN daily BY (symbol, date), divs BY (symbol, date);
外连接:
jnd = JOIN daily BY (symbol, date) left outer, divs BY (symbol, date);
多表连接:
A = LOAD 'input1' AS (x, y);
B = LOAD 'input2' AS (u, v);
C = LOAD 'input3' AS (e, f);
alpha = JOIN A BY x, B BY u, C BY e;
limit
用于限制行数(类似MySQL的LIMIT)。
divs = LOAD 'NYSE_dividends';
first10 = LIMIT divs 10;
sample
随机抽取指定比例(0到1)的数据。
some = SAMPLE divs 0.1;
parallel
用于实现指定数量的多节点并行运算。
daily = LOAD 'NYSE_daily' AS (exchange, symbol, date, open, high, low, close, volume, adj_close);
bysymbl = GROUP daily BY symbol PARALLEL 10;
可以使用default_parallel来指定默认的并行度选项:
SET default_parallel 10;
daily = LOAD 'NYSE_daily' AS (exchange, symbol, date, open, high, low, close, volume, adj_close);
bysymbl = GROUP daily BY symbol;
average = FOREACH bysymbl GENERATE group, AVG(daily.close) AS avg;
sorted = ORDER average BY avg desc;
自定义函数(UDFS)
REGISTER 'your_path_to_piggybank/piggybank.jar';
DEFINE reverse org.apache.pig.piggybank.evaluation.string.Reverse();
divs = LOAD 'NYSE_dividends' as (exchange:chararray, symbol:chararray, date:chararray, dividends:float);
backwards = FOREACH divs GENERATE reverse(symbol);
flatten
将数据内部的包或元组扁平化(展开为底层字段——以笛卡尔积的方式扩展)。
players = LOAD ‘baseball’ AS (name:chararray, team:chararray, position:bag{t:(p:chararray)}, bat:map[]);
pos = foreach players generate name, flatten(position) as position;
bypos = group pos by position;
上面的players中的数据应该是这样的(已用逗号取代TAB便于查看):
Jorge Posada,New York Yankees,{(Catcher),(Designated_hitter)},...
一旦经过了flatten语句,它将变成两个数据:
Jorge Posada,Catcher
Jorge Posada,Designated_hitter
cogroup
基于一个key,记录多个输入。
A = load 'input1' as (id:int, val:float);
B = load 'input2' as (id:int, val2:int);
C = cogroup A by id, B by id;
describe C;
C: {group: int,A: {id: int,val: float},B: {id: int,val2: int}}
用它可以达到全外连接的效果:
--semijoin.pig
daily = load 'NYSE_daily' as (exchange:chararray, symbol:chararray,
date:chararray, open:float, high:float, low:float,
close:float, volume:int, adj_close:float);
divs = load 'NYSE_dividends' as (exchange:chararray, symbol:chararray,
date:chararray, dividends:float);
grpd = cogroup daily by (exchange, symbol), divs by (exchange, symbol);
sjnd = filter grpd by not IsEmpty(divs);
final = foreach sjnd generate flatten(daily);
非线性数据流(split)
wlogs = load 'weblogs' as (pageid, url, timestamp);
split wlogs into
apr03 if timestamp < '20110404',
apr02 if timestamp < '20110403' and timestamp > '20110401',
apr01 if timestamp < '20110402' and timestamp > '20110331';
store apr03 into '20110403';
store apr02 into '20110402';
store apr01 into '20110401';
上面的split等价于:
apr03 = filter wlogs by timestamp < '20110404';
apr02 = filter wlogs by timestamp < '20110403' and timestamp > '20110401';
apr01 = filter wlogs by timestamp < '20110402' and timestamp > '20110331';