A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© wuqiong 金牌黑马   /  2018-7-12 09:25  /  1217 人查看  /  9 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本文是一个学习笔记,并不包含完整的Pig(Pig Latin)内容,仅仅列出了一些本人在学习过程中觉得重要的内容,更详细的内容参考《Hadoop权威指南》、《实战Hadoop》。

Pig概述

Pig是一种探索大规模数据集的脚本语言。
Pig相当于一个Hadoop的客户端。

Pig提供了丰富的数据结构,和一套强大的数据变换操作。

MapReduce的一个缺点是开发周期太长,Pig Latin代码能轻松处理TB级的数据,而只需要少量代码。这样就能够更简单的挖掘大规模数据集。

Pig的一个更有用的特性是在它支持在输入数据的一个有代表性的子集上试运行,方便检查程序中的错误。

一个Pig Latin程序由一系列的操作和变换组成。每个操作或变换对输入进行数据处理,产生输出结果,这些操作整体上描述了一个数据流。
Pig执行环境把数据流翻译为可执行的内部表示,在内部,这些变换操作被转换为一系列MapReduce作业。程序员无需关注这些转换是如何进行的,可以集中精力在数据上,而非执行的细节上。

Pig被设计为可扩展的。通过UDF可以做到这一点,UDF在底层和Pig操作集成,UDF开发比MapReduce程序开发的库更易于重用。

Pig Latin编程语言

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


过滤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();

        }      

    }   

}




计算UDF


例子:简单的模仿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();

        }

    }   

}


加载UDF


数据库操作


加载和存储数据


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;

1

FILTER


FILTER

FILTER A BY name matches 'T*';


分组和连接:JOIN、GROUP


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;

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';


对数据进行排序 ORDER、LIMIT


--第一个字段升序,第二个字段降序

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)



Pig实战


并行处理


参数替换


动态参数替换


简单的应用场景


例子来自刘鹏主编的《实战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();


9 个回复

倒序浏览
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
回复 使用道具 举报
哈哈哈
回复 使用道具 举报
回复 使用道具 举报
优秀,加油加油!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马