【问题标题】:Hadoop MapReduce access mapper output number in reducerHadoop MapReduce访问reducer中的mapper输出数
【发布时间】:2018-08-02 17:33:50
【问题描述】:

我有一个映射器,它输出句子中的每个字母,它是键,数字 1 作为它的值。例如,我的映射器将“你好吗”输出为

H 1
o 1
w 1
a 1
r 1
e 1
y 1
o 1
u 1

我的 reducer 使用这个并使用 1 来计算每个字母的出现次数。例如,它会输出字母“o”作为键,输出 2 作为值,因为它出现了两次。

我的问题是我想计算每个字母在句子中出现的频率。为此,我需要访问句子中的字母总数(输出的映射器数量)。我是 mapreduce 的新手,所以我不确定最好的方法。

【问题讨论】:

  • 如果映射器中有字母总数,也许您也可以将该值附加到每个输出中? H 1 9, o 1 9, w 1 9 ...
  • 您的输入是什么样的?每个映射器几乎肯定会阅读多个句子。通常,映射器一次读取一行数据。您不希望仅仅为了阅读一个句子而产生一个映射器的巨大开销。

标签: java hadoop mapreduce mapper reducers


【解决方案1】:

假设您的映射器正在获取一个完整的句子,您正在尝试查找频率并且您正在使用 Java API,您可以通过 context.write(...) 函数从映射器输出两个键:

映射器的java语法:public void map(LongWritable key, Text value, Context context)

  1. 密钥:<lineNo_Letter>;值:c_m
  2. 键:<lineNo_Letter>;值:t_n

在哪里

lineNo = same as key to the mapper (the first parameter to the above function)
letter = your desired letter
m = <total number of letters in the line (the 2nd parameter to the above function) input to the mapper>
n = <number of occurrence of letter in the line (the 2nd parameter to the above function) mapper input line>

c_a_ 只是识别计数类型的前缀。 c代表字母的出现;而t代表出现的总数。

基本上,我们在这里利用的概念是,您可以从 mapper/reducer 中写入任意数量的键值。

现在减速器会得到类似的东西 键:&lt;lineNo_letter&gt; 值:ListOf[c_m, t_n]

现在,只需在列表上进行迭代,使用分隔符 _ 和标识符前缀(tc)将其拆分;您在减速器中有所需的值。即

Total number of letter in the sentence = m
Total number of occurrence of the letter = n

编辑:添加伪逻辑

以您的示例为例,假设映射器函数public void map(LongWritable key, Text value, Context context) 的输入行是

LongWritable key = 1
Text value = howareyou

映射器的输出应该是:

-- Output length of the Text Value against each letter
context.write("1_h", "t_9");
context.write("1_o", "t_9");
context.write("1_w", "t_9");
context.write("1_a", "t_9");
context.write("1_r", "t_9");
context.write("1_e", "t_9");
context.write("1_y", "t_9");
context.write("1_u", "t_9");

请注意,上述输出是映射器中句子的每个字母一次。这就是为什么字母o 只输出一次(即使它在输入中出现两次)。

映射器代码的更多输出将是

-- Output individual letter count in the input text as 
context.write("1_h", "c_1");
context.write("1_o", "c_2");
context.write("1_w", "c_1");
context.write("1_a", "c_1");
context.write("1_r", "c_1");
context.write("1_e", "c_1");
context.write("1_y", "c_1");
context.write("1_u", "c_1");

同样,您可以看到字母 o 的值等于 c_2,因为它在句子中出现了两次。

现在将生成 8 个 reducer,每个都将获得以下键值对之一:

key: "1_h" value: ListOf["t_9", "c_1"]
key: "1_o" value: ListOf["t_9", "c_2"]
key: "1_w" value: ListOf["t_9", "c_1"]
key: "1_a" value: ListOf["t_9", "c_1"]
key: "1_r" value: ListOf["t_9", "c_1"]
key: "1_e" value: ListOf["t_9", "c_1"]
key: "1_y" value: ListOf["t_9", "c_1"]
key: "1_u" value: ListOf["t_9", "c_1"]

现在在每个 reducer 中,拆分 key 以获得行号和字母。 遍历值列表以提取出现的总数和字母。

第 1 行中字母 h 的频率 = Integer.parseInt("c_1".split("_")[1])/Integer.parseInt("t_9".split("_")[1])

这是一个供你实现的伪逻辑。

【讨论】:

  • 所以在我上面的例子中,有 9 个字母。我可以在映射器中计算这个计数,因为我在每个 context.write(key, val) 上增加一个变量。我的问题是我需要减速器中的这个计数来计算频率。我不知道如何从映射器到减速器的计数。
  • 我添加了伪逻辑。基本上,您不需要按context.write(key, 1) 计算一行中的每个字母,因为句子中的所有字母都可以使用简单的for 循环来计算。
  • @Oblivion 如果它对你有用,你能接受答案吗?
【解决方案2】:

不要立即写下你看到的每一个字母。计算所有字符,然后将总数与字符一起写出来。

然后根据你写值的方式,你的 reducer 会看到

o, [(1,9), (1,9)]

将1相加,提取任意一个9,然后除以

【讨论】:

    【解决方案3】:

    自己解决了:使用全局计数器访问 MAP_OUTPUT_RECORDS 以获取 reducer 中映射器输出的总数。

    代码:

    Configuration conf = context.getConfiguration();
    Cluster cluster = new Cluster(conf);
    Job currentJob = cluster.getJob(context.getJobID());
    long totalCharacters = currentJob.getCounters().findCounter(TaskCounter.MAP_OUTPUT_RECORDS).getValue();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-03
      相关资源
      最近更新 更多