【问题标题】:Pig Mapreduce to count letters in a rowPig Mapreduce 连续计算字母
【发布时间】:2012-11-06 10:15:26
【问题描述】:

我需要数字母,而不是数单词。 但是我在使用 Apache Pig 版本 0.8.1-cdh3u1 实现这个时遇到了问题

给定以下输入:

989;850;abcccc
29;395;aabbcc

输出应该是:

989;850;a;1
989;850;b;1
989;850;c;4
29;395;a;2
29;395;b;2
29;395;c;2

这是我尝试过的:

A = LOAD 'input' using PigStorage(';') as (x:int, y:int, content:chararray);
B = foreach A generate x, y, FLATTEN(STRSPLIT(content, '(?<=.)(?=.)', 6)) as letters;
C = foreach B generate x, y, FLATTEN(TOBAG(*)) as letters;
D = foreach C generate x, y, letters.letters as letter;
E = GROUP D BY (x,y,letter);
F = foreach E generate group.x as x, group.y as y, group.letter as letter, COUNT(D.letter) as count;

可以转储 A、B 和 C,但“转储 D”会导致“错误 2997:无法从支持的错误重新创建异常:java.lang.ClassCastException:java.lang.Integer 无法转换为 org.apache。 pig.data.Tuple"

dump C 显示(尽管第三个值是一个奇怪的元组):

(989,850,a)
(989,850,b)
(989,850,c)
(989,850,c)
(989,850,c)
(989,850,c)
(29,395,a)
(29,395,a)
(29,395,b)
(29,395,b)
(29,395,c)
(29,395,c)

以下是架构:

grunt> describe A; describe B; describe C; describe D; describe E; describe F;
A: {x: int,y: int,content: chararray}
B: {x: int,y: int,letters: bytearray}
C: {x: int,y: int,letters: (x: int,y: int,letters: bytearray)}
D: {x: int,y: int,letter: bytearray}
E: {group: (x: int,y: int,letter: bytearray),D: {x: int,y: int,letter: bytearray}}
F: {x: int,y: int,letter: bytearray,count: long}

这个猪版本似乎不支持 TOBAG($2..$8),因此 TOBAG(*) 也包括 x 和 y,但可以稍后按句法排序... 我想避免编写 UDF,否则我会直接使用 Java API。

但我并没有真正得到转换错误。谁能解释一下。

【问题讨论】:

    标签: hadoop mapreduce apache-pig


    【解决方案1】:

    我建议改为写一个custom UDF。一个快速的原始实现如下所示:

    package com.example;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.pig.EvalFunc;
    import org.apache.pig.data.BagFactory;
    import org.apache.pig.data.DataBag;
    import org.apache.pig.data.DataType;
    import org.apache.pig.data.Tuple;
    import org.apache.pig.data.TupleFactory;
    import org.apache.pig.impl.logicalLayer.schema.Schema;
    
    public class CharacterCount extends EvalFunc<DataBag> {
    
        private static final BagFactory bagFactory = BagFactory.getInstance();
        private static final TupleFactory tupleFactory = TupleFactory.getInstance();
    
        @Override
        public DataBag exec(Tuple input) throws IOException {
            try {
    
                Map<Character, Integer> charMap = new HashMap<Character, Integer>();
    
                DataBag result = bagFactory.newDefaultBag();
                int x = (Integer) input.get(0);
                int y = (Integer) input.get(1);
                String content = (String) input.get(2);
    
                for (int i = 0; i < content.length(); i++){
                    char c = content.charAt(i);        
                    Integer count = charMap.get(c);
                    count = (count == null) ? 1 : count + 1;
                    charMap.put(c, count);
                }
    
                for (Map.Entry<Character, Integer> entry : charMap.entrySet()) {
                    Tuple res = tupleFactory.newTuple(4);
                    res.set(0, x);
                    res.set(1, y);
                    res.set(2, String.valueOf(entry.getKey()));
                    res.set(3, entry.getValue());
                    result.add(res);
                }
    
                return result;
    
            } catch (Exception e) {
                throw new RuntimeException("CharacterCount error", e);
            }
        }
    
    }
    

    将其打包到jar中并执行:

    register '/home/user/test/myjar.jar';
    A = LOAD '/user/hadoop/store/sample/charcount.txt' using PigStorage(';') 
          as (x:int, y:int, content:chararray);
    
    B = foreach A generate flatten(com.example.CharacterCount(x,y,content)) 
          as (x:int, y:int, letter:chararray, count:int);
    
    dump B;
    (989,850,b,1)
    (989,850,c,4)
    (989,850,a,1)
    (29,395,b,2)
    (29,395,c,2)
    (29,395,a,2)
    

    【讨论】:

    • 感谢示例代码。所以在“纯”猪拉丁 0.8 中是不可能的?
    • 我并不是说这是不可能的,但是以一种棘手的方式使用大量内置转换来实现结果可能会更昂贵(即:您最终将拥有更多的 MR 工作)。例如:分组将始终强制执行 reducer 阶段。
    【解决方案2】:

    我没有0.8版本,但你能试试这个吗:

    A = LOAD 'input' using PigStorage(';') as (x:int, y:int, content:chararray);
    B = foreach A generate x, y, FLATTEN(STRSPLIT(content, '(?<=.)(?=.)', 6));
    C = foreach B generate $0 as x, $1 as y, FLATTEN(TOBAG(*)) as letter;
    E = GROUP C BY (x,y,letter);
    F = foreach E generate group.x as x, group.y as y, group.letter as letter, COUNT(C.letter) as count;
    

    【讨论】:

      【解决方案3】:

      你可以试试这个

      grunt> a = load 'inputfile.txt' using PigStorage(';') as (c1:chararray, c2:chararray, c3:chararray);
      grunt> b = foreach a generate c1,c2,FLATTEN(TOKENIZE(REPLACE(c3,'','^'),'^')) as split_char;
      grunt> c = group b by (c1,c2,split_char);
      grunt> d = foreach c generate group, COUNT(b);
      grunt> dump d;
      

      输出如下所示:

      ((29,395,a),2)
      ((29,395,b),2)
      ((29,395,c),2)
      ((989,850,a),1)
      ((989,850,b),1)
      ((989,850,c),4)
      

      【讨论】:

      猜你喜欢
      • 2018-09-09
      • 2018-11-20
      • 1970-01-01
      • 1970-01-01
      • 2019-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-12
      相关资源
      最近更新 更多