Storm 第三章 Storm编程案例及Stream Grouping详解

1 功能说明

  设计一个topology,来实现对文档里面的单词出现的频率进行统计。整个topology分为三个部分:

  SentenceSpout:数据源,在已知的英文句子中,随机发送一条句子出去。

  SplitBolt:负责将单行文本记录(句子)切分成单词

  CountBolt:负责对单词的频率进行累加

2 代码实现

 1 package com.ntjr.bigdata;
 2 
 3 import org.apache.storm.Config;
 4 import org.apache.storm.LocalCluster;
 5 import org.apache.storm.StormSubmitter;
 6 import org.apache.storm.generated.AlreadyAliveException;
 7 import org.apache.storm.generated.AuthorizationException;
 8 import org.apache.storm.generated.InvalidTopologyException;
 9 import org.apache.storm.topology.TopologyBuilder;
10 import org.apache.storm.tuple.Fields;
11 
12 public class WrodCountTopolog {
13     public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException, AuthorizationException {
14         //使用TopologyBuilder 构建一个topology
15         TopologyBuilder topologyBuilder = new TopologyBuilder();
16         //发送英文句子
17         topologyBuilder.setSpout("sentenceSpout", new SentenceSpout(), 2);
18         //将一行行的文本切分成单词
19         topologyBuilder.setBolt("splitBolt", new SplitBolt(), 2).shuffleGrouping("sentenceSpout");
20         //将单词的频率进行累加
21         topologyBuilder.setBolt("countBolt", new CountBolt(), 2).fieldsGrouping("splitBolt", new Fields("word"));
22         //启动topology的配置信息
23         Config config = new Config();
24         //定义集群分配多少个工作进程来执行这个topology
25         config.setNumWorkers(3);
26         
27         //本地模式提交topology
28         LocalCluster localCluster = new LocalCluster();
29         localCluster.submitTopology("mywordCount", config, topologyBuilder.createTopology());
30         
31         //集群模式提交topology
32         StormSubmitter.submitTopologyWithProgressBar("mywordCount", config, topologyBuilder.createTopology());
33 
34     }
35 
36 }
WrodCountTopolog.java
 1 package com.ntjr.bigdata;
 2 
 3 import java.util.Map;
 4 
 5 import org.apache.storm.spout.SpoutOutputCollector;
 6 import org.apache.storm.task.TopologyContext;
 7 import org.apache.storm.topology.OutputFieldsDeclarer;
 8 import org.apache.storm.topology.base.BaseRichSpout;
 9 import org.apache.storm.tuple.Fields;
10 import org.apache.storm.tuple.Values;
11 
12 public class SentenceSpout extends BaseRichSpout {
13 
14     private static final long serialVersionUID = 1L;
15     // 用来收集Spout输出的tuple
16     private SpoutOutputCollector collector;
17 
18     @Override
19     public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
20         this.collector = collector;
21 
22     }
23 
24     // 该方法会循环调用
25     @Override
26     public void nextTuple() {
27         collector.emit(new Values("i am lilei love hanmeimei"));
28     }
29 
30     // 消息源可以发送多条消息流,该方法定义输出的消息类型的字段
31     @Override
32     public void declareOutputFields(OutputFieldsDeclarer declarer) {
33         declarer.declare(new Fields("love"));
34 
35     }
36 
37 }
SentenceSpout.java
 1 package com.ntjr.bigdata;
 2 
 3 import java.util.Map;
 4 
 5 import org.apache.storm.task.OutputCollector;
 6 import org.apache.storm.task.TopologyContext;
 7 import org.apache.storm.topology.OutputFieldsDeclarer;
 8 import org.apache.storm.topology.base.BaseRichBolt;
 9 import org.apache.storm.tuple.Fields;
10 import org.apache.storm.tuple.Tuple;
11 import org.apache.storm.tuple.Values;
12 
13 public class SplitBolt extends BaseRichBolt {
14 
15     private static final long serialVersionUID = 1L;
16 
17     private OutputCollector collector;
18 
19     // 该方法只会调用一次用来执行初始化
20     @Override
21     public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
22         this.collector = collector;
23 
24     }
25 
26     // 接收的参数时spout发出来的句子,一个句子就是一个tuple
27     @Override
28     public void execute(Tuple input) {
29         String line = input.getString(0);
30         String[] words = line.split(" ");
31         for (String word : words) {
32             collector.emit(new Values(word, 1));
33         }
34 
35     }
36 
37     // 定义输出类型,输出类型为单词和单词的数目和collector.emit(new Values(word, 1));对应
38     @Override
39     public void declareOutputFields(OutputFieldsDeclarer declarer) {
40         declarer.declare(new Fields("word", "num"));
41 
42     }
43 
44 }
SplitBolt.java
 1 package com.ntjr.bigdata;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 
 6 import org.apache.storm.task.OutputCollector;
 7 import org.apache.storm.task.TopologyContext;
 8 import org.apache.storm.topology.OutputFieldsDeclarer;
 9 import org.apache.storm.topology.base.BaseRichBolt;
10 import org.apache.storm.tuple.Tuple;
11 
12 public class CountBolt extends BaseRichBolt {
13 
14     private static final long serialVersionUID = 1L;
15     private OutputCollector collector;
16     // 用来保存最后的计算结果 key:单词,value:单词的个数
17     Map<String, Integer> map = new HashMap<String, Integer>();
18 
19     // 该方法调用一次用来执行初始化
20     @Override
21     public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
22         this.collector = collector;
23 
24     }
25 
26     @Override
27     public void execute(Tuple input) {
28         String word = input.getString(0);
29         Integer num = input.getInteger(1);
30 
31         if (map.containsKey(word)) {
32             Integer count = map.get(word);
33             map.put(word, count + num);
34         } else {
35             map.put(word, num);
36         }
37         System.out.println("count:" + map);
38     }
39 
40     @Override
41     public void declareOutputFields(OutputFieldsDeclarer declarer) {
42 
43     }
44 
45 }
CountBolt.java

3 执行流程图

 

Stream Grouping详解

  3.1 Shuffle Grouping: 随机分组, 随机派发stream里面的tuple,保证每个bolt接收到的tuple数目大致相同。

  3.2 Fields Grouping:按字段分组,比如按userid来分组,具有同样userid的tuple会被分到相同的Bolts里的一个task,而不同的userid则会被分配到不同的bolts里的task。

  3.3 All Grouping:广播发送,对于每一个tuple,所有的bolts都会收到。

  3.4 Global Grouping:全局分组, 这个tuple被分配到storm中的一个bolt的其中一个task。再具体一点就是分配给id值最低的那个task。

  3.5 Non Grouping:不分组,这stream grouping个分组的意思是说stream不关心到底谁会收到它的tuple。目前这种分组和Shuffle grouping是一样的效果 有一点不同的是storm会把这个bolt放到这个bolt的订阅者同一个线程里面去执行。

  3.6 Direct Grouping: 直接分组, 这是一种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发射。

            消息处理者可以通过TopologyContext来获取处理它的消息的task的id (OutputCollector.emit方法也会返回task的id)。

  3.7 Local or shuffle grouping:如果目标bolt有一个或者多个task在同一个工作进程中,tuple将会被随机发生给这些tasks。否则,和普通的Shuffle Grouping行为一致。

 

posted @ 2018-01-24 15:36  IT-執念  阅读(391)  评论(0编辑  收藏  举报