• 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行为一致。

  • 相关阅读:
    linux安装mysql
    yum命令
    java启动jar包中的指定类
    linux系统配置参数修改
    iconfont阿里巴巴矢量图标库批量保存
    Python 使用Pandas读取Excel的学习笔记
    在Ubuntu18.04的Docker中安装Oracle镜像及简单使用
    Eclipse 安装PyDev开发Python及初步使用
    Python打包工具
    MacOS下打包Python应用
  • 原文地址:https://www.cnblogs.com/zhaobingqing/p/8341913.html
Copyright © 2020-2023  润新知