7.4.2 MapFile类
MapFile的使用与SequenceFile类似,建立MapFile文件的程序如下:
MapFileWriteFile. java
package cn.edn.ruc.cloudcomputing.book.chapter07;
import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.*;
public class MapFileWriteFile{
private static final String[]myValue={
"hello world",
"bye world",
"hello hadoop",
"bye hadoop"
};
public static void main(String[]args)throws IOException{
String uri="你想要生成SequenceFile的位置";
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(URI.create(uri),conf);
IntWritable key=new IntWritable();
Text value=new Text();
MapFile.Writer writer=null;
try{
writer=new MapFile.Writer(conf, fs, uri, key.get
Class(),value.getClass());
for(int i=0;i<500;i++){
key.set(i);
value.set(myValue[i%myValue.length]);
writer.append(key, value);
}
}finally{
IOUtils.closeStream(writer);
}
}
}
这个程序与建立SequenceFile文件的程序极其类似,这里就不详述了。与SequenceFile只生成一个文件不同,这个程序生成的是一个文件夹。如下所示:
-rw-r—r—*supergroup 16018/user/root/MapFileOutput/data
-rw-r—r—*supergroup 227/user/root/MapFileOutput/index
其中data是存储的数据,即MapFile文件(经过排序SequenceFile文件),index就是索引了,在这个程序中,其内容如下:
0 128
128 4200
256 8272
384 12344
可以看出,索引是按每128个键建立的,这个值可以通过修改io.map.index.interval的大小来修改。key值后面是偏移量,用于记录key的位置。
读取MapFile文件的程序也很简单,其内容如下所示:
package cn.edn.ruc.cloudcomputing.book.chapter07;
import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.MapFile;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.util.ReflectionUtils;
public class MapFileReadFile{
public static void main(String[]args)throws IOException{
String uri="你想要读取的MapFile文件位置";
Configuration conf=new Configuration();
FileSystem fs=FileSystem.get(URI.create(uri),conf);
MapFile.Reader reader=null;
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);
}
reader.get(new IntWritable(7),value);
System.out.printf("%s\n",value);
}finally{
IOUtils.closeStream(reader);
}
}
}
其特别之处是,MapFile可以查找单个键所对应的value值,见下面这段话:
执行这个操作时,MapFile.Reader()需要先把index读入内存中,然后执行一个简单的二叉搜索找到数据,MapFile.Reader()在查找时,会先在索引文件中找到小于我们想要找的key值的索引key值,然后再到data文件中向后查找。
大型MapFile文件的索引通常会占用很大的内存,这时我们可以通过重设索引、增加索引间隔的方法降低索引文件的大小,但是重设索引是一个很麻烦的事情。Hadoop提供了另一个非常有效的方法,就是读取索引文件时,可以每隔几个索引key再读取索引key值,这样就可以有效地降低读入内存的索引文件的大小。至于跳过key的个数是通过io.map.index.skip来设置的。