文章目录
1. SequenceFile概述
- SequenceFile是Hadoop提供的一种对二进制文件的支持,二进制文件直接将<Key, Value>对序列化到文件中。
- HDFS文件系统是适合存储大文件的,小文件多的话会对NN造成很大的压力,因为每一个文件都会有一条元数据信息存储在NN上,所以可以通过SequenceFile将小文件合并起来,可以更高效率的存储和计算。
- SequenceFile中的key和value可以是任意类型的Writable或者自定义的Writable类型。
- SequenceFile文件并不按照其存储的Key进行排序存储,SequenceFile的内部类Writer提供了append功能。
- 在存储结构上,SequenceFile主要由一个Header后跟多条Record组成,Header主要包含了,key和value的类名,存储压缩算法,用户自定义元数据等信息。此外,还包含了一些同步标识,用于快速定位到记录的边界。每条Record以键值对的方式进行存储,用来表示它的字符数组可以一次解析成:记录的长度、Key的长度、Key值和value值,并且Value值的结构取决于该记录是否被压缩。
2. SequenceFile优缺点介绍
2.1 SequenceFile优点
2.1.1 支持压缩
- 记录(Record)压缩
记录压缩格式与无压缩格式基本相同,不同的是值字节是用定义在头部的编码器来压缩。
- 块(Block)压缩
块压缩一次压缩多个记录,因此它比记录压缩更紧凑,而且一般优先选择。当记录的字节数达到最小大小,才会添加到块。该最小值由io.seqfile.compress.blocksize中的属性定义。默认值是1000000字节。格式为记录数、键长度、键、值长度、值。
- 无压缩类型
如果没有启动压缩(默认设置),那么每个记录就由它的记录长度(字节数)、键的长度、键和值组成,长度字段为4个字节。
下图为SequenceFile内部结构图:
Record针对压缩,只压缩Value部分不压缩key;Block对Key和Value都压缩。
2.1.2 本地化任务支持
因为文件可以被切分,因此在运行MapReduce任务时数据的本地化情况应该是非常好的,尽可能多地发起Map Task来进行并行处理进而提高作业的执行效率。
2.1.3 难度低
因为Hadoop框架提供API,业务逻辑的修改比较简单。
2.2 SequenceFile缺点
需要一个合并文件的过程,且合并后的文件不方便查看。
3. SequenceFile写操作
3.1 写操作实现步骤
- 设置Configuration
- 获取FileSystem
- 设置文件输出路径
- SequenceFile.createWriter()创建SequenceFile.Write写入
- 调用SequenceFile.Write.append追加写入
- 关闭流
3.2 写操作代码实现
前面提到过的VM options参数,继续设置上。
代码实现:
package Sequence;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Text;
import java.net.URI;
public class SequenceFileWriter {
private static Configuration configuration = new Configuration();
private static String HDFS_PATH = "hdfs://master002:9000";
private static String[] data = {"a,b,c,d,e,f,g","e,f,g,h,j,k","l,m,n,o,p,q,r,s","t,y,v,w,x,y,z"};
public static void main(String[] args) throws Exception {
System.setProperty("HADOOP_USER_NAME", "hadoop");
FileSystem fileSystem = FileSystem.get(URI.create(HDFS_PATH), configuration);
Path outputPath = new Path("MySequenceFile.seq");
IntWritable key = new IntWritable();
Text value = new Text();
SequenceFile.Writer writer = SequenceFile.createWriter(fileSystem, configuration,
outputPath, IntWritable.class, Text.class);
for(int i=0;i<10;i++){
key.set(10-i);
value.set(data[i%data.length]);
writer.append(key, value);
}
IOUtils.closeStream(writer);
}
}
效果截图:
4.SequenceFile读操作
4.1 读操作实现步骤
- 设置Configuration
- 获取FileSystem
- 设置文件输出路径
- 调用SequenceFile.Reader()创建读取类SequenceFile.Reader
- 拿到Key和value的class
- 读取
- 关闭流
4.2 读操作代码实现
代码实现:
package Sequence;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.util.ReflectionUtils;
import java.net.URI;
public class SequenceFileReader {
private static Configuration configuration = new Configuration();
private static String HDFS_PATH = "hdfs://master002:9000";
public static void main(String[] args) throws Exception{
System.setProperty("HADOOP_USER_NAME", "hadoop");
FileSystem fileSystem = FileSystem.get(URI.create(HDFS_PATH), configuration);
Path inputPath = new Path("MySequenceFile.seq");
SequenceFile.Reader reader = new SequenceFile.Reader(fileSystem, inputPath, configuration);
Writable keyClass = (Writable) ReflectionUtils.newInstance(reader.getKeyClass(), configuration);
Writable valueClass = (Writable) ReflectionUtils.newInstance(reader.getValueClass(), configuration);
while(reader.next(keyClass, valueClass)){
System.out.println("key:"+keyClass);
System.out.println("value:"+valueClass);
System.out.println("position:"+reader.getPosition());
}
IOUtils.closeStream(reader);
}
}
效果截图:
5. SequenceFile写操作使用压缩
SequenceFile写操作的压缩支持Record和Block两种,在读取时能够自动解压。
代码实现:
package Sequence;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.*;
import org.apache.hadoop.io.compress.BZip2Codec;
import org.apache.hadoop.util.ReflectionUtils;
import java.net.URI;
public class SequenceFileCompression {
private static Configuration configuration = new Configuration();
private static String HDFS_PATH = "hdfs://master001:9000";
private static String[] data = {"a,b,c,d,e,f,g","e,f,g,h,j,k","l,m,n,o,p,q,r,s","t,y,v,w,x,y,z"};
public static void main(String[] args) throws Exception {
System.setProperty("HADOOP_USER_NAME", "hadoop");
FileSystem fileSystem = FileSystem.get(URI.create(HDFS_PATH), configuration);
Path outputPath = new Path("MySequenceFileCompression.seq");
IntWritable key = new IntWritable();
Text value = new Text();
SequenceFile.Writer writer = SequenceFile.createWriter(fileSystem, configuration, outputPath,
IntWritable.class, Text.class, SequenceFile.CompressionType.RECORD, new BZip2Codec());
for(int i=0;i<10;i++){
key.set(10-i);
value.set(data[i%data.length]);
writer.append(key, value);
}
IOUtils.closeStream(writer);
Path inputPath = new Path("MySequenceFileCompression.seq");
SequenceFile.Reader reader = new SequenceFile.Reader(fileSystem, inputPath, configuration);
Writable keyClass = (Writable) ReflectionUtils.newInstance(reader.getKeyClass(), configuration);
Writable valueClass = (Writable)ReflectionUtils.newInstance(reader.getValueClass(), configuration);
while(reader.next(keyClass, valueClass)){
System.out.println("key:"+keyClass);
System.out.println("value:"+valueClass);
System.out.println("position:"+reader.getPosition());
}
IOUtils.closeStream(reader);
}
}
效果截图: