【问题标题】:hadoop mapreduce: handling a text file with a headerhadoop mapreduce:处理带有标题的文本文件
【发布时间】:2015-05-05 12:24:12
【问题描述】:

我正在玩和学习 hadoop MapReduce。

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

我想创建一个使用这些数据的映射器。必须可以从此 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());
      //(....)
    }
  }

【问题讨论】:

    标签: java hadoop mapreduce bioinformatics vcf-variant-call-format


    【解决方案1】:

    我认为您的案例与您链接的示例不同。在这种情况下,标题在自定义RecordReader 类中使用,以提供单个“当前值”,这是由所有过滤词组成的行,并传递给映射器。但是,在您的情况下,您想使用 RecordReader 之外的标头信息,即在您的映射器中,这是无法实现的。

    我还认为您可以通过提供已处理的信息来模仿链接的示例行为:通过读取标头,存储它们,然后在获取当前值时,您的映射器可以接收 my.VcfCodec 对象而不是 @ 987654324@ 对象(即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...
    }
    

    【讨论】:

    • 你的意思是我文件中的每一行都会嵌入整个标题吗?
    • 不,我的意思是每次将一行传递给您的映射器时,它之前在RecordReader 处被编码为my.VcfCodec 对象;这意味着没有 Text 对象真正传递给 Mapper,而是 my.VcfCodec 对象。这样,就不需要访问或将标头传递给映射器,因为信息到达已经编码到映射器。
    • 我进行了编辑,因为 map 方法中的 value 参数类型错误。对不起。
    【解决方案2】:

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

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

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

    希望这会有所帮助..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多