Storm的wordCounter计数器详解
点击(此处)折叠或打开
- package cn.jd.storm;
- import backtype.storm.Config;
- import backtype.storm.LocalCluster;
- import backtype.storm.topology.TopologyBuilder;
- import backtype.storm.tuple.Fields;
- /**
- * 功能说明:
- * 设计一个topology,来实现对一个句子里面的单词出现的频率进行统计。
- * 整个topology分为三个部分:
- * WordReader:数据源,负责发送单行文本记录(句子)
- * WordNormalizer:负责将单行文本记录(句子)切分成单词
- * WordCounter:负责对单词的频率进行累加
- *
- * @author 毛祥溢
- * Email:frank@maoxiangyi.cn
- * 2013-8-26 下午5:59:06
- */
- public class TopologyMain {
- /**
- * @param args 文件路径
- */
- public static void main(String[] args)throws Exception {
- // Storm框架支持多语言,在JAVA环境下创建一个拓扑,需要使用TopologyBuilder进行构建
- TopologyBuilder builder = new TopologyBuilder();
- /* WordReader类,主要是将文本内容读成一行一行的模式
- * 消息源spout是Storm里面一个topology里面的消息生产者。
- * 一般来说消息源会从一个外部源读取数据并且向topology里面发出消息:tuple。
- * Spout可以是可靠的也可以是不可靠的。
- * 如果这个tuple没有被storm成功处理,可靠的消息源spouts可以重新发射一个tuple,但是不可靠的消息源spouts一旦发出一个tuple就不能重发了。
- *
- * 消息源可以发射多条消息流stream。多条消息流可以理解为多中类型的数据。
- * 使用OutputFieldsDeclarer.declareStream来定义多个stream,然后使用SpoutOutputCollector来发射指定的stream。
- *
- * Spout类里面最重要的方法是nextTuple。要么发射一个新的tuple到topology里面或者简单的返回如果已经没有新的tuple。
- * 要注意的是nextTuple方法不能阻塞,因为storm在同一个线程上面调用所有消息源spout的方法。
- *
- * 另外两个比较重要的spout方法是ack和fail。storm在检测到一个tuple被整个topology成功处理的时候调用ack,否则调用fail。storm只对可靠的spout调用ack和fail。
- */
- builder.setSpout("word-reader",new WordReader());
- /* WordNormalizer类,主要是将一行一行的文本内容切割成单词
- *
- * 所有的消息处理逻辑被封装在bolts里面。Bolts可以做很多事情:过滤,聚合,查询数据库等等。
- * Bolts可以简单的做消息流的传递。复杂的消息流处理往往需要很多步骤,从而也就需要经过很多bolts。
- * 比如算出一堆图片里面被转发最多的图片就至少需要两步:
- * 第一步算出每个图片的转发数量。
- * 第二步找出转发最多的前10个图片。(如果要把这个过程做得更具有扩展性那么可能需要更多的步骤)。
- *
- * Bolts可以发射多条消息流, 使用OutputFieldsDeclarer.declareStream定义stream,使用OutputCollector.emit来选择要发射的stream。
- * Bolts的主要方法是execute, 它以一个tuple作为输入,bolts使用OutputCollector来发射tuple。
- * bolts必须要为它处理的每一个tuple调用OutputCollector的ack方法,以通知Storm这个tuple被处理完成了,从而通知这个tuple的发射者spouts。
- * 一般的流程是: bolts处理一个输入tuple, 发射0个或者多个tuple, 然后调用ack通知storm自己已经处理过这个tuple了。storm提供了一个IBasicBolt会自动调用ack。
- *
- *
- */
- builder.setBolt("word-normalizer", new WordNormalizer()).shuffleGrouping("word-reader");
- /*
- * 上面的代码和下面的代码中都设定了数据分配的策略stream grouping
- * 定义一个topology的其中一步是定义每个bolt接收什么样的流作为输入。stream grouping就是用来定义一个stream应该如果分配数据给bolts上面的多个tasks。
- * Storm里面有7种类型的stream grouping
- * Shuffle Grouping: 随机分组, 随机派发stream里面的tuple,保证每个bolt接收到的tuple数目大致相同。
- * Fields Grouping:按字段分组, 比如按userid来分组, 具有同样userid的tuple会被分到相同的Bolts里的一个task,
- * 而不同的userid则会被分配到不同的bolts里的task。
- * All Grouping:广播发送,对于每一个tuple,所有的bolts都会收到。
- * Global Grouping:全局分组, 这个tuple被分配到storm中的一个bolt的其中一个task。再具体一点就是分配给id值最低的那个task。
- * Non Grouping:不分组,这stream grouping个分组的意思是说stream不关心到底谁会收到它的tuple。
- * 目前这种分组和Shuffle grouping是一样的效果, 有一点不同的是storm会把这个bolt放到这个bolt的订阅者同一个线程里面去执行。
- * Direct Grouping: 直接分组, 这是一种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。
- * 只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发射。
- * 消息处理者可以通过TopologyContext来获取处理它的消息的task的id (OutputCollector.emit方法也会返回task的id)。
- * Local or shuffle grouping:如果目标bolt有一个或者多个task在同一个工作进程中,tuple将会被随机发生给这些tasks。
- * 否则,和普通的Shuffle Grouping行为一致。
- *
- */
- builder.setBolt("word-counter", new WordCounter(),1).fieldsGrouping("word-normalizer", new Fields("word"));
- /*
- * storm的运行有两种模式: 本地模式和分布式模式.
- * 1) 本地模式:
- * storm用一个进程里面的线程来模拟所有的spout和bolt. 本地模式对开发和测试来说比较有用。
- * 你运行storm-starter里面的topology的时候它们就是以本地模式运行的, 你可以看到topology里面的每一个组件在发射什么消息。
- * 2) 分布式模式:
- * storm由一堆机器组成。当你提交topology给master的时候, 你同时也把topology的代码提交了。
- * master负责分发你的代码并且负责给你的topolgoy分配工作进程。如果一个工作进程挂掉了, master节点会把认为重新分配到其它节点。
- * 下面是以本地模式运行的代码:
- *
- * Conf对象可以配置很多东西, 下面两个是最常见的:
- * TOPOLOGY_WORKERS(setNumWorkers) 定义你希望集群分配多少个工作进程给你来执行这个topology.
- * topology里面的每个组件会被需要线程来执行。每个组件到底用多少个线程是通过setBolt和setSpout来指定的。
- * 这些线程都运行在工作进程里面. 每一个工作进程包含一些节点的一些工作线程。
- * 比如, 如果你指定300个线程,60个进程, 那么每个工作进程里面要执行6个线程, 而这6个线程可能属于不同的组件(Spout, Bolt)。
- * 你可以通过调整每个组件的并行度以及这些线程所在的进程数量来调整topology的性能。
- * TOPOLOGY_DEBUG(setDebug), 当它被设置成true的话, storm会记录下每个组件所发射的每条消息。
- * 这在本地环境调试topology很有用, 但是在线上这么做的话会影响性能的。
- */
- Config conf = new Config();
- conf.setDebug(true);
- conf.setNumWorkers(2);
- conf.put("wordsFile","/root/workspace1/com.jd.storm.demo/src/main/resources/words.txt");
- conf.setDebug(true);
- conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 1);
- /*
- * 定义一个LocalCluster对象来定义一个进程内的集群。提交topology给这个虚拟的集群和提交topology给分布式集群是一样的。
- * 通过调用submitTopology方法来提交topology, 它接受三个参数:要运行的topology的名字,一个配置对象以及要运行的topology本身。
- * topology的名字是用来唯一区别一个topology的,这样你然后可以用这个名字来杀死这个topology的。前面已经说过了, 你必须显式的杀掉一个topology, 否则它会一直运行。
- */
- LocalCluster cluster = new LocalCluster();
- cluster.submitTopology("wordCounterTopology", conf, builder.createTopology());
- Thread.sleep(1000);
- cluster.killTopology("wordCounterTopology");
- cluster.shutdown();
- }
- }
读句子
点击(此处)折叠或打开
- package cn.jd.storm;
- import java.io.BufferedReader;
- import java.io.FileNotFoundException;
- import java.io.FileReader;
- import java.util.Map;
- 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;
- /**
- *
- * 功能说明:
- * 主要是将文件内容读出来,一行一行
- *
- * Spout类里面最重要的方法是nextTuple。
- * 要么发射一个新的tuple到topology里面或者简单的返回如果已经没有新的tuple。
- * 要注意的是nextTuple方法不能阻塞,因为storm在同一个线程上面调用所有消息源spout的方法。
- * 另外两个比较重要的spout方法是ack和fail。
- * storm在检测到一个tuple被整个topology成功处理的时候调用ack,否则调用fail。
- * storm只对可靠的spout调用ack和fail。
- *
- * @author 毛祥溢
- * Email:frank@maoxiangyi.cn
- * 2013-8-26 下午6:05:46
- */
- public class WordReader extends BaseRichSpout {
- private SpoutOutputCollector collector;
- private FileReader fileReader;
- private String filePath;
- private boolean completed = false;
- //storm在检测到一个tuple被整个topology成功处理的时候调用ack,否则调用fail。
- public void ack(Object msgId) {
- System.out.println("OK:"+msgId);
- }
- public void close() {}
- //storm在检测到一个tuple被整个topology成功处理的时候调用ack,否则调用fail。
- public void fail(Object msgId) {
- System.out.println("FAIL:"+msgId);
- }
- /*
- * 在SpoutTracker类中被调用,每调用一次就可以向storm集群中发射一条数据(一个tuple元组),该方法会被不停的调用
- */
- public void nextTuple() {
- if(completed){
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- }
- return;
- }
- String str;
- BufferedReader reader =new BufferedReader(fileReader);
- try{
- while((str = reader.readLine()) != null){
- System.out.println("WordReader类 读取到一行数据:"+ str);
- this.collector.emit(new Values(str),str);
- System.out.println("WordReader类 发射了一条数据:"+ str);
- }
- }catch(Exception e){
- throw new RuntimeException("Error reading tuple",e);
- }finally{
- completed = true;
- }
- }
- public void open(Map conf, TopologyContext context,SpoutOutputCollector collector) {
- try {
- this.fileReader = new FileReader(conf.get("wordsFile").toString());
- } catch (FileNotFoundException e) {
- throw new RuntimeException("Error reading file ["+conf.get("wordFile")+"]");
- }
- this.filePath = conf.get("wordsFile").toString();
- this.collector = collector;
- }
- /**
- * 定义字段id,该id在简单模式下没有用处,但在按照字段分组的模式下有很大的用处。
- * 该declarer变量有很大作用,我们还可以调用declarer.declareStream();来定义stramId,该id可以用来定义更加复杂的流拓扑结构
- */
- public void declareOutputFields(OutputFieldsDeclarer declarer) {
- declarer.declare(new Fields("line"));
- }
- }
将句子切割成单词
点击(此处)折叠或打开
- package cn.jd.storm;
- import backtype.storm.topology.BasicOutputCollector;
- import backtype.storm.topology.OutputFieldsDeclarer;
- import backtype.storm.topology.base.BaseBasicBolt;
- import backtype.storm.tuple.Fields;
- import backtype.storm.tuple.Tuple;
- import backtype.storm.tuple.Values;
- /**
- *
- * 功能说明:
- * 将一行文本切割成单词,并封装collector中发射出去
- *
- * @author 毛祥溢
- * Email:frank@maoxiangyi.cn
- * 2013-8-26 下午6:05:59
- */
- public class WordNormalizer extends BaseBasicBolt {
- public void cleanup() {
- System.out.println("将一行文本切割成单词,并封装collector中发射出去 ---完毕!");
- }
- /**
- * 接受的参数是WordReader发出的句子,即input的内容是句子
- * execute方法,将句子切割形成的单词发出
- */
- public void execute(Tuple input, BasicOutputCollector collector) {
- String sentence = input.getString(0);
- String[] words = sentence.split(" ");
- System.out.println("WordNormalizer类 收到一条数据,这条数据是: "+ sentence);
- for(String word : words){
- word = word.trim();
- if(!word.isEmpty()){
- word = word.toLowerCase();
- System.out.println("WordNormalizer类 收到一条数据,这条数据是: "+ sentence+"数据正在被切割,切割出来的单词是 "+ word);
- collector.emit(new Values(word));
- }
- }
- }
- /**
- * 定义字段id,该id在简单模式下没有用处,但在按照字段分组的模式下有很大的用处。
- * 该declarer变量有很大作用,我们还可以调用declarer.declareStream();来定义stramId,该id可以用来定义更加复杂的流拓扑结构
- */
- public void declareOutputFields(OutputFieldsDeclarer declarer) {
- declarer.declare(new Fields("word"));
- }
- }
计数器WordCounter
点击(此处)折叠或打开
- package cn.jd.storm;
- import java.util.HashMap;
- 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;
- /**
- *
- * 功能说明:
- * 实现计数器的功能,第一次将collector中的元素存放在成员变量counters(Map)中.
- * 如果counters(Map)中已经存在该元素,getValule并对Value进行累加操作。
- *
- * @author 毛祥溢
- * Email:frank@maoxiangyi.cn
- * 2013-8-26 下午6:06:07
- */
- public class WordCounter extends BaseBasicBolt {
- private static final long serialVersionUID = 5678586644899822142L;
- Integer id;
- String name;
- //定义Map封装最后的结果
- Map<String, Integer> counters;
- /**
- * 在spout结束时被调用,将最后的结果显示出来
- *
- * 結果:
- * -- Word Counter [word-counter-2] --
- * really: 1
- * but: 1
- * application: 1
- * is: 2
- * great: 2
- */
- @Override
- public void cleanup() {
- System.out.println("-- Word Counter ["+name+"-"+id+"] --");
- for(Map.Entry<String, Integer> entry : counters.entrySet()){
- System.out.println(entry.getKey()+": "+entry.getValue());
- }
- System.out.println("实现计数器的功能 --完畢!");
- }
- /**
- * 初始化操作
- */
- @Override
- public void prepare(Map stormConf, TopologyContext context) {
- this.counters = new HashMap<String, Integer>();
- this.name = context.getThisComponentId();
- this.id = context.getThisTaskId();
- }
- public void declareOutputFields(OutputFieldsDeclarer declarer) {}
- /**
- * 实现计数器的功能,第一次将collector中的元素存放在成员变量counters(Map)中.
- * 如果counters(Map)中已经存在该元素,getValule并对Value进行累加操作。
- */
- public void execute(Tuple input, BasicOutputCollector collector) {
- String str = input.getString(0);
- System.out.println("WordCounter 计数器收到单词 "+ str);
- if(!counters.containsKey(str)){
- counters.put(str, 1);
- }else{
- Integer c = counters.get(str) + 1;
- counters.put(str, c);
- }
- }
- }
数据格式
storm ni great he he xi wang test haha heihei very are mao xiang yi jd |
运行日志
WordReader类 发射了一条数据:storm ni great he he xi wang WordReader类 发射了一条数据:test haha heihei very WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang数据正在被切割,切割出来的单词是 storm WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang数据正在被切割,切割出来的单词是 ni WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang数据正在被切割,切割出来的单词是 great WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang数据正在被切割,切割出来的单词是 he WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang数据正在被切割,切割出来的单词是 he WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang数据正在被切割,切割出来的单词是 xi WordNormalizer类 收到一条数据,这条数据是: storm ni great he he xi wang数据正在被切割,切割出来的单词是 wang WordCounter 计数器收到单词 storm WordCounter 计数器收到单词 ni WordCounter 计数器收到单词 great WordCounter 计数器收到单词 he WordCounter 计数器收到单词 he WordCounter 计数器收到单词 xi WordCounter 计数器收到单词 wang WordNormalizer类 收到一条数据,这条数据是: test haha heihei very WordNormalizer类 收到一条数据,这条数据是: test haha heihei very 数据正在被切割,切割出来的单词是 test WordNormalizer类 收到一条数据,这条数据是: test haha heihei very 数据正在被切割,切割出来的单词是 haha WordNormalizer类 收到一条数据,这条数据是: test haha heihei very 数据正在被切割,切割出来的单词是 heihei WordNormalizer类 收到一条数据,这条数据是: test haha heihei very 数据正在被切割,切割出来的单词是 very WordCounter 计数器收到单词 test WordCounter 计数器收到单词 haha WordCounter 计数器收到单词 heihei WordCounter 计数器收到单词 very WordReader类 发射了一条数据:are mao xiang yi jd WordNormalizer类 收到一条数据,这条数据是: are mao xiang yi jd WordNormalizer类 收到一条数据,这条数据是: are mao xiang yi jd 数据正在被切割,切割出来的单词是 are WordNormalizer类 收到一条数据,这条数据是: are mao xiang yi jd 数据正在被切割,切割出来的单词是 mao WordNormalizer类 收到一条数据,这条数据是: are mao xiang yi jd 数据正在被切割,切割出来的单词是 xiang WordNormalizer类 收到一条数据,这条数据是: are mao xiang yi jd 数据正在被切割,切割出来的单词是 yi WordNormalizer类 收到一条数据,这条数据是: are mao xiang yi jd 数据正在被切割,切割出来的单词是 jd WordCounter 计数器收到单词 are WordCounter 计数器收到单词 mao WordCounter 计数器收到单词 xiang WordCounter 计数器收到单词 yi WordCounter 计数器收到单词 jd -- Word Counter [word-counter-2] -- xi: 1 test: 1 heihei: 1 haha: 1 he: 2 storm: 1 wang: 1 jd: 1 xiang: 1 great: 1 are: 1 ni: 1 yi: 1 very: 1 mao: 1 实现计数器的功能 --完畢! 将一行文本切割成单词,并封装collector中发射出去 ---完毕! |
阅读(40) | 评论(0) | 转发(0) |
-->
Storm的wordCounter计数器详解的更多相关文章
- Storm概念、原理详解及其应用(一)BaseStorm
本文借鉴官文,添加了一些解释和看法,其中有些理解,写的比较粗糙,有问题的地方希望大家指出.写这篇文章,是想把一些官文和资料中基础.重点拿出来,能总结出便于大家理解的话语.与大多数“wordcount” ...
- (转)LR监控Linux系统性能计数器详解
从LR里面add measurement,填写linux机器的IP,出现所有unix/linux的计数器,包括cpu的,mem的,disk,network的.这里介绍几个常用的: (对于如何监控Lin ...
- CSS 计数器详解
在前端开发中总少不了列表项,对于列表项序号,射鸡师一般会列出个1,2,3...序号.在不了解css计数器属性之前,我一般会用精灵图,用类名来区分序列号图片.这样做尽管可以达到目的,但是很不方便,开发过 ...
- Storm集群安装详解
storm有两种操作模式: 本地模式和远程模式. 本地模式:你可以在你的本地机器上开发测试你的topology, 一切都在你的本地机器上模拟出来; 远端模式:你提交的topology会在一个集群的机器 ...
- css计数器详解
什么是css计数器 体验更佳排版请戳原文链接:http://blog.liuxianan.com/css-counters.html 就是采用css给一些html元素自动生成编号,比如类似1.3.2这 ...
- Storm 提交任务过程详解 (不对地方麻烦指正)
1.使用的是Storm中自带的一个测试jar包 提交下这任务到storm中去 storm jar /usr/local/app/storm/examples/storm-starter/storm-s ...
- storm学习之七-storm UI页面参数详解
http://lbxc.iteye.com/blog/1522318 --参考文章 http://blog.csdn.net/rong_89/article/details/39473917 --参考 ...
- Storm配置项详解【转】
Storm配置项详解 ——阿里数据平台技术博客:storm配置项详解 什么是Storm? Storm是twitter开源的一套实时数据处理框架,基于该框架你可以通过简单的编程来实现对数据流的实时处理变 ...
- storm源码之理解Storm中Worker、Executor、Task关系 + 并发度详解
本文导读: 1 Worker.Executor.task详解 2 配置拓扑的并发度 3 拓扑示例 4 动态配置拓扑并发度 Worker.Executor.Task详解: Storm在集群上运行一个To ...
随机推荐
- Toolbar使用
原文地址 http://www.cnblogs.com/Dentist/p/4370176.html Android4.0出现的Actionbar提供了同意方便的导航管理.很大程度的统一了Androi ...
- 【openCV学习笔记】【3】高斯模糊一张图片(_cvSmooth相关编译错误)
代码如下: #include <iostream> #include <opencv/highgui.h> #include <opencv/cv.h> void ...
- linux 目标文件 bss,data,text,rodata,堆,栈***
linux目标文件 一个简单的程序被编译成目标文件后的结构如下: 从图可以看出,已初始化的全局变量和局部静态变量保存在 .data段中,未初始化的全局变量和未初始化的局部静态变量保存在 .bss段中. ...
- c#实现QQ群成员列表导出及邮件群发之模拟QQ登陆
主题已迁移至:http://atiblogs.com/ ITO-神奇的程序员
- PS相关技术
PS相关长时间不用就忘记了,做个笔记,记录下来 (1)复制图层,可以将图层复制到另外的图层里去,这样,多个图层就可以编辑了 (2)通过建立选区,可以选择右键,通过剪切的图层,通过复制的图层将图片抠出来 ...
- java中关于length的真确理解~~~~有补充的请跟帖~~~
java中的length到底是个什么东西呢?有人说它是一个类,一个方法,如果是方法,它没有括号, 我只知道它可以得出数组的长度,但是今天遇到一段代码,怎么都解释不通,那就是绝对不会把循环的次数与数组的 ...
- PL/SQL 训练05--游标
--隐式游标--通过一个简单的SELECT ...INTO 语句提取一行数据,并放在一个局部变量中,最简单获取数据的途径 --显示游标--可以在声明单元明确的声明一个查询,这样可以在一个或多个程序中打 ...
- mybatis generator 用法
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration ...
- Java学习之Dubbo+ZooKeeper分布式服务Demo
背景:在之前的一个<Java学习之SpringBoot整合SSM Demo>分享中说到搭建ZooKeeper和Dubbo分布式框架中遇到了一些技术问题没能成功,只分享了其中的一个中间产物, ...
- ulimit open files linux打开文件数设置验证
#include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h ...