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 初識編碼ORM
- 編寫 Netty / RPC 客戶端【框架程式碼分析】NettyRPC客戶端框架
- 如何編寫高效的Android程式碼Android
- 如何編寫簡潔的程式碼?
- Sublime 編寫編譯 swift程式碼編譯Swift
- IEDA編寫程式碼常用的快捷鍵
- 編寫更優雅的 JavaScript 程式碼JavaScript
- 編寫簡單的Java程式碼:HelloWoridJava
- 編寫高效能的Java程式碼Java
- PEP 8 程式程式碼的編寫風格指南
- Hbuilder快速程式碼編寫技巧UI
- Model 編寫程式碼智慧提醒
- 02 | 編寫Model層程式碼
- vue3程式碼編寫Vue
- 消除程式碼中的壞味道,編寫高質量程式碼
- 編寫優雅程式碼的最佳實踐
- ekzhang/rustpad:使用Rust編寫的高效程式碼編輯器Rust
- 🐒編寫高質量程式碼(手撕程式碼)
- Java程式碼編寫、程式碼優化技巧總結Java優化
- python如何換行編寫程式碼Python
- iOS程式碼編寫利器AppCode 2022iOSAPP
- 使用 xunit 編寫測試程式碼
- Django開發——003程式碼編寫Django
- 用Rust編寫的快如閃電的程式碼編輯器:lapceRust
- Python 工匠:編寫條件分支程式碼的技巧Python
- 編寫可閱讀的程式碼--基本規約
- golang如何優雅的編寫事務程式碼Golang
- Flink 入門篇之 寫個WordCount
- 中國程式設計師與美國程式設計師寫程式碼的區別分析程式設計師
- 在 Laravel 中編寫簡潔的程式碼的策略Laravel
- 乾淨的程式碼: 編寫可讀的函式函式
- 前端進階-編寫測試程式碼前端
- 如何學習用Java編寫程式碼?Java
- 使用 Source Generators 快速編寫 MVVM 程式碼MVVM
- 使用pycharm or vscode來編寫python程式碼?PyCharmVSCodePython
- AppCode 2022 for Mac(iOS程式碼編寫利器)APPMaciOS
- 程式碼規範之前端編寫碼規範前端