我已经在Hadoop
中的Reducer类的run()方法中编写了这段代码@Override
public void run(Context context) throws IOException, InterruptedException {
setup(context);
ConcurrentHashMap<String, HashSet<Text>> map = new ConcurrentHashMap<String, HashSet<Text>>();
while (context.nextKey()) {
String line = context.getCurrentKey().toString();
HashSet<Text> values = new HashSet<Text>();
for (Text t : context.getValues()) {
values.add(new Text(t));
}
map.put(line, new HashSet<Text>());
for (Text t : values) {
map.get(line).add(new Text(t));
}
}
ConcurrentHashMap<String, HashSet<Text>> newMap = new ConcurrentHashMap<String, HashSet<Text>>();
for (String keyToMerge : map.keySet()) {
String[] keyToMergeTokens = keyToMerge.split(",");
for (String key : map.keySet()) {
String[] keyTokens = key.split(",");
if (keyToMergeTokens[keyToMergeTokens.length - 1].equals(keyTokens[0])) {
String newKey = keyToMerge;
for (int i = 1; i < keyTokens.length; i++) {
newKey += "," + keyTokens[i];
}
if (!newMap.contains(newKey)) {
newMap.put(newKey, new HashSet<Text>());
for (Text t : map.get(keyToMerge)) {
newMap.get(newKey).add(new Text(t));
}
}
for (Text t : map.get(key)) {
newMap.get(newKey).add(new Text(t));
}
}
}
//call the reducers
for (String key : newMap.keySet()) {
reduce(new Text(key), newMap.get(key), context);
}
cleanup(context);
}
我的问题是,即使我的输入太小,由于 newMap.put()调用,因此需要30分钟才能运行。如果我将此命令放在注释中,那么它会快速运行而不会出现任何问题 如您所见,我使用ConcurrentHashMap。我不想使用它,因为我认为run()只在每台机器上调用一次(它不会同时运行)所以我对简单的HashMap没有任何问题,但如果我更换了concurrentHashMap与简单的HashMap我收到一个错误(concurrentModificationError)。 有没有人知道如何使它工作没有任何延迟? 提前谢谢!
*的Java6 * hadoop 1.2.1
答案 0 :(得分:2)
我不知道它是否会解决您的性能问题,但我看到您正在做的一件效率低下的事情:
newMap.put(newKey, new HashSet<Text>());
for (Text t : map.get(keyToMerge)) {
newMap.get(newKey).add(new Text(t));
}
将HashSet保存在变量中而不是在newMap中搜索它会更有效:
HashSet<Text> newSet = new HashSet<Text>();
newMap.put(newKey, newSet);
for (Text t : map.get(keyToMerge)) {
newSet.add(new Text(t));
}
您正在做的另一个低效的事情是创建一个值的HashSet,然后创建另一个相同的HashSet以放入地图中。由于原始的HashSet(values
)从未再次使用过,因此您无需任何理由构建所有这些Text对象。
而不是:
while (context.nextKey()) {
String line = context.getCurrentKey().toString();
HashSet<Text> values = new HashSet<Text>();
for (Text t : context.getValues()) {
values.add(new Text(t));
}
map.put(line, new HashSet<Text>());
for (Text t : values) {
map.get(line).add(new Text(t));
}
}
您可以简单地写一下:
while (context.nextKey()) {
String line = context.getCurrentKey().toString();
HashSet<Text> values = new HashSet<Text>();
for (Text t : context.getValues()) {
values.add(new Text(t));
}
map.put(line, values);
}
编辑:
我刚刚看到您发布的其他代码作为答案(来自您的cleanup()
方法):
//clear map
for (String s : map.keySet()) {
map.remove(s);
}
map = null;
//clear newMap
for (String s : newMap.keySet()) {
newMap.remove(s);
}
newMap = null;
此代码为您提供ConcurrentModificationError
的原因是foreach循环不支持修改您正在迭代的集合。
要解决此问题,您可以使用迭代器:
//clear map
Iterator<Map.Entry<String, HashSet<Text>>> iter1 = map.entrySet ().iterator ();
while (iter1.hasNext()) {
Map.Entry<String, HashSet<Text>> entry = iter1.next();
iter1.remove();
}
map = null;
//clear newMap
Iterator<Map.Entry<String, HashSet<Text>>> iter2 = newMap.entrySet ().iterator ();
while (iter2.hasNext()) {
Map.Entry<String, HashSet<Text>> entry = iter2.next();
iter2.remove();
}
newMap = null;
那就是说,你真的不必单独删除每个项目。 你可以简单地写
map = null;
newMap = null;
当您删除对地图的引用时,垃圾收集器可以对它们进行垃圾收集。从地图中删除项目没有任何区别。