Hadoop in Action簡單筆記(一)

轉載請標明出處: http://fuliang.iteye.com/blog/1136669

第一部分 Hadoop 分佈式的編程框架

第一章 Hadoop 簡介
1、philosophy: move-code-to-data,適合數據密集性應用。
2、SQL database VS Hadoop:
1) SCALE-OUT INSTEAD VS SCALE-UP
2) Key/value對 VS 關係表:無結構、半結構數據 VS 結構化的數據
3)函數式編程(MapReduce) VS 聲明式編程(SQL):hive can map the sql to the job
4)離線批處理 VS 在線事務處理
3、理解MapReduce
1)2個階段:
map:轉換+過濾數據: <k1, v1> -> list(<k2, v2>)
reduce:<k2, list(v2)> -> list(<k3, v3>)
map和reduce之間按照key進行group,hadoop負責處理、只需要寫map和reduce程序
2)word count 例子


第二章 Starting Hadoop
1、Blocks of Hadoop:
NameNode: Master, bookkeeper of the HDFS,keeps track of how your fi les are broken down into file blocks, which nodes store those blocks, and the overall health of the distributed filesystem
內存、I/O密集型。單點,但SNN可以作爲master的備用

DataNode: Slave of the HDFS, 存儲數據的節點、冗餘備份、向NameNode報告本地數據的變化。

Secondary NameNode(SNN):作爲master的備用節點、獲得NameNode的HDFS元數據的快照、集羣的配置

JobTracker:分配提供的job成爲多個task,監控各個task,檢測各個task的心跳,重啓動失敗的任務。計算中的master

TaskTracker:負責執行JobTracker分配的單個任務,像JobTracker發送心跳信息。每個DN節點一個TaskTracker,但它可以創建多個jvm實例,並行的處理多個map和reduce的任務。
計算中的slave

2、安裝Hadoop
三種模式: Local (standalone) mode、Pseudo-distributed mode、Fully distributed mode

3、Web-based cluster UI查看節點和job的信息


第三章 Hadoop各個組件
這章主要從程序員的角度介紹了Hadoop的計算框架。
3.1 在HDFS文件系統下工作
HDFS是爲分佈式計算框架設計的大規模的分佈式數據處理而設計的。
Hadoop shell提供了很多類似Unix的命令行工具,是HDFS系統的主要接口。
Hadoop也提供了HDFS的編程接口。

3.1.1基本的文件命令
基本形式: hadoop fs -cmd <args>
hadoop fs -ls
hadoop fs -lsr #相當於linux 的ls -r
hadoop fs -put example.txt . #將example.txt從本地文件系統copy到HDFS上。
hadoop fs -get example.txt . #從HDFS將example get到本地
hadoop fs -cat example.txt #相當於linux的cat
hadoop fs -tail example.txt #linux tail
可以結合Unix管道:
hadoop fs -cat example.txt | head -n 10
hadoop fs -rm example.txt #linux rm
查看幫助,比如ls的幫助:
hadoop fs -help ls

可以使用URI來制定精確的文件和目錄位置:
hadoop fs -cat hdfs://localhost:9000/user/chunk/example.txt
如果處理本地文件系統,那麼可以通過配置fs.default.name來配置默認的file://scheme部分。

<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>

這樣就可以直接hadoop fs -cat /user/chunk/example.txt

3.1.2編程的方式讀寫HDFS
Java編程方式操作HDFS,主要在org.apache.hadoop.fs包下面。Hadoop文件操作主要包括:
打開、讀、寫、關閉,不僅可以操作HDFS,也可以操作本地普通的文件系統。

FileSystem:是文件系統的交互的一個抽象類,有很多具體的子類來處理HDFS和本地文件系統。可以使用:FileSystem.get(Configuration conf)這個工廠來創建期望的實例。
Configuration:只有key/value配置參數的類。默認的配置是基於HDFS系統的資源配置的。

Configuration conf = new Configuration();
FileSystem hdfs = FileSystem.get(conf);

FileSystem.getLocal(Configuration conf)可以創建一個針對本地的文件系統。

Path: 文件和目錄的名字
FileStatus: 文件和目錄的元數據信息

FileSystem local = FileSystem.getLocal(conf);
Path inputDir = new Path(args[0]);
FileStatus[] inputFiles = local.listStatus(inputDir);


FSDataInputStream:

FSDataInputStream in = local.open(inputFiles[i].getPath());
byte buffer[] = new byte[256];
int bytesRead = 0;
while( (bytesRead = in.read(buffer)) > 0 ){
//...
}
in.close();

FSDataInputStream是java DataInputStream的子類,支持隨機訪問.

FSDataOutputStream:與FSDataInputStream相對應的輸出流:

Path hdfsFile = new Path(args[1]);
FSDataOutputStream out = hdfs.create(hdfsFile);
out.write(buffer,o,bytesRead);
out.close();


3.2 一個MapReduce程序剖析
Map Reduce數據流:
[img]http://fuliang.iteye.com/upload/picture/pic/96422/4faccd48-8d09-3565-b165-5593ea63d842.jpg[/img]

3.2.1 Hadoop數據類型
MapReduce的key,value不能是普通的class,它需要key/value實現序列化的方法,
key還需要具有可比較性。所以MapReduce對基本類型進行了封裝。
一般key/value會實現WritableComparable<T>接口,value會Writable接口。
Hadoop預定義了一些對基本類型封裝的類型:BooleanWritable,ByteWritable,
DoubleWritable,FloatWritable,IntWritable,LongWritable,Text,NullWritable。
你可以自己定義類型,實現Writable或者WritableComparable接口。

3.2.2 Mapper
作爲一個Mapper,一般實現了Mapper接口並且繼承了MapReduceBase類。MapReduceBase從名字可以看出,作爲Mapper和Reducer的基類。
有兩個方法作爲構造和析構:
void configure(JobConf job) 在數據處理之前調用,加載配置項
void close() 在map任務結束調用,進行資源回收,比如數據庫連接、打開文件關閉。

Mapper接口負責數據處理階段,他有一個map方法,來處理key/value對:

void map(K1 key, V1 value, OutputCollector<K2,V2> output,Reporter reporter)
throws IOException

這個方法給定輸入(k1,v1)得到list(k2,v2)
OutputCollector接受mapper過程的結果,Reporter記錄了任務進度的相關信息。
Hadoop預定義了一些Mapper:
IdentityMapper<K,V>: 實現了Mapper<K,V,K,V> 將輸入直接映射爲輸出
InverseMapper<K,V>:實現了Mapper<K,V,V,K> 逆置key/value對
RegexMapper<K>: 實現了Mapper<K,Text,Text,LongWritable>,對匹配的項生成(match,1)對
TokenCount<K>: 實現了Mapper<K,Text,Text,LongWritable>,生成(token,1)對

3.2.3 Reducer
Reducer和Mapper一樣都繼承了MapReduceBase類,同時還實現了Reducer接口,它包含了
單個方法:

void reduce(K2 key,Iterator<V2> values,OutputCollector<K3,V3> output,
Reporter reporter) throws IOException

Reducer接受到各個mapper的輸出,將key/value對按照key進行排序然後按照key進行分組。
然後調用reduce函數。OutputCollection接收reduce過程的輸出,並將輸出寫入文件中。
Reporter記錄了reducer任務的進度的額外信息。

Hadoop默認實現了一些Reducer:
IdentityReducer<K,V>:實現了Reducer<K,V,K,V> 將輸入直接映射爲輸出。
LongSumReducer<K>: 實現了Reducer<K,LongWritable,K,LongWritable>,計算出一個key所有value的和。

3.2.4 劃分--將Mapper的輸出重定向
一個常見的誤解是,MapReduce程序只有一個Reducer。
有多個Reducer就需要將mapper的輸出正確的發送的某個Reducer上。默認的是將key進行hash
然後決定輸出到哪個Reducer上,Hadoop提供了HashPartitioner類。
有時候我們需要自定義Partitioner,需要實現configure() 和
getPartition()方法,configure根據hadoop job的配置來配置partitioner,
getPartition返回分配到的reducer的號,大小從0到reducer數。

比如分析航線信息,計算從離開飛機場乘客的數量。
[quote]
(San Francisco, Los Angeles) Chuck Lam
(San Francisco, Dallas) James Warren
...
[/quote]
我們實現EdgePartitioner:

public class EdgePartitioner implements Partitioner<Edge, Writable>
{
@Override
public int getPartition(Edge key, Writable value, int numPartitions)
{
return new Long(key.getDepartureNode()).hashCode() % numPartitions;
}
@Override
public void confi gure(JobConf conf) { }
}


3.2.5 組合--本地reducer
很多MapReducer程序,在分發mapper結果之前希望進行一次本地的Reducer操作。
比如WordCount的例子,如果一個job處理一個文檔包含 the 574詞,存儲和shuffle (the,574)一次要比多次(the,1)要高效。

3.2.6 Word Counting和預定義的Mapper和Reducer類
使用hadoop預定義的TokenCountMapper和LongSummReducer類重寫r了WordCount例子。

3.3 讀和寫
MapReduce需要讀取輸入的數據,寫輸出的數據,所以文件的格式需要關注。hadoop提供了
靈活的處理各種數據格式的方法。
每個split大小要合適,既要足夠小,提供並行處理能力,又不能太小,以至於啓動和停止的時間佔了大部分。
Hadoop的FSDataInputStream具有隨機讀的能力,所以能夠有效的定位到文件split的位置。

Hadoop提供一些數據格式,你還可以自定義格式。

3.3.1 輸入格式:
InputFormat接口:所有的實現輸入文件split up供hadoop讀取實現的接口。

TextInputFormat: 默認的InputFormat實現類。這對於沒有定義key的,但是想一行一行處理的數據來說非常有用。每一行一條記錄
key: 當前行的byte offset, LongWritable
value:當前行,Text。

KeyValueTextInputFormat: 每行一條記錄,第一個分隔符將一行分開,
key: 分割符之前的部分,Text
value: 分割符之後的部分,Text

SequenceFileInputFormat<K,V>: 一種對於一個MapReduce job是另一個MapReduce輸入的一種優化的格式:
key: K用戶定義
value: V用戶自定義

NLineInputFormat: 和TextInputFormat類似,每個split保證含有N行,mapred.line.input.format.linespermap屬性,默認是1,設置了N
key: LongWritable
value: Text

你可以在配置輸入使用的格式:
conf.setInputFormat(KeyValueTextInputFormat.class);

創建自定義的輸入格式:
有時候hadoop提供的標準的幾個輸入格式不能滿足要求,需要自定義。InputFormat接口
包含了兩個方法:

public interface InputFormat<K,V>{
InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;
RecordReader<K,V> getRecordReader(InputSplit split,
JobConf job,
Reporter reporter) throws IOException;
}

這兩個方法提供的功能:
1.將輸入數據分成輸入的split,每一個map任務處理一個split
2.提供迭代給定split的每個記錄的能力,並且能夠將每個記錄解析成預定義類型的key和value。

一般繼承FileInputFormat,它實現了getSplits方法,但沒有實現getRecordReader,FileInputFormat還提供了一些protected的方法,供子類覆寫。
比如isSplitable(FileSystem fs, Path filename),它檢查是否可以將一個文件分塊。
有些壓縮文件和其他的文件需要將一個文件視爲原子記錄,那麼可以覆寫,返回false。

使用了FileInputFormat之後,需要關注的就是自定義RecordReader:

public interface RecordReader<K,V>{
boolean next(K key, V value) throws IOException;

K createKey();
V createValue();
long getPos() throws IOException;
void close() throws IOException;
float getProgress() throws IOException;
}

Hadoop有一些實現好的RecordReader,比如LineRecordReader<LongWritable,Text>
它在TextInputFormat被使用,KeyValueLineRecordReader在KeyValueTextInputFormat被使用。

3.3.2 輸出格式。
和InputFormat對應,輸出有OutputFormat類,輸出沒有splits,每個reducer寫入自己的文件。
Hadoop提供了一些預定義的輸出格式實現,可以通過JobConf的setOutputFormat來指定。
TextOutputFormat<K,V> 將每個記錄寫成一行,key和value用\t分割,可以在mapred.textoutputformat.separator中指定分隔符。
SequenceFileOutputFormat<K,V> 將key/value寫入hadoop的sequence 文件格式。和
SequenceFileInputFormat對應。

NullOutputFormat<K,V> 不輸出。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章