2015-05-05 3 views
2

Я играю & learning hadoop MapReduce.hadoop mapreduce: обработка текстового файла с заголовком

Я пытаюсь отобразить данные из VCF файла (http://en.wikipedia.org/wiki/Variant_Call_Format): а VCF является табуляцией файла, начиная с (возможно большим) заголовком. Этот заголовок необходим для получения семантики записей в теле.

http://wiki.bits.vib.be/index.php/NGS_Exercise.5

Я хотел бы создать Mapper, который будет использовать эти данные. Заголовок должен быть доступен из этого Mapper для декодирования строк.

С http://jayunit100.blogspot.fr/2013/07/hadoop-processing-headers-in-mappers.html, я создал этот InputFormat, с настраиваемым чтением:

public static class VcfInputFormat extends FileInputFormat<LongWritable, Text> 
    { 
    /* the VCF header is stored here */ 
    private List<String> headerLines=new ArrayList<String>(); 

    @Override 
    public RecordReader<LongWritable, Text> createRecordReader(InputSplit split, 
      TaskAttemptContext context) throws IOException, 
      InterruptedException { 
     return new VcfRecordReader(); 
     } 
    @Override 
    protected boolean isSplitable(JobContext context, Path filename) { 
     return false; 
     } 

    private class VcfRecordReader extends LineRecordReader 
     { 
     /* reads all lines starting with '#' */ 
     @Override 
     public void initialize(InputSplit genericSplit, 
       TaskAttemptContext context) throws IOException { 
      super.initialize(genericSplit, context); 
      List<String> headerLines=new ArrayList<String>(); 
      while(super.nextKeyValue()) 
       { 
       String row = super.getCurrentValue().toString(); 
       if(!row.startsWith("#")) throw new IOException("Bad VCF header"); 
       headerLines.add(row); 
       if(row.startsWith("#CHROM")) break; 
       } 
      } 
     } 
    } 

Теперь в Mapper, есть способ, чтобы иметь указатель на VcfInputFormat.this.headerLines для того, чтобы декодировать линии?

public static class VcfMapper 
     extends Mapper<LongWritable, Text, Text, IntWritable>{ 

    public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { 
     my.VcfCodec codec=new my.VcfCodec(???????.headerLines); 
     my.Variant variant =codec.decode(value.toString()); 
     //(....) 
    } 
    } 

ответ

0

Я думаю, что ваш случай отличается от вашего примера. В этом случае заголовок используется внутри настраиваемого класса RecordReader, чтобы обеспечить одно «текущее значение», которое представляет собой строку, составленную всеми отфильтрованными словами, и которая передается преобразователю. Однако в вашем случае вы хотите использовать информацию заголовков за пределами RecordReader, то есть у вас картограф, и этого не может быть достигнуто.

Я также думаю, что вы можете имитировать поведение связанного примера, предоставляя уже обработанную информацию: читайте заголовки, сохраняя их, а затем, когда получаете текущее значение, ваш картограф может получить объект my.VcfCodec вместо объекта Text (т. е. метод getCurrentValue возвращает объект my.VcfCodec). Ваш картографа может быть что-то вроде ...

public static class VcfMapper extends Mapper<LongWritable, my.VcfCodec, Text, IntWritable>{ 
    public void map(LongWritable key, my.VcfCodec value, Context context) throws IOException, InterruptedException { 
     // whatever you may want to do with the encoded data... 
} 
+0

вы имеете в виду, что каждая строка из моего файла будет вставлять весь заголовок? – Pierre

+0

Нет, я имею в виду каждый раз, когда строка будет передана вашему картографу, она предварительно закодирована в 'RecordReader' как объект' my.VcfCodec'; это означает, что объект «Text» действительно не передается в Mapper, а вместо него - объект my.VcfCodec. Таким образом, нет необходимости в доступе и передаче заголовков к картографу, поскольку информация поступает уже в кодировщик. – frb

+0

Я отредактировал, потому что параметр 'value' в методе' map' был неправильного типа. Сожалею. – frb

0

Ваш класс входной формат отлично, так как @frb сказал класс inputformat не сможет дать дифференциацию между мета-данными и записями.

Одна мысль, что я могу предложить,

  • Объявить статические глобальные переменные в классе картографа для каждого мета собственности данных файла VCF, таких как FileFormat, дата, источник и т.д ..
  • От класс чтения VcfInputFormat, если строка начинается с '##', затем проанализируйте строку и установите значение для переменной статического переменной класса сопоставления с именем свойства в текущей строке .
  • если строка не начинается с '##' затем просто передать строку в картографа
  • В классе картографа, просто разобрать содержимое записи и получить полезные значения с помощью статических переменных представляет собой мета-данные.

надеюсь, что это помогает ..