Storm實戰之TopN
TopN這種統計場景很常見,例如,統計出搜尋熱度最高的詞,點選率最高的廣告等,現在有了Hadoop、Storm這些工具之後,很方便地就能得到結果。
這裡以Storm為例,簡易地實現了TopN單詞的統計,由於剛剛入門,程式碼寫得比較簡單。
首先,在多臺機器上執行多個bolt,每個bolt負責計算一部分word的TopN,最後有一個全域性的bolt,合併上一步的結果,最後得出全域性的TopN。
這裡需要注意的幾點是,第一個bolt的分組策略是fieldsGrouping,按照欄位分組,這一點很重要,它能保證相同的word被分發到同一個bolt上,
像做wordcount、TopN之類的應用就要使用這種分組策略。
最後一個bolt的分組策略是globalGrouping,全域性分組,tuple會被分配到一個bolt用來彙總。
為了提高並行度,spout和第一個bolt均設定並行度為2(我這裡測試機器效能不是很高)。
spout的作用是隨機傳送word,傳送100次,由於並行度是2,將產生2個spout例項,所以這裡的計數器使用了static的AtomicInteger來保證執行緒安全。
在WordCounter裡面有個執行緒安全的容器ConcurrentHashMap,來儲存word以及對應的次數。在prepare方法裡啟動一個執行緒,長期監聽edit的狀態,監聽間隔是5秒,
當edit為false,即execute方法不再執行、容器不再變化,可以認為spout已經傳送完畢了,可以開始排序取TopN了。這裡使用了一個volatile edit(回憶一下volatile的使用場景:
對變數的修改不依賴變數當前的值,這裡設定true or false,顯然不相互依賴)。
最後一個bolt做全域性的彙總,這裡我偷了懶,直接將結果寫到檔案了,省略擷取TopN的過程,因為我這裡就一個supervisor節點,所以結果是正確的。
這裡以Storm為例,簡易地實現了TopN單詞的統計,由於剛剛入門,程式碼寫得比較簡單。
首先,在多臺機器上執行多個bolt,每個bolt負責計算一部分word的TopN,最後有一個全域性的bolt,合併上一步的結果,最後得出全域性的TopN。
點選(此處)摺疊或開啟
-
package test.storm.topology;
-
-
import test.storm.bolt.WordCounter;
-
import test.storm.bolt.WordWriter;
-
import test.storm.spout.WordReader;
-
import backtype.storm.Config;
-
import backtype.storm.StormSubmitter;
-
import backtype.storm.generated.AlreadyAliveException;
-
import backtype.storm.generated.InvalidTopologyException;
-
import backtype.storm.topology.TopologyBuilder;
-
import backtype.storm.tuple.Fields;
-
-
public class WordTopN {
-
public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException {
-
if (args == null || args.length < 1) {
-
System.err.println("Usage: N");
-
System.err.println("such as : 10");
-
System.exit(-1);
-
}
-
-
TopologyBuilder builder = new TopologyBuilder();
-
builder.setSpout("wordreader", new WordReader(), 2);
-
builder.setBolt("wordcounter", new WordCounter(), 2).fieldsGrouping("wordreader", new Fields("word"));
-
builder.setBolt("wordwriter", new WordWriter()).globalGrouping("wordcounter");
-
-
Config conf = new Config();
-
conf.put("N", args[0]);
-
-
conf.setDebug(false);
-
StormSubmitter.submitTopology("topN", conf, builder.createTopology());
-
-
}
- }
像做wordcount、TopN之類的應用就要使用這種分組策略。
最後一個bolt的分組策略是globalGrouping,全域性分組,tuple會被分配到一個bolt用來彙總。
為了提高並行度,spout和第一個bolt均設定並行度為2(我這裡測試機器效能不是很高)。
點選(此處)摺疊或開啟
-
package test.storm.spout;
-
-
import java.util.Map;
-
import java.util.Random;
-
import java.util.concurrent.atomic.AtomicInteger;
-
-
import backtype.storm.spout.SpoutOutputCollector;
-
import backtype.storm.task.TopologyContext;
-
import backtype.storm.topology.OutputFieldsDeclarer;
-
import backtype.storm.topology.base.BaseRichSpout;
-
import backtype.storm.tuple.Fields;
-
import backtype.storm.tuple.Values;
-
-
public class WordReader extends BaseRichSpout {
-
private static final long serialVersionUID = 2197521792014017918L;
-
private SpoutOutputCollector collector;
-
private static AtomicInteger i = new AtomicInteger();
-
private static String[] words = new String[] { \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\",
-
\"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\" };
-
-
@Override
-
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
-
this.collector = collector;
-
}
-
-
@Override
-
public void nextTuple() {
-
if (i.intValue() < 100) {
-
Random rand = new Random();
-
String word = words[rand.nextInt(words.length)];
-
collector.emit(new Values(word));
-
i.incrementAndGet();
-
}
-
}
-
-
@Override
-
public void declareOutputFields(OutputFieldsDeclarer declarer) {
-
declarer.declare(new Fields("word"));
-
}
- }
點選(此處)摺疊或開啟
-
package test.storm.bolt;
-
-
import java.util.ArrayList;
-
import java.util.Collections;
-
import java.util.Comparator;
-
import java.util.HashMap;
-
import java.util.List;
-
import java.util.Map;
-
import java.util.Map.Entry;
-
import java.util.concurrent.ConcurrentHashMap;
-
-
import backtype.storm.task.OutputCollector;
-
import backtype.storm.task.TopologyContext;
-
import backtype.storm.topology.IRichBolt;
-
import backtype.storm.topology.OutputFieldsDeclarer;
-
import backtype.storm.tuple.Fields;
-
import backtype.storm.tuple.Tuple;
-
import backtype.storm.tuple.Values;
-
-
public class WordCounter implements IRichBolt {
-
private static final long serialVersionUID = 5683648523524179434L;
-
private static Map<String, Integer> counters = new ConcurrentHashMap<String, Integer>();
-
private volatile boolean edit = true;
-
-
@Override
-
public void prepare(final Map stormConf, TopologyContext context, final OutputCollector collector) {
-
new Thread(new Runnable() {
-
@Override
-
public void run() {
-
while (true) {
-
//5秒後counter不再變化,可以認為spout已經傳送完畢
-
if (!edit) {
-
if (counters.size() > 0) {
-
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>();
-
list.addAll(counters.entrySet());
-
Collections.sort(list, new ValueComparator());
-
-
//向下一個bolt傳送前N個word
-
for (int i = 0; i < list.size(); i++) {
-
if (i < Integer.parseInt(stormConf.get("N").toString())) {
-
collector.emit(new Values(list.get(i).getKey() + ":" + list.get(i).getValue()));
-
}
-
}
-
}
-
-
//傳送之後,清空counters,以防spout再次傳送word過來
-
counters.clear();
-
}
-
-
edit = false;
-
try {
-
Thread.sleep(5000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
}).start();
-
}
-
-
@Override
-
public void execute(Tuple tuple) {
-
String str = tuple.getString(0);
-
if (counters.containsKey(str)) {
-
Integer c = counters.get(str) + 1;
-
counters.put(str, c);
-
} else {
-
counters.put(str, 1);
-
}
-
-
edit = true;
-
}
-
-
private static class ValueComparator implements Comparator<Map.Entry<String, Integer>> {
-
@Override
-
public int compare(Entry<String, Integer> entry1, Entry<String, Integer> entry2) {
-
return entry2.getValue() - entry1.getValue();
-
}
-
}
-
-
@Override
-
public void declareOutputFields(OutputFieldsDeclarer declarer) {
-
declarer.declare(new Fields("word_count"));
-
}
-
-
@Override
-
public void cleanup() {
-
}
-
-
@Override
-
public Map<String, Object> getComponentConfiguration() {
-
return null;
-
}
- }
當edit為false,即execute方法不再執行、容器不再變化,可以認為spout已經傳送完畢了,可以開始排序取TopN了。這裡使用了一個volatile edit(回憶一下volatile的使用場景:
對變數的修改不依賴變數當前的值,這裡設定true or false,顯然不相互依賴)。
點選(此處)摺疊或開啟
-
package test.storm.bolt;
-
-
import java.io.FileWriter;
-
import java.io.IOException;
-
import java.util.Map;
-
-
import backtype.storm.task.TopologyContext;
-
import backtype.storm.topology.BasicOutputCollector;
-
import backtype.storm.topology.OutputFieldsDeclarer;
-
import backtype.storm.topology.base.BaseBasicBolt;
-
import backtype.storm.tuple.Tuple;
-
-
public class WordWriter extends BaseBasicBolt {
-
private static final long serialVersionUID = -6586283337287975719L;
-
private FileWriter writer = null;
-
-
public WordWriter() {
-
}
-
-
@Override
-
public void prepare(Map stormConf, TopologyContext context) {
-
try {
-
writer = new FileWriter("/data/tianzhen/output/" + this);
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
-
@Override
-
public void execute(Tuple input, BasicOutputCollector collector) {
-
String s = input.getString(0);
-
try {
-
writer.write(s);
-
writer.write("\n");
-
writer.flush();
-
} catch (IOException e) {
-
e.printStackTrace();
-
} finally {
-
//writer不能close,因為execute需要一直執行
-
}
-
}
-
-
@Override
-
public void declareOutputFields(OutputFieldsDeclarer declarer) {
-
-
}
- }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28912557/viewspace-1579860/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Storm實戰之WordCountORM
- MapReduce之topN
- Kafka實戰-Storm ClusterKafkaORM
- Kafka實戰-Kafka到StormKafkaORM
- 大資料Storm 之RCE實踐大資料ORM
- Storm 實戰:構建大資料實時計算ORM大資料
- Flink實時計算topN熱榜
- 《Storm企業級應用:實戰、運維和調優》——第2章開始使用StormORM運維
- 兩個例子(來自Storm實戰 構建大資料實時計算)ORM大資料
- Storm入門之第6章一個實際的例子ORM
- Storm入門之附錄CORM
- 【Twitter Storm系列】flume-ng+Kafka+Storm+HDFS 實時系統搭建ORMKafka
- 探索c#之storm的TimeCacheMapC#ORM
- Storm應用系列之——Spout、Bolt APIORMAPI
- Storm應用系列之——Topology部署ORM
- Storm流計算之專案篇(Storm+Kafka+HBase+Highcharts+JQuery,含3個完整實際專案)ORMKafkajQuery
- 《Storm企業級應用:實戰、運維和調優》——2.5 本章小結ORM運維
- 《Storm企業級應用:實戰、運維和調優》——1.6 本章小結ORM運維
- Storm 系列(九)—— Storm 整合 KafkaORMKafka
- 【Storm篇】--Storm基礎概念ORM
- 【Storm篇】--Storm分組策略ORM
- 《Storm企業級應用:實戰、運維和調優》——2.1 環境準備ORM運維
- 大資料storm學習之我觀大資料ORM
- shiro實戰系列(二)之入門實戰續
- kubebuilder實戰之七:webhookUIWebHook
- Django之MTV實戰(2)Django
- golang實戰之flag包Golang
- 機器學習實戰之開篇機器學習
- 自娛小程式–超大檔案topN
- Flutter實戰之動畫實現篇Flutter動畫
- Storm系列(六)storm和kafka整合ORMKafka
- 【Storm篇】--Storm併發機制ORM
- 【Storm篇】--Storm 容錯機制ORM
- storm實時計算例項(socket實時接入)ORM
- Java 8 Stream之實戰篇Java
- BIOS實戰之Memory配置iOS
- helm實戰之開發Chart
- iOS動畫實戰之Lottie動畫iOS動畫