您在这里不需要两个 MapReduce 作业(或者因此是一个 LinkedList)。我们可以将其视为字数统计的一种变体,但会在输出中添加电影 ID 列表。
地图输入:
354757\tToys come alive
432984\tMore toys
地图代码:
String[] idAndWords = input.split("\\t");
for(String word : idAndWords[1].split(" ")) {
//Do whatever cleansing you want here - remove punctuation, lowercase etc.
output.write(word,idAndWords[0]);
}
地图输出:
("toys","354757")
("come","354757")
("alive","354757")
("more","432984")
("toys","432984")
reducer 代码:
//Maps movie IDs to occurrences
Map<String,Int> movieMap = new HashMap<>();
//In here is the list of movie IDs for each word
for(String val : values) {
if(!movieMap.contains(val)) {
movieMap.put(val,1);
} else {
movieMap.put(val,movieMap.get(val)+1);
}
}
output.write(NullWritable.get(),key+"\t"+movieMap);
减速机输出:
toys\t[(3547571),(432984,1)]
come\t[(354757,1)]
alive\t[(354757,1)]
more\t[(432984,1)]
现在您不需要自定义 Writable,而且它的逻辑行数不到十行,而我认为这将是一组非常复杂的两个链式 MR 作业。
效率扩展:
您可以通过在映射器输出中添加计数来提高效率 - 在当前实现中,情节线“狗咬狗”将导致地图输出:
("dog","354757")
("eat","354757")
("dog","354757")
而您可以通过添加一个计数器并在输出前扫描整行来将其减少到两条记录:
("dog","354757\t2")
("eat","354757\t1")
我不想通过包含这个让我的示例变得更复杂和可读性更低,但它应该很容易实现并且应该可以很好地节省性能。