【问题标题】:MapReduce program keep counter when reading a text fileMapReduce程序在读取文本文件时保持计数器
【发布时间】:2019-02-24 00:44:57
【问题描述】:

我正在尝试实现一个 map reduce 程序,以便输出是 .txt 文件的对角线。 例如,读取文件

a*****
*b****
**c***
***d**
****e*
*****f

我希望输出为 abcdef

我写的映射器类是这个:

public class MapperClass extends MapReduceBase implements Mapper<LongWritable, Text, Text, Text>
{
//hadoop supported data types
private static final Text t = new Text("");
private Text word = new Text();
//private static int linenumber = 0;

  public void map(LongWritable key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException
  {
        //taking one line at a time from input file
        String line = value.toString();
        int linenumber = 0; 
        word.set(Character.toString(line.charAt(linenumber++)));
        output.collect(word, t);
   }
}

但我得到的输出是

a
*
*
*
*
*

我尝试将行号从 map 方法中删除,但仍然得到相同的结果。有人可以帮忙吗?我只需要找到一种方法来保持计数器在我从文件中读取下一行时递增。 P.S. 我认为这里不需要减速器,因为我不想对任何中间结果进行排序。如果我错了,请纠正我。 谢谢!

【问题讨论】:

    标签: hadoop mapreduce


    【解决方案1】:

    使用已提供给您的map 方法的LongWritable key 参数并指向已处理文件中的行号。

    通常,您无法在映射器中跟踪linenumber,因为一个文件可能由多个映射器处理(特别是如果您使用TextInputFormat,它假定常规文本文件是splittable)。这种全局状态通常只在计数器中才有意义。

    【讨论】:

    • 我尝试过这样的事情(假设每行有 6 个字符长) int position = ((int) key.get() / 6) % 6; word.set(Integer.toString(position));问题是我按排序顺序获取字母(相反,我希望它们一个接一个地出现,例如第一行的第一个字母,然后是第二行的字母等。对此有什么想法吗?
    • 我认为您需要显式调用job.setNumReduceTasks(0),否则您最终将使用IdentityReducer,并且仍然会进行随机播放和排序。您是否看到为您的工作产生了任何 reducer 任务?
    • 是的,有一个 reducer 任务正在生成。我添加了job.setNumReduceTask(0),但我遇到了一些奇怪的事情。作为输入,我有一个 .txt 文件,它有 12 行,每行 4 个字母。然后使用 word.set(Integer.toString((int)key.get())); output.collect(word, t); 输出为 0,5,10,15,20,25,30。不应该一直持续到60吗??我不明白为什么会这样
    • 作业成功了吗?日志中有异常吗?
    • 是的。日志中没有异常
    【解决方案2】:

    实际上你没有使用任何循环,所以它在第一行本身遍历。试试这个

    public void map(LongWritable key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException
    {
        //taking one line at a time from input file
        String line = value.toString();
        StringTokenizer itr = new StringTokenizer(line.toLowerCase());
        int linenumber = 0; 
        while(itr.hasMoreTokens()) {
    
        word.set(Character.toString(line.charAt(linenumber++)));
        output.collect(word, t);
        }
    }
    

    希望能成功

    【讨论】:

    • 你有什么错误或者你能告诉我你的工作状态是什么
    • 我尝试使用现在包含行 (a,ab,abc) 的不同文件,但我得到 java.lang.StringIndexOutOfBoundsException: String index out of range: 2
    【解决方案3】:

    在静态范围内启用private static int linenumber = 0; 行。

    并在映射器方法中注释int linenumber = 0; 行。

    是的,当然,您不需要减速器来满足您的要求。

    【讨论】:

      【解决方案4】:

      所有行在 map 函数中不一起执行。他们逐行执行。 第一次使用 linenumber++ 时,它会给你 'a' 但下一次 linenumber 也会设置为 0,所以 '*' 将被发送到 reducer 函数。对这些类型的问题使用上下文计数器。

      【讨论】:

        猜你喜欢
        • 2013-02-09
        • 1970-01-01
        • 1970-01-01
        • 2016-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多