Pig是一款数据装载、处理、存储的工具。我们可以使用pig将数据装载到内存中成为一个关系,然后再通过PigLatin语言对数据进行操作,最后再将数据转换的结果存储到一个文件中。它的底层事实上是MR的任务,所以会具备MR的各个特性。
Pig由两部分组成
一个PigLatin程序是由一组PigLatin语句组成。大小写敏感,每一句最后都以分号结尾。其中所有的一行行的语句都是为了构建一个查询计划。在构建查询计划时语句是不会执行的。在构建完成之后Pig就会做一个整体的优化。比如我们在上一句查询了1000条数据然后下面会给出一些条件去过滤掉一些数据。这样的话我们就可以直接去追求那些最终的数据从而省略掉中间的步骤。最后在使用比如说DUMP语句的时候再去将逻辑计划转换成物理计划再执行。需要注意的是如果中间出现了一个错误的语法那么逻辑计划的搭建就会终止。
在批处理下还有一个隐藏的优化点就是多查询执行就是一个执行的结果可以多个过程所引用。在交互式的环境下STORE、DUMP命令总是会触发语句的执行,各个操作之间彼此隔离他们内部会包含run语句,执行的结果不能重用。但是批处理下的STORE操作就能够实现多查询执行它内部包含exec语句。
有些语句并不会处理数据比如说导包或者是注册语句,由于它不会处理语句的特性所以他们不会像执行计划一样最后才执行,相反他们会立即执行。
当我们把文件中的数据通过PigLatin装载到内存中的时候,当我们将数据执行了一些操作的时候,我们会把这个数据称作为关系,它在内存中它而且可能具有复杂嵌套的结构。在结构方面它与Pig中的包(本质上也是一个复杂嵌套的数据结构)一样。但是Pig赋予他们的操作是不同的。
详见文档
在PigLatin中没有一种数据对饮Java中的byte、short、char。字符串使用chararray来表示,其它整数类型与Java的基本类似。除此之外还有一些复杂的类型,tuple元组、bag包、map映射。如果在装载数据时没有指定类型那么默认的数据类型就是bytearray。
其它详见文档。
模式简单来说就是字段名称+字段类型。上面我们已经提到,SQL中会现有模式然后再有数据。但是Pig是一个数据处理工具所以会在已有的数据上添加对应的模式。但是我们也可以不去定义模式,通过$[数字]来引用获取数据,此时获取到的所有数据的类型都是bytearray类型。
Pig的模式十分的灵活,我们可以在任意一个操作之前重新定义我们所需要的模式,但是这也带来了一些负担。因为有些模式不是每次都需要定义因为它与上一次的模式是一样的。但是Pig本身是不能够实现模式的重用的,这时就能够使用HCatalog来利用Hive的matestore来存储模式进而达到模式重用。
实务上我们采集到的数据可能是残缺的不完整的或者是格式错误的,这时候我们可能使用过滤操作把它过滤掉。当然没有明确的手段去处理这些事情可以说是非常的灵活。
在SQL中我们在一些操作之后会得到新的模式比如说把两张表连接。Pig中不用为每个新产生的关系申明模式。大多数情况下会根据输入的模式来确定输出的模式。但是模式的合并可能会比较复杂当数据横向合并的时候会由于两组数据字段的个数不同而不兼容。
这里着重强调聚集函数中的代数函数,代数函数可以有进一步的优化。比如说求最大值这种运算,几个小组的最大值的最大值就是所有数的最大值。但是几个小组的中位数的中位数就不是全体数字的中位数。前一个计算就属于代数函数。
过滤函数的底层是一个判断,返回值是一个boolean。满足要求的就返回true否则就返回false这样的话返回为true的值会留下来。
加载函数会指明如何从外部存储加载到一个关系。
如何把一个关系中的数据存储到外部存储。通常加载和存储会由相同的类来实现。
就是一些函数或者是操作的封装。一个宏可以打包一段PigLatin的代码。使用$前缀进行引用,在运行的时候会展开宏。
所有的UDF都是EvalFunc的实现类(直接或者间接)。在调用的时候我们会使用类名加参数,这也是为什么Pig中会严格的区分大小写。由于UDF在Java语言描述的情况下会在执行的时候以jar包的方式运行,所以会在运行时将jar文件传输到集群。
我们也可以利用UDF来告诉Pig所期望的各个字段的值。重写EvalFunc的getArgToFuncMapping()方法。
只是继承不同的类而已,在动态调用中如果用到了Java中的代码的话我们就会使用反射技术同时使用Method的InvokeXX来调用。
Pig数据的加载会先于mapper的运行,所以保证数据可以被分割成各个独立的mapper是十分重要的。在遇到损坏的数据的时候通常会采取返回null的策略。我们可以在类中定义类的模式但需要注意的是AS中所定义的模式的优先级会高于在函数中的优先级。
常见的调用默认的存储函数,比如说PigStorage。
新关系 = FOREACH 旧关系 GENERATE 旧关系中的字段的一些处理,当然也包含我们的添加字段。
另外排序与数据的组合或者是拆分与SQL基本类似。合并会由于字段的不一致所导致模式的混乱,如果字段值的个数不一致的话那么就或导致没有模式。同样分割也是按照一定的指标去实现数据分离(IF … OTHERWISE…)。