我在输出中的含义是:
字,文件 ----- ------ wordx Doc2,Doc1,Doc1,Doc1,Doc1,Doc1,Doc1,Doc1
我想要的是:
字,文件 ----- ------ wordx Doc2,Doc1
public static class LineIndexMapper extends MapReduceBase
implements Mapper<LongWritable, Text, Text, Text> {
private final static Text word = new Text();
private final static Text location = new Text();
public void map(LongWritable key, Text val,
OutputCollector<Text, Text> output, Reporter reporter)
throws IOException {
FileSplit fileSplit = (FileSplit) reporter.getInputSplit();
String fileName = fileSplit.getPath().getName();
location.set(fileName);
String line = val.toString();
StringTokenizer itr = new StringTokenizer(line.toLowerCase());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
output.collect(word, location);
}
}
}
public static class LineIndexReducer extends MapReduceBase
implements Reducer<Text, Text, Text, Text> {
public void reduce(Text key, Iterator<Text> values,
OutputCollector<Text, Text> output, Reporter reporter)
throws IOException {
boolean first = true;
StringBuilder toReturn = new StringBuilder();
while (values.hasNext()) {
if (!first) {
toReturn.append(", ");
}
first = false;
toReturn.append(values.next().toString());
}
output.collect(key, new Text(toReturn.toString()));
}
}
为了获得最佳性能 - 我应该在哪里跳过重复出现的文件名?地图,减少或两者兼而有之 ps:我是编写MR任务的初学者,也是试图用我的问题弄清楚编程逻辑。
答案 0 :(得分:1)
您只能删除Reducer中的重复项。为此,您可以使用Set,它不允许重复。
public void reduce(Text key, Iterator<Text> values,
OutputCollector<Text, Text> output, Reporter reporter)
throws IOException {
// Text's equals() method should be overloaded to make this work
Set<Text> outputValues = new HashSet<Text>();
while (values.hasNext()) {
// make a new Object because Hadoop may mess with original
Text value = new Text(values.next());
// takes care of removing duplicates
outputValues.add(value);
}
boolean first = true;
StringBuilder toReturn = new StringBuilder();
Iterator<Text> outputIter = outputValues.iter();
while (outputIter.hasNext()) {
if (!first) {
toReturn.append(", ");
}
first = false;
toReturn.append(outputIter.next().toString());
}
output.collect(key, new Text(toReturn.toString()));
}
编辑:根据Chris的评论将值的副本添加到Set。
答案 1 :(得分:0)
您可以通过本地地图聚合和引入合并器来提高性能 - 基本上您希望减少映射器和缩减器之间传输的数据量
本地地图聚合是一种概念,通过这种概念,您可以维护LRU,例如输出对的映射(或集合)。在您的情况下,当前映射器文档的一组单词(假设每个映射都有一个文档)。这样,您可以在集合中查找单词,并且只有在该集合尚未包含该单词时才输出K,V对(表示您尚未为其输入条目)。如果该集不包含该单词,则输出单词,docid对,并使用单词更新该集。
如果设置得太大(比如5000或10000个条目),那么将其清除并重新开始。通过这种方式,您可以看到映射器输出的值的数量(如果您的值域或值集很小,单词就是一个很好的示例)。
您也可以在组合器阶段引入您的reducer逻辑
一旦发出警告的最后一句 - 要小心地将Key / Value对象添加到集合中(比如在Matt D的答案中),hadoop会重新使用引擎盖下的对象,所以如果你得到意想不到的结果,不要感到惊讶你添加引用 - 总是创建一个对象的副本。
有一篇关于本地地图聚合的文章(对于单词计数示例),您可能会发现它很有用: