大數據之hadoop[序列化與壓縮]

Hadoop的序列化
序列化:數據從內存中的到輸出流,比如磁盤,網絡,也就是說數據出內存的過程就是序列化的過程。
反序列化:數據從輸入流到內存緩衝區,比如從磁盤、網絡,也就是說數據進入內存的過程就是發序列化的過程,和序列化互爲逆過程。
Hadoop自定義序列化類的案例
需求:
是電信一段日誌記錄的表結構,現需要統計每一個手機號碼的upPackNum、downPackNum、upPayLoad、dwonPayLoad的分別的總和。
分析:
1、要按照手機號碼來統計上述四個值,那麼我們的k2就應該是手機號碼,類型可以是Text或者IntWritable
2、接下來要確定v2的類型
我們發現要分別統計四個值的綜合,可以有兩種方式
1°第一種方式:
將每一條記錄拼成一個字符串,用相應的分隔符分割這四個值,eg:
v2Str = upPackNum + ” ” + downPackNum + ” ” + upPayLoad + ” ” + dwonPayLoad;
這樣的話,在reducer中只需要對每一個v2Str進行解析即可獲取每一個字段的值,最後進行累加(String–>IntWritable)。
這裏必須要注意的是:解析的順序不能亂。這種方式留給大家自己來做。
2°、第二種方式:
我們可以採用面向對象的方式,因爲在java的世界中,絕大部分數據都封裝在對象裏面,我們就可以採用自定義Writable
序列化對象的方式來做,那麼怎麼來做呢?
public class MyWritable implements Writable {
write(DataoutPut out) {
…//–>將獲取的每一行數據中的這四個值寫到磁盤
}
readFields(DataInPut in) {
…//–>從磁盤中獲取write寫出去的四個值,然後加載到內存
}
}
注意:我們自定義的MyWritable並沒有事項WritableComparable接口,因爲我們在這裏確定的是v2的類型,不需要再shuffle中
進行分區比較排序,所以就不用實現WritableComparable接口!
3、輸出結果格式
手機號 upPackNum downPackNum upPayLoad dwonPayLoad
public class WritableMR {

        static class WritableMapper extends Mapper<LongWritable, Text, IntWritable, MyWritable> {
            map() {
            }
        }

        static class WritableReducer extends Reducer<IntWritable, MyWritable, IntWritable, MyWritable> {
            reduce() {
            }
        }           

}

SequenceFile2HDFS
要將普通的文本文件經過壓縮之後上傳到HDFS裏面,這是我們採用的Gzip,壓縮爲二進制的序列化sequence文件,
要使用SequenceFile提供的一個類Writer來進行寫文件的操作。
/* option數組裏面的內容
* Path name 這是壓縮輸出到hdfs上的文件路徑
* Class keyClass 壓縮後的數據key的類型
* Class valClass 壓縮後的數據value的類型
* SequenceFile.CompressionType compressionType
*/
Option outputPathOption = SequenceFile.Writer.Option.file(outpath);
Option keyClazzOption = SequenceFile.Writer.Option.keyClass(Text.class);
Option valClazzOption = SequenceFile.Writer.Option.ValueClass(NullWritable.class);
Option compressionOption = SequenceFile.Writer.Option.compression(SequenceFile.CompressionType.BLOCK, new GzipCodec());
Option[] opts = new Option[]{outputPathOption, keyClazzOption,valClazzOption, compressionOption};
SequenceFile.Writer writer = SequenceFile.Writer.createWriter(conf, opts);
BufferedReader br = new BufferedReader(new FileReader(inputpath));//inputpath是linux上面的路徑
String line = null;
Text key = new Text();
while((line = br.readLine()) != null) {
key.set(line);
writer.append(key, NullWritable.get());
}
writer.close();
br.close();
以上過程的逆過程
/**
* 將HDFS中壓縮後的額數據,讀取出來,保存成正常的沒有經過壓縮的文件到本地磁盤
*/
public class HDFS2SequenceFile {
public static void main(String[] args) throws Exception {
if(args == null || args.length < 2) {
System.err.println(“parameter errors! Useage: ”);
System.exit(-1);
}
Path inputPath = new Path(args[0]);
String outputPath = args[1];
Configuration conf = new Configuration();
//獲取hdfs中對壓縮數據讀取的輸入流SequenceFile.Reader
SequenceFile.Reader reader = new SequenceFile.Reader(conf,//制定要讀取文件的hdfs路徑
SequenceFile.Reader.file(inputPath));
Text key = new Text();
FileWriter fw = new FileWriter(new File(outputPath));//創建了一個輸出流執行本次磁盤的一個路徑
while(reader.next(key, NullWritable.get())) {//循環讀取壓縮文件到指定的key和value中
String content = key.toString();//對讀到的key和value中的數據進行提取或其他操作
fw.write(content);//將提取到的內容寫到輸出流fw中
}
fw.close();
reader.close();
}
}

發佈了251 篇原創文章 · 獲贊 66 · 訪問量 82萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章