本文是一个学习笔记,并不包含完整的Pig(Pig Latin)内容,仅仅列出了一些本人在学习过程中觉得重要的内容,更详细的内容参考《Hadoop权威指南》、《实战Hadoop》。
Pig是一种探索大规模数据集的脚本语言。
Pig相当于一个Hadoop的客户端。
Pig提供了丰富的数据结构,和一套强大的数据变换操作。
MapReduce的一个缺点是开发周期太长,Pig Latin代码能轻松处理TB级的数据,而只需要少量代码。这样就能够更简单的挖掘大规模数据集。
Pig的一个更有用的特性是在它支持在输入数据的一个有代表性的子集上试运行,方便检查程序中的错误。
一个Pig Latin程序由一系列的操作和变换组成。每个操作或变换对输入进行数据处理,产生输出结果,这些操作整体上描述了一个数据流。
Pig执行环境把数据流翻译为可执行的内部表示,在内部,这些变换操作被转换为一系列MapReduce作业。程序员无需关注这些转换是如何进行的,可以集中精力在数据上,而非执行的细节上。
Pig被设计为可扩展的。通过UDF可以做到这一点,UDF在底层和Pig操作集成,UDF开发比MapReduce程序开发的库更易于重用。
Pig 对所有的语句和语义进行确认,但是只有遇到Store和Dump命令时,才按照顺序执行之前的所有语句。
(1)空格问题
--records与“=”号之间必须有空格,否则会出错。
--等号与Load之间可以有,也可以没有空格.
--下面语句读入的是制表符(table)分割的文本。读其他分割符文本不行。
records =load 'test' as (year,temperature,quality);
--如果读其它分割符文本,如‘:’
records =load 'test' using PigStorage(':')
as (year,temperature,quality);
(2)SPLIT函数不能只写一半:
如下面写法就是错误的:
--错误写法
split records into good_records if quality is not null;
--正确写法如下:
split records into good_records if quality is not null,bad_records if quality is null;
操作和命令大小写无关,而别名和函数命是大小写敏感的。
结尾加逗号
注释方法 多行/* */ 单行–
Pig Latin数据类型:
数值 int 32位有符号整数 1
long 64位有符号整数 1L
float 32位浮点 1.0F
double 64位浮点 1.0
文本 chararray UTF-16格式的字符数组 ‘a’
二进制 bytearray 字节(8bit)数组
复杂类型 tuple 任何类型的字段序列 (1,’as’)
map 一个键值对集合 键必须是字符数组 [‘a’#’toms’]
bag 元组的无需多重集合 {(‘1’,’some’),(2)}
内置转换函数可供操作:
TOMAP,TOTUPLE,TOBAG
Pig Latin提供算术,比较,关系等运算符,含义和用法与C语言相差不大。
算术:%与?:与C语言相同,取模和条件?成立时:不成立时
比较运算:==、!=、<、>、>=、<=与C语言相同,多了个模式匹配 matches ,左边是表达式,右边是字符串常量
X =ForeachA Generate name matches 'T*'? 1: 0;
X=Filter A By f1=='cstor' And f2>80;
grunt> describe records;
records: {year: bytearray,temperature: int,quality: int}
Pig支持Piggy Bank,可以使用其它用户编写的UDF
过滤函数都是FilterFunc的子类,FilterFunc本身是EvalFunc的子类。
/**输出类型是Boolean,可以编写各种过滤函数*/
package myPigUdf;
import java.io.IOException;
/**包含pig-0.15.0-core-h1.jar,pig-0.15.0-core-h2.jar*/
/**还要包含hadoop相关的类,如果提示找不到相应类,ctrl+shit+t查找添加即可*/
import org.apache.pig.FilterFunc;
import org.apache.pig.data.Tuple;
import org.apache.pig.backend.executionengine.ExecException;
public class IsGoodQuality extends FilterFunc{
@Override
public Boolean exec(Tuple tuple) throws IOException {
if (tuple==null||tuple.size()==0) {
return false;
}
try {
Object object =tuple.get(0);
if (object==null) {
return false;
}
int i=(Integer)object;
return i==0||i==1||i==4||i==5||i==9;
} catch (ExecException e) {
throw new IOException();
}
}
}
例子:简单的模仿String.trim(),去除字符串两端的空格函数
/**输出类型是public String,因此可以在借用这个函数,编写自
--己的字符串操作函数,也可以编写自己的数学计算函数*/
package myPigUdf;
import java.io.IOException;
import org.apache.pig.EvalFunc;
import org.apache.pig.backend.executionengine.ExecException;
import org.apache.pig.data.Tuple;
public class Trim extends EvalFunc<String>{
@Override
public String exec(Tuple input) throws IOException {
if(input==null||input.size()==0){
return null;
}
try {
Object object =input.get(0);
if (object==null) {
return null;
}
return ((String)object).trim();
//return ((String)object).toUpperCase();
} catch (ExecException e) {
throw new IOException();
}
}
}
LOAD、STORE
PigStorage是Load和Store操作符加载函数,能处理简单和复杂的数据类型
PigStorage对有结构的文本进行读取,并采用UTF-8编码进行存储。
默认情况下是’\t’,可以制定其它字符。
A= Load 'input.dat' USING PigStore(':') as(year,temperature:float);
STORE A INTO 'out' USING PigStorage(':');
当用AS语句载入数据时,Pig会尝试将数据转换为指定的数据类型,如果转换失败,载入程序时会产生一个NULL值,或者报错。
FOREACH GENERATE
FOREACH A GENERATE $0,'Constant',$2+1;
FILTER
FILTER
FILTER A BY name matches 'T*';
JOIN
grunt>DUMP A;
(2,Tie)
(4,Coat)
(3,Hat)
(1,Scarf)
grunt>DUMP B;
(Joe,2)
(Hank,4)
(Ali,0)
(Eve,3)
(Hank,2)
grunt>C=JOIN A BY $0,B BY $1;
/*内连接,等值连接,如果A的第0行等于B的第1行,则进行连接*/
(2,Tie,Joe,2)
(2,Tie,Hank,2)
(3,Hat,Eve,3)
(4,Coat,Hank,4)
/*还可以使用A::name*/
如果连接的关系太大,不能全部放在内存中,则应使用通用的连接操作。
如果小的那个可以全部放在内存中,则可以使用分段复制的连接。
如下例:第一个是大关系,第二个是小关系(可以全部放在内存中):
grunt>C=JOIN A BY $0,B BY $1 USING "replicated";
/*replicated:可复制的*/
外连接
可以找到连接表中不能匹配的数据行。
grunt>C=JOIN A BY $0 LEFT OUTER,B BY $$1;
grunt>DUMP C
(1,Scarf,,) /*与内连接的区别在这里*/
(2,Tie,Joe,2)
(2,Tie,Hank,2)
(3,Hat,Eve,3)
(4,Coat,Hank,4)
COGROUP
D=GROUP A BY $0,B BY $1;
--max_temp_station_name.pig
REGISTER pig-examples.jar
DEFINE isGood com.hadoopbook.pig.IsGoodQuality();
stations=LOAD 'input/NCDC/'
USING com.hadoopbook.pig.CutLoadFunc('1-6,8-12,14-42')
As(usaf:chararray,wban:chararray,name:chararray);
trimmed_stations=FOREACH stations GENERATE usaf,wban,com.hadoopbook.pig.Trim(name);
records =LOAD ''
USING
AS(usaf:chararray,wban:chararray,temperature:int,quality:int);
filtered_records=FILTER records BY temperature !=9999 AND isGood(quality);
grouped_records=GROUP filtered_records BY (usaf,wban)PARALLEL 30;
max_temp=FOREACH group_records GENERATE FLATTEN(group),
MAX(filtered_records.temperature);
max_temp_name=JOIN max_temp BY(usaf,wban),trimmed_stations BY(usaf,wabna)PARALLEL 30;
max_temp_result=FOREACH max_temp_name GENERATE $1,$1,$5,$2;
STOR max_temp_result INTO 'max_temp_by_station';
--第一个字段升序,第二个字段降序
B=ORDER A BY $0,$1 DESC
--只显示其中两个结果
LIMIT B 2
--并集,对于两个不同模式的关系,也可以并
C=UNION A,B
--如果是A,B模式不相同,则:Schema for C unknown
UNION相反的操作是SPLIT
grunt> split records into good_records if quality is not null,bad_records if quality is null;
grunt> dump bad_records;
(1992,22,)
grunt> dump good_records;
(1990,12,7)
(1992,13,8)
(1990,23,9)
(1991,23,1)
例子来自刘鹏主编的《实战Hadoop》一书P233
电信通话记录查询
文本文件示例:
start_time end_time calling_number called_number cdr_type
1312444562132 1312444582121 13712652152 13771262151 1
1312444562132 1312444582121 13712652152 10086 2
cdr_type 1 电话 2 短信
grunt> records =load 'hdfs://cstortest:9000/wjb/cdr.txt'
using PigStore('\t')
as (start_time:long,
end_time:long,
calling_number:long,
cdr_type:int);
grunt> filter_records =filter records by
start_time>1300835802 and
called_number==10086 and
cdr_type=2;
grunt> store filter_records into
'hdfs://cstor-master:9000/wjb/filter_records.txt'
using PigStorage();