Несколько выходов в hadoop
Я использую MultipleOutputs в моей программе сокращения моей фазы сокращения. Набор данных, над которым я работаю, составляет около 270 МБ, и я запускаю его на своем псевдораспределенном одном узле. Я использовал пользовательские записи для выходных значений моей карты. ключи - это страны, представленные в наборах данных.
public class reduce_class extends Reducer<Text, name, NullWritable, Text> {
public void reduce(Text key,Iterable<name> values,Context context) throws IOException, InterruptedException{
MultipleOutputs<NullWritable,Text> m = new MultipleOutputs<NullWritable,Text>(context);
long pat;
String n;
NullWritable out = NullWritable.get();
TreeMap<Long,ArrayList<String>> map = new TreeMap<Long,ArrayList<String>>();
for(name nn : values){
pat = nn.patent_No.get();
if(map.containsKey(pat))
map.get(pat).add(nn.getName().toString());
else{
map.put(pat,(new ArrayList<String>()));
map.get(pat).add(nn.getName().toString());}
}
for(Map.Entry entry : map.entrySet()){
n = entry.getKey().toString();
m.write(out, new Text("--------------------------"), key.toString());
m.write(out, new Text(n), key.toString());
ArrayList<String> names = (ArrayList)entry.getValue();
Iterator i = names.iterator();
while(i.hasNext()){
n = (String)i.next();
m.write(out, new Text(n), key.toString());
}
m.write(out, new Text("--------------------------"), key.toString());
}
m.close();
}
}
выше моя логика сокращения
проблемы
1) приведенный выше код прекрасно работает с небольшим набором данных, но не работает из-за пространства кучи с набором данных 270 МБ.
2) Использование страны в качестве ключа передает довольно большие значения в одну итеративную коллекцию. Я пытался решить эту проблему, но MutlipleOutputs создает уникальные файлы для данного набора ключей. Дело в том, что я не могу добавить уже существующий файл, созданный предыдущим запуском метода Reduce and throws error. таким образом, для определенных ключей я должен создать новые файлы. Есть ли способ обойти это?, Решение вышеуказанной ошибки заставило меня определить ключи как названия стран (мои последние отсортированные данные), но выдает ошибку кучи Java.
Пример ввода
3858241,"Durand","Philip","E.","","","Hudson","MA","US","",1 3858241,"Norris","Lonnie","H.","","","Milford","MA","US","",2 3858242,"Gooding","Elwyn","R.","","120 Darwin Rd.","Pinckney","MI","US","48169",1 3858243,"Pierron","Claude","Raymond","",","Epinal","","FR","",1 3858243,"Дженни", "Джин", "Пол","","","Decines","","FR","",2 3858243,"Zuccaro","Robert","","","","Epinal","","FR","",3 3858244,"Mann","Richard","L.","","PO Box 69","Woodstock","CT","США","06281",1
Пример вывода для небольших наборов данных
пример структуры каталогов...
CA-R-00000
FR-т-00000
Квебек-т-00000
TX-т-00000
США-т-00000
*Индивидуальное содержание*
3858241 Филип Э. Дюран
Лонни Х. Норрис
3858242
Элвин Р. Гудинг
3858244
Ричард Л. Манн
1 ответ
Я знаю, что отвечаю на очень старый вопрос здесь, но в любом случае позвольте мне высказать некоторые идеи здесь. Кажется, вы создаете TreeMap в своем редукторе со всеми записями, которые вы получаете за один вызов сокращения. В Mapreduce вы не можете позволить себе хранить все записи в памяти, потому что они никогда не масштабируются. Вы делаете карту patent_no
и все names
связано с этим patent_no
, Все, что вы хотите, это выделить записи на основе patent_no
, так почему бы не использовать сортировку структуры mapreduce.
Вы должны включить patent_no
а также name
вместе с country
в самом доступном для записи ключе.
- Пиши свой
Partitioner
разделять только на основеcountry
, - Сортировка должна быть включена
country
,patent_no
,name
, - Вы должны написать свой
Grouping comparator
группировать поcountry
,patent_no
,
В результате все записи с одинаковыми country
будет идти к тому же редуктору и отсортированы по patent_no
а также name
, И в пределах одного и того же редуктора разные патентные номера будут отправляться на разные вызовы сокращения. Теперь все, что вам нужно, это просто написать это в MultipleOutputs. Таким образом вы избавитесь от любого в памяти TreeMap.
И некоторые моменты, о которых я бы посоветовал вам позаботиться:
- Не создавать
new MultipleOutputs
в методе Reduce каждый раз вместо этого вы должны написатьsetup()
метод и создать только один вsetup()
метод. - Не создавать
new Text()
каждый раз вместо этого создайте один в методе установки и повторно используйте тот же экземплярset("string")
методText
, Вы можете утверждать, что в этом смысл, GC Java все равно будет собирать мусор. Но вы всегда должны стараться использовать как можно меньше памяти, чтобы сборщик мусора Java вызывался реже.