2

我正在玩和学习 hadoop MapReduce。

我正在尝试从VCF文件 ( http://en.wikipedia.org/wiki/Variant_Call_Format ) 映射数据:VCF 是一个制表符分隔的文件,以(可能很大)标题开头。此标头是获取正文中记录的语义所必需的。

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

我想创建一个使用这些数据的映射器。必须可以从此 Mapper 访问标头才能对行进行解码。

http://jayunit100.blogspot.fr/2013/07/hadoop-processing-headers-in-mappers.html ,我创建了这个InputFormat,带有一个自定义的 Reader :

  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());
      //(....)
    }
  }
4

2 回答 2

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...
}
于 2015-05-05T12:49:02.030 回答
0

您的输入格式类很好,正如@frb 所说,输入格式类将无法区分元数据和记录。

我可以建议的一个想法是,

  • 在映射器类中为 VCF 文件的每个元数据属性(例如文件格式、日期、来源等)声明静态全局变量。
  • 从 VcfInputFormat 类中读取 lines ,如果该行开头,'##'则解析该行并根据当前行中的属性名称将值设置为映射器类的静态变量。
  • 如果该行不是以开头,'##'则只需将该行传递给映射器
  • 在映射器类中,只需解析记录内容并在静态变量的帮助下派生有用的值表示元数据。

希望这可以帮助..

于 2015-05-05T13:30:30.987 回答