2013-09-25 3 views
0

Я хочу использовать HashSet, который существует/работает против одного файла во время его сопоставления, а затем сбрасывается/воссоздается при сопоставлении следующего файла. Я изменил TextInputFormat, чтобы переопределить isSplitable, чтобы вернуть false, чтобы файл не был разделен и обрабатывается в целом Mappers. Можно ли сделать что-то подобное? Или есть другой способ сделать меньше записей в таблице Accumulo?Можно ли связать экземпляр объекта с одним файлом, пока он отображается на карте, только отображаемый объект Job?

Позвольте мне начать с того, что я не верю, что хочу глобальную переменную. Я просто хочу обеспечить уникальность и, таким образом, записать меньше мутаций в таблицу Accumulo.

Мой проект состоит в том, чтобы преобразовать функциональность файла Index.java из примера shard из линейной клиентской программы накопителя в ту, которая использует функциональность mapreduce, при этом создавая ту же таблицу в Accumulo. Это должно быть mapreduce, потому что это модное слово, и по существу оно будет работать быстрее, чем линейная программа против терабайт данных.

Вот код индекса для справки: http://grepcode.com/file/repo1.maven.org/maven2/org.apache.accumulo/examples-simple/1.4.0/org/apache/accumulo/examples/simple/shard/Index.java

Этой программа использует BatchWriter писать Мутации в 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 сверху. Если это так, мне просто нужно найти решение для уникальности.

Любая помощь или консультация предоставляются с благодарностью.

ответ

1

Mapper имеет setup и cleanup методы, которые вы можете переопределить, чтобы обрабатывать такие вещи более чисто. setup вызывается один раз, затем map вызывается много раз (один раз для каждой записи), затем cleanup вызывается один раз в конце. Идея заключалась бы в том, что вы создаете HashSet в методе setup, создаете его в map и совершаете все в cleanup или периодически включаете в некоторые вызовы map, если необходимо.

Однако вы почти наверняка не увидите улучшения во время выполнения, пока не перейдете в настоящий кластер. Одноузловой тестовый экземпляр практически не имеет преимуществ по сравнению с простой линейной программой, за исключением того, что один и тот же код будет работать намного быстрее, как только вы получите реальный кластер.