第11章Pig

一个例子

让我们看下,用Pig Latin写一个程序计算几年中气温最大值(就像我们第二章做的事情那样),这样的简单例子。完整的程序只有几行:

-- max_temp.pig: Finds the maximum temperature by year

records = LOAD 'input/ncdc/micro-tab/sample.txt'

AS (year:chararray, temperature:int, quality:int);

filtered_records = FILTER records BY temperature != 9999 AND

(quality == 0 OR quality == 1 OR quality == 4 OR quality == 5 OR quality == 9);

grouped_records = GROUP filtered_records BY year;

max_temp = FOREACH grouped_records GENERATE group,

MAX(filtered_records.temperature);

DUMP max_temp;

为了看看到底发生了什么,我们会使用PigGrunt 解释器,这将允许我们进入行模式,并且和程序交互,以此来理解它正在做什么。在本地模式开启Grunt,并且输入Pig script的第一行

grunt> records = LOAD 'input/ncdc/micro-tab/sample.txt'

>> AS (year:chararray, temperature:int, quality:int);

为了简单起见,程序假设输入时tab分割的文本,每一行仅有一个年份,温度,天气质量字段。(Pig实际上有比这种格式的输入,有更多的灵活性,稍后会见到)这行描述了我们将要处理的数据。chararray 对应javastring等。LOAD操作符使用URI作为参数;这里我们仅使用一个本地文件,但是可以指向HDFS URI

AS语句(可选择的)给字段起了个别名,以便在后续语句中引用方便。LOAD操作符的结果,实际上,Pig Latin中的任何操作符的结果,都是一元数组。一元数组就像是数据库表中的一行,多个字段以特定的顺序排列。在这个例子中,LOAD函数,产生输入文件的一元数组。我们写了每行一元数组的关系,一元数组是以常用的圆括号作为分隔符的。

(1950,0,1)

(1950,22,1)

(1950,-11,1)

(1949,111,1)

关系被给了名字或者别名,因此它们可以被引用。我们可以使用DUMP操作符,检查一个别名的内容。

grunt> DUMP records;

(1950,0,1)

(1950,22,1)

(1950,-11,1)

(1949,111,1)

(1949,78,1)

我们同样可以看到,数据关系的结构或者模式,通过DESCRIBE命令

grunt> DESCRIBE records;

records: {year: chararray,temperature: int,quality: int}

下面的语句删除了不满足要求的数据。

grunt> filtered_records = FILTER records BY temperature != 9999 AND

>> (quality == 0 OR quality == 1 OR quality == 4 OR quality == 5 OR quality == 9);

grunt> DUMP filtered_records;

(1950,0,1)

(1950,22,1)

(1950,-11,1)

(1949,111,1)

(1949,78,1)

下面的语句使用GROUP函数根据year字段分组。

grunt> grouped_records = GROUP filtered_records BY year;

grunt> DUMP grouped_records;

(1949,{(1949,111,1),(1949,78,1)})

(1950,{(1950,0,1),(1950,22,1),(1950,-11,1)})

现在,我们有了两行数据。在数据中,一个是每年的输入数据。第一个字段是year字段,第二个字段是那一年的一元数组。一个bag仅仅是一元数组的集合,在Pig Latin中,使用大括号来表示。

通过以这种方式,分组数据,我们创建了每年的数据,因此,所有剩下的事情就是找到每个bag中一元数组中的最大值。在做次之前,让我们理解下grouped_records relation的结构:

grunt> DESCRIBE grouped_records;

grouped_records: {group: chararray,filtered_records: {year: chararray,

temperature: int,quality: int}}

这就告诉了我们,分组字段是被Pig重命名了,并且第二个字段与filtered_records的结构是一样的。有了这个知识以后,我们可以尝试第四种转换:

grunt> max_temp = FOREACH grouped_records GENERATE group,

>> MAX(filtered_records.temperature);

FOREACH 处理每一行来生成行的派生集,使用GENERATE语句来定义每一个生成的行的字段。在这个例子中,第一个字段分组字段,就是year字段。第二个字段有一点复杂。grunt> DUMP max_temp;

(1949,111)

(1950,22)

grunt> max_temp = FOREACH grouped_records GENERATE group,

>> MAX(filtered_records.temperature);

这样,我们成功的计算出了每年温度的最大值。

生成例子

在这个例子中,我们使用了小的,仅有几行的数据集,作为例子,这样是为了跟踪数据流和debug的方便。创建一个缩减的数据库是一项艺术,数据库中的数据应该覆盖执行查询的所有丰富的数据(完整属性)。使用一个随机的例子,通常情况下不能工作的,因为,joinfilter操作趋向于删除所有的随机数据,留下一个空的结果,是没有说明的一般流程。

ILLUSTRATE操作符,Pig提供了一个工具产生相当完整和简洁的数据集。尽管,它不能生成所有查询的例子(它不支持 LIMIT, SPLIT, 或者FOREACH语句 ),它可以生成对很多查询有用的例子。ILLUSTRATE在仅当数据关系中仅有一个模式的时候。

与数据库的比较

已经看过了Pig的操作,看起来,Pig LatinSQL有点类似。GROUP BY 和 DESCRIBE操作的存在,更是强化了这种印象。然而,在这两种语言中,有几个区别,通常情况下,是PigRDBMS之间的区别。

最重大的区别是,Pig Latin是一个数据流编程语言,而SQL是一个声明式编程语言。换句话说,Pig Latin程序是一步一步的操作。每一步都是单独的转换。但是,SQL语句是一组约束条件,定义了输出。在许多方面,Pig编程就像在一个RDBMS查询规划上面,画出了,怎样声明语句到一个系统中。

RDBMSs把数据存储在表中,有一个预先定义的模式。Pig对它处理的数据就比价轻松些,你可以在运行时设置数据的模式,但是这是可选的。本质上,它会操作任何类型的一元数组(尽管,当有多个文件的时候,元数据应该支持平行的读取),这里,UDF被用来读取原始数据的一元数组。

Pig的对复杂的支持,嵌套的数据结构,区别于SQLSQL 的操作符信奉结构。同时,Pig的使用UDFS和流操作的能力和在PIg语言中是紧密联系在一起的,这使得Pig LatinSQL语言更加自定义化。

线上支持有几个特点,RDBMS的查询的低延迟在Pig中是没有的,例如事务性和索引。就像之前提到过的一样,Pig不支持随机在几十毫秒以内完成读取、查询。它也不支持随机的写更新数据的一小部分,所有的写入都是成块的,都是流写入,就像Mapreduce一样。

Hive的定位则是PigRDBMS之间。像Pig一样,Hive被设计,使用HDFS作为存储系统,但是,它们之间有些重大的不同。Hive的查询语言,HiveQl是基于SQL的,并且,任何熟悉SQL的人,使用HiveQl没有多大问题的。就像RDBMSsHive中,所有的数据都存储在表中,表是有结构的;但是,它可以和之前存在HDFS中的数据进行联接,因此load步骤是可选的。Hive不支持低延迟查询,这是它与Pig的一个共性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值