【问题标题】:How can I use the map datatype in Apache Pig?如何在 Apache Pig 中使用地图数据类型?
【发布时间】:2011-05-03 10:41:52
【问题描述】:

我想使用 Apache Pig 构建一个大键 -> 值映射,在映射中查找内容,然后遍历键。但是,甚至似乎没有用于执行这些操作的语法;我检查了手册、wiki、示例代码、大象书、谷歌,甚至尝试解析解析器源。每个示例都从文件中加载地图文字......然后从不使用它们。如何使用 Pig 的地图?

首先,似乎没有办法将 2 列 CSV 文件直接加载到地图中。如果我有一个简单的map.csv

1,2
3,4
5,6

我尝试将其加载为地图:

m = load 'map.csv' using PigStorage(',') as (M: []);
dump m;

我得到三个空元组:

()
()
()

所以我尝试加载元组然后生成地图:

m = load 'map.csv' using PigStorage(',') as (key:chararray, val:chararray);
b = foreach m generate [key#val];
ERROR 1000: Error during parsing. Encountered " "[" "[ "" at line 1, column 24.
...

语法的许多变体也会失败(例如,generate [$0#$1])。

好的,所以我将我的地图转换成 Pig 的地图文字格式为map.pig

[1#2]
[3#4]
[5#6]

然后加载它:

m = load 'map.pig' as (M: []);

现在让我们加载一些键并尝试查找:

k = load 'keys.csv' as (key);
dump k;
3
5
1

c = foreach k generate m#key;  /* Or m[key], or... what? */
ERROR 1000: Error during parsing.  Invalid alias: m in {M: map[ ]}

嗯,好的,可能因为涉及到两个关系,我们需要一个连接:

c = join k by key, m by /* ...um, what? */ $0;
dump c;
ERROR 1068: Using Map as key not supported.
c = join k by key, m by m#key;
dump c;
Error 1000: Error during parsing. Invalid alias: m in {M: map[ ]}

失败。如何引用地图的键(或值)?映射模式语法似乎不允许您命名键和值(邮件列表说无法分配类型)。

最后,我希望能够在我的地图中找到他们所有的键:

d = foreach m generate ...oh, forget it.

Pig 的地图类型是半生不熟的吗?我错过了什么?

【问题讨论】:

    标签: syntax map hadoop apache-pig


    【解决方案1】:

    我认为您需要考虑relationsmap 只是一条记录的一个字段。然后你可以在关系上应用一些operations,比如加入两个集合datamapping

    输入

    $ cat data.txt 
    1
    2
    3
    4
    5
    $ cat mapping.txt 
    1   2
    2   4
    3   6
    4   8
    5   10
    

    mapping = LOAD 'mapping.txt' AS (key:CHARARRAY, value:CHARARRAY);
    
    data = LOAD 'data.txt' AS (value:CHARARRAY);
    
    
    -- list keys
    mapping_keys =
      FOREACH mapping
      GENERATE key;
    
    DUMP mapping_keys;
    
    
    -- join mapping to data
    mapped_data =
      JOIN mapping BY key, data BY value;
    
    DUMP mapped_data;
    

    输出

    > # keys
    (1)
    (2)
    (3)
    (4)
    (5)
    
    > # mapped data
    (1,2,1)
    (2,4,2)
    (3,6,3)
    (4,8,4)
    (5,10,5)
    

    如果您只想做一个简单的查找,这个答案也可以帮助您: pass-a-relation-to-a-pig-udf-when-using-foreach-on-another-relation

    【讨论】:

      【解决方案2】:

      目前 pig maps 需要您提供的 chararray(字符串)的键,而不是包含字符串的变量。因此在 map#key 中,键必须是您提供的常量字符串(例如:map#'keyvalue')。

      这种情况的典型用例是加载一个复杂的数据结构,其中一个元素是键值对,稍后在 foreach 语句中,您可以根据您感兴趣的键引用特定值。

      http://pig.apache.org/docs/r0.9.1/basic.html#map-schema

      【讨论】:

        【解决方案3】:

        在 Pig 版本 0.10.0 中,有一个名为“TOMAP”(http://pig.apache.org/docs/r0.10.0/func.html#tomap) 的新函数可以将其奇数 (chararray) 参数转换为键,将偶数参数转换为值。不幸的是,我发现它并没有那么有用,因为我通常处理不同长度和键的任意字典。

        我会发现将元组作为单个参数而不是可变数量的参数的 TOMAP 函数更有用。

        这不是您问题的完整解决方案,但 TOMAP 的可用性为您提供了更多选项来构建真正的解决方案。

        【讨论】:

          【解决方案4】:

          好问题! 我个人不喜欢 Pig 中的 Maps。它们在 Java、C# 等传统编程语言中占有一席之地,其中在地图中查找键非常方便快捷。另一方面,Pig 中的地图功能非常有限。

          正如您正确指出的那样,无法在 Pig 的 Map 中查找变量键。密钥必须是常量。例如允许使用 myMap#'keyFoo',但不允许使用 myMap#$SOME_VARIABLE。

          仔细想想,Pig 中不需要 Map。人们通常从某个来源加载数据,对其进行转换,将其与其他数据集连接,对其进行过滤,对其进行转换等等。 JOIN 实际上在查找数据中的变量键方面做得很好。 例如data1 有 2 列 A 和 B,而 data2 有 3 列 X、Y、Z。如果将 data1 BY A 与 data2 BY Z 连接起来,JOIN 会执行 Map(来自传统语言)的工作,它将 Z 列的值映射到B 列(通过 A 列)。所以data1本质上代表了一个地图A -> B。

          那么为什么我们需要在 Pig 中使用 Map?

          通常 Hadoop 数据是来自传统语言的不同数据源的转储。如果原始数据源包含 Maps,则 HDFS 数据将包含相应的 Map。

          如何处理地图数据?

          确实有 2 个用例:

          1. 映射键是常量。 例如HttpRequest Header 数据包含时间、服务器、clientIp 作为 Map 中的键。要访问特定键的值,一种情况是使用常量键访问它们。 例如header#'clientIp'。

          2. 映射键是变量。 在这些情况下,您很可能希望将 Map 键与其他一些数据集连接起来。我通常使用 UDF MapToBag 将 Map 转换为 Bag,它将地图数据转换为包含 2 个字段元组(键、值)的 Bag。将地图数据转换为元组包后,很容易将其与其他数据集连接。

          我希望这会有所帮助。

          【讨论】:

            【解决方案5】:

            1)如果你想加载地图数据,它应该像“[programming#SQL,rdbms#Oracle]”

            2)如果你想加载元组数据,它应该像“(first_name_1234,middle_initial_1234,last_name_1234)”

            3)如果你想加载包数据,它应该像“{(project_4567_1),(project_4567_2),(project_4567_3)}”

            我的文件 pigtest.csv 像这样

            1234|emp_1234@company.com|(first_name_1234,middle_initial_1234,last_name_1234)|{(project_1234_1),(project_1234_2),(project_1234_3)}|[programming#SQL,rdbms#Oracle] 4567|emp_4567@company.com|(first_name_4567,middle_initial_4567,last_name_4567)|{(project_4567_1),(project_4567_2),(project_4567_3)}|[programming#Java,OS#Linux]


            我的架构:

            a = LOAD 'pigtest.csv' using PigStorage('|') AS (employee_id:int, email:chararray, name:tuple(first_name:chararray, middle_name:chararray, last_name:chararray), project_list:bag{project : tuple(project_name:chararray)}, Skill:map[chararray]) ;

            b = FOREACH a GENERATE employee_id、email、name.first_name、project_list、skills#'programming' ;

            转储 b;

            【讨论】:

              【解决方案6】:

              您可以加载任何数据,然后转换并以键值格式存储以供以后使用

              data = load 'somedata.csv' using PigStorage(',')
              STORE data into 'folder' using PigStorage('#')
              

              然后作为映射数据读取。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-04-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多