天天看點

《Hadoop與大資料挖掘》一2.6.3 Hadoop TF-IDF程式設計實作

本節書摘來華章計算機《hadoop與大資料挖掘》一書中的第2章 ,第2.6.3節,張良均 樊 哲 位文超 劉名軍 許國傑 周 龍 焦正升 著 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

這裡給出的tf-idf算法的測試資料使用的是avro格式的。這裡隻對avro進行簡單介紹,如讀者需要深入了解,可以上網查找相關資料。

avro簡介

avro是一個資料序列化的系統,它可以将資料結構或對象轉化成便于存儲或傳輸的格式。avro設計之初就用來支援資料密集型應用,适合于遠端或本地大規模資料的存儲和交換。

avro依賴于模式(schema)。通過模式定義各種資料結構,隻有确定了模式才能對資料進行解釋,是以在資料的序列化和反序列化之前,必須先确定模式的結構。

《Hadoop與大資料挖掘》一2.6.3 Hadoop TF-IDF程式設計實作

schema通過json對象表示。schema定義了簡單資料類型和複雜資料類型,其中複雜資料類型包含不同屬性。通過各種資料類型使用者可以自定義豐富的資料結構。

avro定義了幾種簡單資料類型,表2-10是對其簡單說明。

《Hadoop與大資料挖掘》一2.6.3 Hadoop TF-IDF程式設計實作
《Hadoop與大資料挖掘》一2.6.3 Hadoop TF-IDF程式設計實作

avro定義了6種複雜資料類型,分别是record、enum、array、map、union和fixed,每一種複雜資料類型都具有獨特的屬性。表2-11就record這一種複雜資料類型進行了簡要說明(後面也隻會用到這種資料類型)。

《Hadoop與大資料挖掘》一2.6.3 Hadoop TF-IDF程式設計實作

(1)動手實踐:java基于avro的序列化和反序列化

簡單來說,avro就是提供一個資料檔案的說明文檔,然後可以直接根據該說明文檔進行序列化和反序列化的一個架構而已。

舉個例子,比如現在有一個資料描述檔案,如代碼清單2-46所示。

有定義一個java類和該描述檔案比對,如代碼清單2-47所示。

代碼清單2-46中的name:user或者name:name、name:favorite_number等,不需要與代碼清單2-47中的名字user類或者方法setname、setfavoritecolor名字一模一樣,隻需一一對應即可。

那麼怎麼進行序列化呢?參考代碼清單2-48,即可把使用者user1、user2、user3序列化到本地磁盤的users.avro檔案。

如何進行反序列化呢?參考代碼清單2-49,即可把序列化後的users.avro檔案内容讀取出來了,并且代碼清單2-49中的代碼還把檔案内容也列印出來了。

參考上面的示例,進行下面的實驗。

實驗步驟如下:

1)建立java工程,引入avro-1.7.4.jar、avro-tools-1.7.4.jar(非必需)、jackson-core-asl-1.9.13.jar、jackson-mapper-asl-1.9.13.jar、junit-4.11.jar、hamcrest-core-1.3.jar。

2)參考代碼清單2-46、代碼清單2-47、代碼清單2-48、代碼清單2-49,縮寫對應程式實作,運作程式檢視結果。

(2)動手實踐:hadoop基于avro的反序列化

這裡增加一點hadoop job counter的知識,hadoop job counter可以在hadoop map-reduce程式運作的過程中定義全局計數器,對一些必要的參數進行統計,通過doc api檢視該用法,如圖2-54所示。

《Hadoop與大資料挖掘》一2.6.3 Hadoop TF-IDF程式設計實作

在java代碼中周遊所有hadoop mapreduce counter,可參考代碼清單2-50。

1)拷貝avro-mapred-1.7.4-hadoop2.jar到hadoop叢集lib目錄,上傳hadoop/data/mann.avro資料到hdfs。

2)設定讀取avro檔案的fileinputformat為avrokeyinputformat。

3)參考示例程式2.5_004_avro_mr,讀懂程式代碼,運作程式,檢視結果。

job1:統計單個檔案某個單詞個數

針對2.6.2節分析的hadoop mapreduce實作tf-idf的流程中的job1,分析如下。

驅動程式driver:隻需要設定mapper以及reducer,需要注意這裡的輸入需要使用avrokeyinputformat,這裡考慮到程式設計友善以及效率,輸出使用sequencefileoutput-format,如代碼清單2-51所示。

mapper要做的工作隻是讀取avro資料,然後針對資料分隔各個單詞(注意這裡有些單詞是不需要進行統計的,可以直接忽略)。mapper的功能描述如下:

1)讀取avro格式資料,擷取檔案名和檔案内容(類似java單機程式),如代碼清單2-52所示。

2)分隔檔案的内容,這裡需要注意不用統計的單詞,具體單詞如代碼清單2-53所示。

分隔采用match類正則進行分隔,如代碼清單2-54所示。

3)隻須輸出單詞、檔案名和計數1即可,如代碼清單2-55所示。

reducer類直接采用hadoop内部類intsumreducer即可,即把相同的key的所有value值全部加起來,其輸入輸出描述如表2-12所示。

job2:統計某個檔案所有單詞個數

job2的driver驅動程式是統計某個檔案的所有單詞個數,輸入是job1的輸出,是以輸入格式為sequencefileinputformat,輸出格式也設成sequencefileoutputformat,友善job3的讀取,其設定參考代碼清單2-56。

mapper類隻需把job1的輸出的鍵值對進行重構即可,這裡即可以利用mapreduce按照key進行分組的特性,輸出<檔案名,檔案中的單詞|檔案中單詞的個數>這樣的鍵值對,如代碼清單2-57所示。

在reucer中利用分組的特性(每個鍵值對按照鍵進行分組,是以會得到每個檔案的所有單詞作為一個清單),統計每個檔案的所有單詞個數,如代碼清單2-58所示。

job3:計算單個檔案某個單詞的tf-idf

job3綜合前面兩個的輸出結構,得到最終每個檔案每個單詞的tf-idf值。driver需要配置輸入輸出以及格式,這裡注意需要把job1統計的總檔案個數傳入job3中,這裡為了便于觀察,輸出格式使用預設值textfileoutputformat,其示例代碼如代碼清單2-59所示。

mapper類根據job2的輸入進行重構,再次使用word作為key,使用filename、word-count、sumofwordsindoc作為value,如代碼清單2-60所示。

reducer根據mapper的輸出,同時利用相同的key聚合的特性,即可統計出每個單詞在多少個檔案中存在;在所有需要的參數計算完成後,即可利用tf-idf的公式進行最後的計算,如代碼清單2-61所示。

(1)動手實踐:hadoop實作tf-idf算法

了解上面hadoop mapreduce架構實作tf-idf算法的原理,結合部分示例代碼,完成該動手實踐。

1)參考“動手實踐:hadoop基于avro的反序列化”内容,建立程式開發環境(主要是avro相關開發包);

2)參考工程2.5_005_tf-idf示例代碼,結合前面的分析,了解代碼功能;

3)修複工程功能(todo提示),運作程式;

4)檢視輸出,對結果進行解釋。

(2)思考

請讀者思考,針對hadoop mapreduce實作tf-idf算法是否還有優化的空間?如果有優化的空間,怎麼做呢?可以考慮下面幾點:

1)是否可以縮減job的個數?(提示:輸出多目錄、自定義鍵值對)

2)如果使用自定義鍵值對技術,應該如何修改程式?

繼續閱讀