Pig Load如何混合标量和地图数据类型?

时间:2013-05-09 18:22:40

标签: apache-pig

使用Apache Pig版本0.10.1.21(rexported)

数据样本文件的内容:

AtomicNumber,ElementName,Symbol,AtomicMass,PropertyMap
46,Palladium,Pd,106.42,[P#46,N#60,Struc#Cubic]
49,Indium,In,114.818,[P#49,N#66,Struc#Tetragonal]
52,Tellurium,Te,127.6,[P#52,N#76,Struc#Hexagonal]
86,Radon,222.0,Rn,[P#86,N#136,Struc#Cubic]
38,Strontium,Sr,87.62,[P#38,N#50,Struc#Cubic]
Plutonium,94,Pu,244.0,[P#94,N#150,Struc#Monoclinic]

注意:有意地交换某些列(对于Radon和Plutonium)以查看Pig如何处理数据类型不匹配

猪脚本:

AtomElem = LOAD 'data/Atoms.txt' USING PigStorage(',') AS (AtomicNumber:int, ElementName:chararray, Symbol:chararray, AtomicMass:float, PropertyMap:map[]);
DUMP AtomElem;

结果:

(,ElementName,Symbol,,)
(46,Palladium,Pd,106.42,)
(49,Indium,In,114.818,)
(52,Tellurium,Te,127.6,)
(86,Radon,222.0,,)
(38,Strontium,Sr,87.62,)
(,94,Pu,244.0,)

问题1 :我希望显示PropertyMap。您能否告诉我如何修改pig脚本或数据文件,以便将PropertyMap列显示为map数据类型。

Question2 :在地图模式的声明中,我想强类型化数据类型。我将模式声明为PropertyMap:map [int,int,chararray]但是pig拒绝了语法(错误,右括号预期)。是否可以声明具有多个键的地图?如果是,那么架构声明应该是什么样的?

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您的脚本无法成功生成地图的原因是您使用逗号作为字段分隔符,但它也是映射键值对的分隔符。因此,当Pig将您的行拆分为字段时,第五个字段不是[P#46,N#60,Struc#Cubic],正如您所期望的那样,而是[P#46。 Pig无法将其成功解析为地图,因此会转换为NULL

关于第二个问题,您无法指定各个地图值的数据类型。首先,订单在地图中没有任何意义。地图可以包含任意数量的元素。如果要为所有值指定单个数据类型,则可以这样做,但除此之外,Pig将确定它的类型,或者在使用它时需要显式转换值。

为了说明这两点,我已将输入数据修改为制表符分隔(并相应地将脚本更新为USING PigStorage('\t')),并交换第二行中两个地图元素的位置以显示Pig不会重现他们提供的顺序。

$ cat data.txt
AtomicNumber    ElementName     Symbol  AtomicMass      PropertyMap
46      Palladium       Pd      106.42  [P#46,N#60,Struc#Cubic]
49      Indium  In      114.818 [N#66,Struc#Tetragonal,P#49]
52      Tellurium       Te      127.6   [P#52,N#76,Struc#Hexagonal]
86      Radon   222.0   Rn      [P#86,N#136,Struc#Cubic]
38      Strontium       Sr      87.62   [P#38,N#50,Struc#Cubic]
Plutonium       94      Pu      244.0   [P#94,N#150,Struc#Monoclinic]

$ cat test.pig
AtomElem = LOAD 'data.txt' USING PigStorage('\t') AS (AtomicNumber:int, ElementName:chararray, Symbol:chararray, AtomicMass:float, PropertyMap:map[]);
DUMP AtomElem;

$ pig -x local test.pig
(,ElementName,Symbol,,)
(46,Palladium,Pd,106.42,[P#46,N#60,Struc#Cubic])
(49,Indium,In,114.818,[P#49,N#66,Struc#Tetragonal])
(52,Tellurium,Te,127.6,[P#52,N#76,Struc#Hexagonal])
(86,Radon,222.0,,[P#86,N#136,Struc#Cubic])
(38,Strontium,Sr,87.62,[P#38,N#50,Struc#Cubic])
(,94,Pu,244.0,[P#94,N#150,Struc#Monoclinic])

答案 1 :(得分:0)

就个人而言,我将所有数据存储为JSON并从中加载。当您在加载的数据集中有复杂的数据结构时,它将使您和之后处理此事的任何人更容易管理,因为JSON是嵌套结构比直接加载地图等更直接的标准...猪。

我认为@WinnieNicklaus的答案也应该有效,但是下一个人正在处理这个问题,或者下次你需要为数据添加一些复杂的东西时,你会遇到同样的问题。只需将所有内容存储在JSON中,然后使用Pig's Built-in JSON loader加载:

a = load 'a.json' using 
JsonLoader('a0:int,a1:{(a10:int,a11:chararray)},a2:(a20:double,a21:bytearray),a3:[chararray]');

如果您不想提供架构,也可以使用ElephantBird的JSON加载器加载:

loaded = LOAD '/path/to/some_file.json'
    using com.twitter.elephantbird.pig.load.JsonLoader('-nestedLoad');

如果我没记错的话,这两个文件都可以正常使用.gz文件,而且elephantbird版本也适用于lzos。