標籤:
WordCount是很多分散式運算中,最常用的例子,例如Hadoop、Storm,Iveely Computing也不例外。明白了WordCount在Iveely Computing上的運行原理,就很容易寫出新的分布式程式。上一篇中已經知道了如何部署Iveely Computing以及提交任務,現在我們將深入WordCount的代碼。
一、代碼結構
圖3-1
從圖3-1中,可以看出,類WordCount中,有兩個子類WordInput、WordOutput,以及一個主方法,WordCount.java即是一個Topology,裡面至少包涵一個Input和Output(缺一不可,否則沒有意義),以及main函數,main函數依然是Topology的入口函數。
現在問題來了,Input和Output到底是什麼關係?還有Topology?
每一個Topology就是一個完整的任務鏈,可以包含多個Input,多個Output,Input的資料只能傳遞給一個或多個Output,Output只能將資料傳遞給一個或多個Output,從而形成一個完整的拓撲結構。
二、Input 深入
Input是資料的產生源,通過類WordInput看下是如何產生資料,並傳遞給Output的。
public static class WordInput extends IInput { /** * Output data to collector. */ private StreamChannel _channel; /** * All sample words. */ private final String[] _words = new String[] { "welcome", "iveely", "computing", "0.9.0", "build", "by", "liufanping", "thanks", "github.com" }; private int _index; @Override public void start(HashMap<String, Object> conf, StreamChannel channel) { // Here,must be initialize channel. _channel = channel; _index = _words.length - 1; } @Override public void declareOutputFields(FieldsDeclarer declarer) { declarer.declare(new String[] { "word" }, new Integer[] { 0 }); } @Override public void nextTuple() { if (_index < 0) { _channel.emitEnd(); } else { for (int i = 0; i < 100; i++) { _channel.emit(_words[_index]); } _index--; } } @Override public void end() { System.out.println(getName() + " finished."); } @Override public void toOutput() { _channel.addOutputTo(new WordOutput()); } }
函數講解:
| start函數 |
在執行此Input之前提前調用的函數,使用者初始化等相關工作,類似於建構函式,對有資料輸出的時候,一定要初始化channel。 |
| declareOutputFields函數 |
用於聲明輸出的資料資訊。 |
| nextTuple函數 |
此函數將會被頻繁調用,用於輸出資料,利用channel.emit提交資料到output。 |
| end函數 |
是在Input執行完畢之後,會執行的代碼,類似於解構函式。 |
| toOutput函數 |
是指定Input的資料輸出到的Output。 |
上面代碼中,必須注意的幾個問題:
2.1 WordInput必須繼承IInput。
2.2 Input中,必須在start中初始化channel,因為input一定會產生資料。
2.3 Input中,toOutput函數中,必須指定資料流向。
三、Output深入
Output是資料的處理單元,也可以是新資料的產生單元。
public static class WordOutput extends IOutput { private TreeMap<String, Integer> _map; @Override public void start(HashMap<String, Object> conf, StreamChannel channel) { _map = new TreeMap<>(); } @Override public void declareOutputFields(FieldsDeclarer declarer) { declarer.declare(new String[] { "word", "totalCount" }, null); } @Override public void execute(Tuple tuple) { String word = tuple.get(0).toString(); if (_map.containsKey(word)) { int currentCount = _map.get(word); _map.put(word, currentCount + 1); } else { _map.put(word, 1); } } @Override public void end() { // Output map to database or print. Iterator<String> it = _map.keySet().iterator(); while (it.hasNext()) { String key = it.next(); int value = _map.get(key); System.out.println(getName() + ":" + key + "," + value); } } @Override public void toOutput() { } }
與Input相比,output中沒有nextTuple函數,而是取而代之的execute函數。nextTuple是產生資料,execute是處理資料。如果execute處理完畢之後的資料也需要提交到新的output中去,則需要在execute中利用channel.emit方法提交資料,此刻toOutput中也需要指定資料流向。
此處也需要注意幾個問題:
3.1 如果output需要繼續傳遞資料,則需要在start中初始化channel。
3.2 如果當前output接受的資料來源來自不同的input,且資料格式不統一,則需要自行判斷資料格式,例如傳遞數組中,第一個用int標識是什麼樣的資料格式。
四、main函數
main函數,依然是Topology的執行入口,不同的是,它有兩種執行方式,一個是本地模式,一個是遠程執行模式。本地模式是用於調試用。
public static void main(String[] args) { TopologyBuilder builder = new TopologyBuilder(true, WordCount.class.getName(), "WordCount"); builder.setInput(new WordInput(), 1); builder.setOutput(new WordOutput(), 4); builder.setSlave(2); TopologySubmitter.submit(builder, args); }
main函數中,主要做的工作。
4.1 建立TopologyBuilder對象,並在建構函式的第一個參數指定當前是本地模式(true)還是遠程模式(false),第二個參數,指定執行的類名,第三個參數,當前Topology的名稱。
4.2 設定input和output。並指定啟動並執行數量比(線程)。
4.3 指定在多少個節點上運行(進程)。
4.4 利用TopologySubmitter提交任務即可。
4.5 注意:在產生jar提交到伺服器上運行時,一定要將TopologyBuilder的第一個參數改為遠程模式(false)。
開源分布式即時計算引擎 Iveely Computing 之 WordCount 詳解(3)