Storm的wordcount程式碼編寫與分析
storm包裡面是給了wordcount程式例項的,所以我們是可以參考這個來自己實現。從原始碼來看,如下
首先建立TopologyBuilder物件,通過該物件來設定spout和bolt。
設定spout的時候可以指定自己編寫的Spout類以及使用的執行緒數(即executor數或者說task數,因為預設情況下就是相等的)。設定bolt的時候可以指定自己編寫的Bolt類,指定分組策略。比如圖中,split這個Bolt的資料(以tuple為單位)來源與id為spout的Spout物件,該物件發射資料給Bolt的策略是隨機發。而count對應的Bolt的資料來源於split對應的Bolt物件,該物件傳送資料按照word欄位來發。
單詞計數的各種實現虛擬碼
1、java實現
//一行一行讀取檔案中資料
String line = BufferedReader.readLine();
//按空格切割
String[] words = line.split(" ");
//進行統計
Map<String,Integer> map = new HashMap<>();
for (String word : words){
if(map.containskey(word)){
map.put(word,map.get(word)+1);
}else {
map.put(word,1);
}
}
2、hadoop實現單詞計數
protected void map(LongWritable key, Text value,Context context)
throws IOException, InterruptedException {
//每讀一行會呼叫一次
//按空格切分單詞
String values = value.toString();
String[] words = values.split(" ");
for (String word : words) {
//將單詞作為key,1作為value輸出
context.write(new Text(word), new IntWritable(1));
}
}
protected void reduce(Text key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
int count = 0;
for (IntWritable in : values) {
count += in.get();
}
context.write(new Text(key), new IntWritable(count));
}
3、storm實現單詞計數
Spout:
FileReader.readLine();
輸出:line(tuple物件)
SplitBolt:
輸入:line(tuple物件)
String[] words = line.split();
for(String word : words){
//輸出word
collectot.emit(word);
}
CountBolt:
輸入:word
Map<String,Integer> map = new HashMap<>();
for (String word : words){
if(map.containskey(word)){
map.put(word,map.get(word)+1);
}else {
map.put(word,1);
}
}
Storm的單詞計數程式碼編寫
1、主程式
public class WordCountTopologyDriver {
public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException {
//1、建立topologyBuilder,設定spout和bolt
TopologyBuilder topologyBuilder = new TopologyBuilder();
//設定spout 傳參:id,使用的Spout類,併發度
topologyBuilder.setSpout("myspout",new MySpout(),1);
//設定Bolt 傳參:id,使用的Bolt類,併發度
//設定分組策略 隨機分 引數為spout的id
//mybolt1與myspout跟進id進行連線,怎麼連線?取決於分組策略,shuffleGrouping會對myspout進行分組
//五個task(也就是五個executor或者說五個執行緒)
topologyBuilder.setBolt("mybolt1",new SplitBolt(),4).shuffleGrouping("myspout");
//設定分組策略 按欄位分 引數為上一階段的bolt的id
//注:如果欄位與mybolt裡面宣告的不一致會出現backtype.storm.generated.InvalidTopologyException: null
topologyBuilder.setBolt("mybolt2",new CountBolt(),2).fieldsGrouping("mybolt1",new Fields("word"));
//2、建立Config,指定分配的worker的數量
Config config = new Config();
config.setNumWorkers(3);
//提交任務,可以使用storm叢集來提交也可以使用本地模式來提交(便於除錯)
// StormSubmitter.submitTopology("wordcountsubmit",config,topologyBuilder.createTopology());
//使用本地模式提交
LocalCluster localCluster = new LocalCluster();
localCluster.submitTopology("wordcountsubmit",config,topologyBuilder.createTopology());
}
}
2、自定義Spout
/**
* 獲取資料
* 將資料一行行寫出去
* Created by 12706 on 2017/11/6.
*/
public class MySpout extends BaseRichSpout {
SpoutOutputCollector collector;
//初始化方法
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector collector) {
this.collector = collector;
}
//storm 框架會迴圈呼叫(while(true){..})該方法,將資料射出去
public void nextTuple() {
//需要傳入的是一個List,而Vlaues本身就是一個list
collector.emit(new Values("hadoop hive hbase storm kafka spark"));
}
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
//給寫出去的資料做宣告,格式根據 collector.emit來定
outputFieldsDeclarer.declare(new Fields("bigdata"));
}
}
3、單詞切割Bolt
/**
* 接收MySpout射出的資料
* 每次接收list中的第一個資料(也只有這一個,是一行單詞),按照空格切分,射出到下一個單詞統計的CountBolt
* Created by 12706 on 2017/11/6.
*/
public class SplitBolt extends BaseRichBolt{
OutputCollector collector;
//初始化方法
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
this.collector = outputCollector;
}
//storm框架會迴圈呼叫該方法
//對MySpout射出的資料進行處理,將資料按照空格切割寫出
public void execute(Tuple tuple) {
//獲取list中的第一個資料(實際也只有這一個)
// public String getString(int i) {
// return (String)this.values.get(i);
// }這是原始碼中程式碼,而value本身就是個list。所以取的就是spout射出的list中的第一個資料
String line = tuple.getString(0);
//按空格切割
String[] words = line.split(" ");
for (String word : words){
collector.emit(new Values(word,1));
}
}
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
//寫出宣告collector.emit(new Values(word,1)),可知需要兩個引數對應word和1
// public Fields(String... fields) {
// this(Arrays.asList(fields));
// }可以從原始碼看到可以傳入多個引數
outputFieldsDeclarer.declare(new Fields("word","num"));
}
}
4、單詞統計Bolt
/**
* 接收上一個單詞劃分Bolt傳來的資料,進行單詞統計
* Created by 12706 on 2017/11/6.
*/
public class CountBolt extends BaseRichBolt {
OutputCollector collector;
//建立一個map用來快取單詞統計結果
Map<String,Integer> countMap = new HashMap<String, Integer>();
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
this.collector = outputCollector;
}
public void execute(Tuple tuple) {
//獲取單詞
String word = tuple.getString(0);
//獲取數量(1)
Integer num = tuple.getInteger(1);
if(countMap.containsKey(word)){
//單詞已經存在,數量疊加
countMap.put(word,countMap.get(word)+1);
}else {
//單詞不存在,新增單詞
countMap.put(word,num);
}
//控制檯輸出檢視
System.out.println(countMap);
}
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
//不需要輸出所以不再做宣告瞭,今後有可能輸出到redis中等
}
}
設定的是本地執行模式,所以可以直接執行
控制檯檢視
...
{storm=79526, spark=79524, hadoop=79527, hbase=79526}
{storm=79526, spark=79525, hadoop=79527, hbase=79526}
{storm=79526, spark=79525, hadoop=79528, hbase=79526}
{storm=79526, spark=79525, hadoop=79528, hbase=79527}
{storm=79527, spark=79525, hadoop=79528, hbase=79527}
{hive=109259, kafka=109257}
{hive=109260, kafka=109257}
{hive=109260, kafka=109258}
{hive=109261, kafka=109258}
...
注:這裡分兩段是因為設定了單詞計算Bolt(CountBolt)的併發度為2,而且指定了分組策略是按欄位分組,所以分了兩段來統計,且各個段裡面的單詞是一樣的。
如果使用叢集模式,那麼講工程打包(如storm.jar)傳到叢集上,執行命令
storm jar storm.jar com.itheima.storm.WordCountTopologyDriver wordcount
相關文章
- Storm系列(三)java編寫第個storm程式ORMJava
- Storm實戰之WordCountORM
- 編寫高效的C程式與C程式碼優化C程式優化
- 編寫一個分析程式碼依賴的工具(一)
- Storm-原始碼分析-Thrift的使用ORM原始碼
- Storm-原始碼分析-metricORM原始碼
- 編寫更好的CSS程式碼CSS
- 編寫可讀的程式碼
- Storm-原始碼分析-hook(backtype.storm.hooks)ORM原始碼Hook
- MapReduce(一):入門級程式wordcount及其分析
- Sublime 編寫編譯 swift程式碼編譯Swift
- 如何編寫簡潔的程式碼?
- 編寫更好的C#程式碼C#
- 編寫易於理解的程式碼
- 編寫程式碼的好習慣
- 編寫高效的Android程式碼Android
- 編寫易讀的程式碼 (轉)
- 程式碼編寫提示配置
- 如何編寫MapReduce程式碼
- [技術討論]程式碼編寫能力與管理手段的配合
- 編寫 Netty / RPC 客戶端【框架程式碼分析】NettyRPC客戶端框架
- 編寫高效能的Java程式碼Java
- 編寫更優雅的 JavaScript 程式碼JavaScript
- 如何編寫高效的Android程式碼Android
- IEDA編寫程式碼常用的快捷鍵
- 編寫可測試的 JavaSript 程式碼Java
- 編寫高質量程式碼的思考
- 編寫高效能的 Swift 程式碼Swift
- 編寫高效能的 Lua 程式碼
- 用jQuery編寫出更好的程式碼jQuery
- 編寫可測試的 JavaScript 程式碼JavaScript
- (轉載)編寫高效的jQuery程式碼jQuery
- 編寫更好程式碼的 6 個提示
- 編寫好程式碼的10條戒律
- C編寫的簡單密碼程式密碼
- 編寫可讀程式碼的藝術
- Model 編寫程式碼智慧提醒
- 02 | 編寫Model層程式碼