我想使用在映射时存在/对一个文件起作用的HashSet,然后在映射下一个文件时重置/重新创建。我已修改TextInputFormat以覆盖isSplitable以返回false,因此文件不会被拆分并由Mappers作为整体进行处理。可以这样做吗?或者是否有另一种方法可以减少对Accumulo表的写入?
让我先说我不相信我想要一个全局变量。我只是想确保唯一性,从而减少我的Accumulo表中的突变。
我的项目是将分片示例中的Index.java文件的功能从线性accumulo客户端程序转换为使用mapreduce功能的程序,同时仍在Accumulo中创建相同的表。它需要mapreduce,因为这是流行语,实质上它比线性程序运行速度快于数TB的数据。
该程序使用BatchWriter将Mutations写入Accumulo,并在每个文件的基础上进行。为了确保它不会写出超过必要的更多突变并确保唯一性(尽管我确实认为Accumulo最终通过压缩合并相同的键),Index.java有一个HashSet,用于确定之前是否运行过一个单词。这一点都比较容易理解。
转移到仅限地图的mapreduce作业更复杂。
这是我对映射的尝试,这似乎与我见过的Accumulo表的部分输出有点相似,但与线性程序Index.java相比,运行真的很慢
public static class MapClass extends Mapper<LongWritable,Text,Text,Mutation> {
private HashSet<String> tokensSeen = new HashSet<String>();
@Override
public void map(LongWritable key, Text value, Context output) throws IOException {
FileSplit fileSplit = (FileSplit)output.getInputSplit();
System.out.println("FilePath " + fileSplit.getPath().toString());
String filePath = fileSplit.getPath().toString();
filePath = filePath.replace("unprocessed", "processed");
String[] words = value.toString().split("\\W+");
for (String word : words) {
Mutation mutation = new Mutation(genPartition(filePath.hashCode() % 10));
word = word.toLowerCase();
if(!tokensSeen.contains(word)) {
tokensSeen.add(word);
mutation.put(new Text(word), new Text(filePath), new Value(new byte[0]));
}
try {
output.write(null, mutation);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
慢的问题可能是我在测试实例上运行所有这一切,Hadoop的单节点实例,ZooKeeper和Accumulo在顶部。如果是这样的话,我只需找到一个独特的解决方案。
非常感谢您提供的任何帮助或建议。
答案 0 :(得分:1)
Mapper具有setup
和cleanup
方法,您可以覆盖这些方法以更干净地处理此类事情。 setup
被调用一次,然后多次调用map
(每个记录一次),然后在结束时调用cleanup
一次。我们的想法是你在setup
方法中创建HashSet,在map
中构建它,并在cleanup
中提交所有内容,或者定期刷新一些map
的调用。 1}}如有必要。
但是,在移动到真正的集群之前,几乎肯定不会看到运行时有任何改进。单节点测试实例与简单的线性程序几乎没有任何好处,只要一旦获得真正的hadoop集群,相同的代码将运行得更快。