将Hadoop中SequenceFile,MapFile转换为文本文件

7 篇文章 0 订阅
6 篇文章 0 订阅

前段时间一直在准备实习的事情,没有更新项目相关的博客。最近才通过了百度的实习生面试,面试的时候这个小项目助力不少,所以又想来补充一下前面没有分享的一些项目经验。

Hadoop输入输出格式

Hadoop中mapper的输入必须是(key, value)格式的。若输入文件类型为文本格式,这也是默认的输入文件类型。则key是行号,value就是这一行对应的文本。
同理reducer输出的默认格式也是文本,输出的key,value为一行,中间用制表符隔开。
同时,hadoop也提供了更改输入输出格式的接口。比如更改输出为hadoop支持的MapFile可使用以下语句:

job.setOutputFormatClass(MapFileOutputFormat.class);

Hadoop的文件格式

Hadoop有两种基本的存储(key, value)文件格式,分别是SequenceFile和MapFile。

SequeceFile

每一行就是key,value,顺序存储,没有排序。

MapFile

其中包括两个SequenceFile文件,命名为data和index。
注意其中data是按照key排好序的顺序文件,排序主要是为了方便直接根据key二分查找小于等于它的最后一个key的位置。因为一般文件都会很大,所以要把所有key存入内存再二分显然是不太可能的。
因此需要对key进行抽取,hadoop默认是每隔128个key提取一个,然后把它放入index文件,index中的key就是从data中提取的key,value就是这个key在data文件中的位置。
查找的时候,把index放入内存,找出对应的key,然后再在data文件中相应位置及其后面127个key中找到对应的key。

文件格式转换

Nutch输出的链接以及url的文本信息,都是MapFile格式,为了减少耦合或者更利于mapper输入,我们把它转换成text。

package SearchPackage;

import java.io.IOException;
import java.net.URI;

import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.MapFile;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.util.ReflectionUtils;
import org.apache.hadoop.io.IOUtils;

public class MapFileRead {

  private static MapFile.Reader reader = null;
  private static Configuration conf = null;
  private static FileSystem fs = null;
  private static Path path = null;

  public MapFileRead(String uri) throws IOException{
  //构造函数,便于在其它需要读取MapFile的程序中在开始阶段就新建一个reader接口
    this.conf = new Configuration();
    this.fs = FileSystem.get(URI.create(uri), conf);
    this.path = new Path(uri);
    this.reader = new MapFile.Reader(fs, uri, conf);
  }

  public static double getValue(String url) throws IOException{
   //读取上次计算的pageRank值时会不断调用此函数
    DoubleWritable value = new DoubleWritable(0);

    try {
      reader.get(new Text(url), value);
    }   
    finally {
      if(value == null) {
        return 0;
      }
      return value.get();
    }
  }

  public static void main(String[] args) throws IOException {
    //当以主程序运行时,为读取MapFile再输出重定向到文本即可
    String uri = args[0];
    conf = new Configuration();
    fs = FileSystem.get(URI.create(uri),conf);
    path = new Path(uri); 
    try {
      reader = new MapFile.Reader(fs, uri, conf);
      WritableComparable key = (WritableComparable) ReflectionUtils.newInstance(reader.getKeyClass(),conf);
      Writable value = (Writable) ReflectionUtils.newInstance(reader.getValueClass(),conf); 
      while(reader.next(key,value)) {
        System.out.printf("%s\t%s\n", key, value);
      }
     } 
      finally {
        IOUtils.closeStream(reader);
      } 
  }
}

以上代码,当直接运行main函数时,会读取mapFile并输出。更重要的是,当新建此类后,可以方便随机读取我们想要的key,value。比如在计算pageRank,迭代时我们需要url上次的pageRank值,这个时候我们就可以把pageRank的输出设置为MapFile格式,在下次运行时新建一个MapFile.Reader,就可以方便地根据url读取它的pageRank值。
实际运行发现这个读取的效率还是不够理想,在面试的时候面试官也提到了,其实更简单的方法是直接把pageRank值放在url的旁边,但是这需要一定的预处理或者脚本处理,在接下来的改进中可以考虑加入。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值