03_Storm编程上手-wordcount
1. Storm编程模型概要
消息源spout, 继承BaseRichSpout类 或 实现IRichSpout接口
1)BaseRichSpout类相对比较简单,需要覆写的方法较少,满足基本业务需求
2)IRichSpout接口,需要实现较多的框架定义好的抽象方法,部分方法和BaseRichSpout重叠,通常用于比较复杂的业务数据接入需求
重要方法
open方法: 初始化动作(传入参数,传入上下文),是spout第一个执行的方法,主类中的拓扑配置实例conf会将相关参数作为实参传入给open
nextTuple方法: 数据接入,消息tuple发射 (spout中最重要的方法)
ack方法:传入参数是object,本质是id,标识唯一一个tuple, 实现该tuple被spout成功处理后的逻辑,storm消息保证的API接口
fail方法:与ack方法对应,实现tuple处理失败后的逻辑, storm消息保证的API接口
declareOutputFields方法:声明输出字段,storm中的每个tuple都要求设置输出字段
处理单元bolt: 继承BaseBasicBolt类,或者实现IRichBolt接口
重要方法
*prepare方法:worker初始化,传递参数,声明上下文
*execute方法:接收1个tuple, 实现bolt处理逻辑,发射新tuple(最重要)
*clearup方法:worker关闭前调用,资源释放等,但不能保证该方法一定会被调用(worker进程出现问题等情况)
*declareOutputFields方法:声明输出tuple的每个字段,storm中的每个tuple都要求设置输出字段
2. wordcount代码架构
从拓扑的角度来看各个类间的关系
各个类主要功能
1. spout中随机发送内置的语句作为消息源
2. 第一组bolt进行语句切分,分离出单词,然后发送给下游bolt
3. 第二组bolt,基于字段分组策略,订阅(接收)切分好的单词,完成单词统计并将结果发送给下游
4. 最后1个bolt, 将结果打印到console
3. RandomSentenceSpout
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;
import backtype.storm.utils.Utils;
import java.util.Map;
import java.util.Random;
/**
*
* @Author: shayzhang
* @Email: shayzhang@sina.com
* @Blog: cn.blogs.com/shay-zhangjin
* @Describe: select 1 random sentence and send to next-level bolt using field streaming groups
*
*/
public class RandomSentenceSpout extends BaseRichSpout {
SpoutOutputCollector spcollector; //for emit tuple
Random random; //spout initialize, spout执行的第一个方法,主要是从conf自动传入spout发送数据的SpoutOutputCollector
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
spcollector = spoutOutputCollector;
random = new Random();
}
//generate tuple and emit
public void nextTuple() {
//每2秒发送一次tuple
Utils.sleep(2000);
String[] sentences = new String[]{
"And if the golden sun",
"four score and seven years ago",
"storm hadoop hbase spark",
"storm is a real-time processing frame-work",
"you make my night bright"
};
// select random sentence
String msg = sentences[random.nextInt(sentences.length)];
// emit tuple, doesn't assign message id
spcollector.emit(new Values(msg.trim().toLowerCase()) );
// ack tuple, successfully sent
} //每个tuple都要说明字段
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("sentence") );
}
}
4. WordNormalizserBolt
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;
import java.util.Map; /**
*
* @author: shayzhang
* @email: shayzhang@sina.com
* @blog: cn.blogs.com/shay-zhangjin
* @description: split sentence into words and emit
*
*/
public class WordNormalizerBolt implements IRichBolt {
private OutputCollector wncollector; //bolt执行的第一个方法,主类中conf对象,将相关数据推送过来,重点是获取Bolt发送数据使用的OutputCollector
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
wncollector = outputCollector;
} public void execute(Tuple tuple) {
//获取整个句子
String sentence = tuple.getString(0);
//分离出单词
String words[] = sentence.split(" ");
//发送每个单词
for(String word: words){
wncollector.emit(new Values(word));
wncollector.ack(tuple);
}
}
//Bolt退出会执行,但不能保证cleanup方法一定会被执行到(节点故障等)
public void cleanup() { }
//字段说明
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("word")); //当下游bolt通过fieldsGrouping方式获取数据时尤为重要,要保障上下游使用的Fields能够对的上
} public Map<String, Object> getComponentConfiguration() {
return null;
}
}
5. WordCountBolt
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;
import java.util.HashMap;
import java.util.Map; /**
*
* @author: shayzhang
* @email: shayzhang@sina.com
* @blog: cn.blogs.com/shay-zhangjin
* @description: count word number, emit top N
*
*/
public class WordCountBolt implements IRichBolt{
OutputCollector collector; //for emit
Map<String,Integer> counters; //for word count //init bolt, bolt执行的第一个方法,主类中的config对象自动进行参数传递
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
collector = outputCollector;
counters = new HashMap<String, Integer>(); } //统计每个单词的次数,并排序
public void execute(Tuple tuple) {
String word = tuple.getString(0); //处理收到的每一个word
if ( !counters.containsKey(word)){
counters.put(word,1);
}else{
counters.put(word, counters.get(word)+1);
} //实时输出 <word, count>
Integer length = counters.keySet().size();
Integer count = 0; for(String key:counters.keySet()){
word = "[" + new String(key) + ": " + String.valueOf(counters.get(key)) + "]";
collector.emit(new Values(word));
collector.ack(tuple);
count++;
if(count==length){
break;
} }//execute }//execute public void cleanup() { } public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("wordcount"));
} public Map<String, Object> getComponentConfiguration() {
return null;
}
}
6. PrintBolt
import backtype.storm.task.OutputCollector;
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.Fields;
import backtype.storm.tuple.Tuple;
import java.util.Map; public class PrintBolt extends BaseBasicBolt{ OutputCollector collector; public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
collector = outputCollector;
} public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) {
try {
String msg = tuple.getString(0);
if (msg != null) {
System.out.println(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
} public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("result"));
}
}
7. 主类:构建拓扑,根据是否传入参数决定运行本地模式、集群模式
import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.AlreadyAliveException;
import backtype.storm.generated.InvalidTopologyException;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.tuple.Fields;
import backtype.storm.utils.Utils; public class WordCountTopology { public static void main(String args[]) throws AlreadyAliveException, InvalidTopologyException {
//Topology配置
Config config = new Config(); //Topology构造器
TopologyBuilder builder = new TopologyBuilder(); //使用builder构建Topology
//spout, 2个executor
builder.setSpout("RandomSentence", new RandomSentenceSpout(), 2); //bolt, 2个executor, 从id为RandomSentence的spout接收tuple, shuffle方式
builder.setBolt("WordNormalizer", new WordNormalizerBolt(), 2).shuffleGrouping("RandomSentence"); //从id为“RandomSentence”的spout获取数据 //bolt, 2个executor,从id为wordNormalizer的bolt接收tuple, fields方式: 根据‘word’字段, 进行单词接收
builder.setBolt("wordcount", new WordCountBolt(), 2).fieldsGrouping("WordNormalizer", new Fields("word")); //从id为WordNormalizser的bolt获取数据,并且按照word域进行分发 //bolt, 1个executor, 收集所有结果并打印, global方式接收所有id为wordcount的bolt发出的信息
builder.setBolt("print", new PrintBolt(), 1).shuffleGrouping("wordcount"); //从id为wordcount的bolt获取数据 //设置debug, true则打印节点间交换的所有信息
config.setDebug(false); //通过是否有参数,来控制启动本地模式,集群模式
if(args!=null && args.length>0){
//有提交参数,执行集群模式
config.setNumWorkers(1); //1个worker进程
try {
//提交拓扑到storm集群, 拓扑名通过提交参数给定(args[0])
StormSubmitter.submitTopology(args[0], config, builder.createTopology());
} catch (AlreadyAliveException e) {
e.printStackTrace();
} catch (InvalidTopologyException e) {
e.printStackTrace();
}
}else{
//无提交参数,执行本地模式,调测用
//本地模式,通过LocalCluster实例提交拓扑任务
config.setMaxTaskParallelism(1);
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("WC_Local", config, builder.createTopology()); //运行5分钟后,kill该topology任务
Utils.sleep(300000);
cluster.killTopology("WC_Local");
cluster.shutdown(); } }//main
}//WordCountTopology
8. 本地模式运行
在IDEA中选择主类,直接运行即可, 从IDE终端可以看到代码是否正常运行
03_Storm编程上手-wordcount的更多相关文章
- 第三次作业-结对编程(wordcount)
GIT地址 https://github.com/gentlemanzq/WordCount.git GIT用户名 gentlemanzq 结对伙伴博客地址 https://home.cnblogs ...
- MapReduce 编程模型 & WordCount 示例
学习大数据接触到的第一个编程思想 MapReduce. 前言 之前在学习大数据的时候,很多东西很零散的做了一些笔记,但是都没有好好去整理它们,这篇文章也是对之前的笔记的整理,或者叫输出吧.一来是加 ...
- 04_Storm编程上手_WordCount集群模式运行
1. 要解决的问题:代码打包 前一篇的代码,在IDEA中通过maven工程创建,通过IDEA完成代码打包 1)File -> Project Structure 2) 选择Artifacts, ...
- Spark编程环境搭建及WordCount实例
基于Intellij IDEA搭建Spark开发环境搭建 基于Intellij IDEA搭建Spark开发环境搭——参考文档 ● 参考文档http://spark.apache.org/docs/la ...
- (升级版)Spark从入门到精通(Scala编程、案例实战、高级特性、Spark内核源码剖析、Hadoop高端)
本课程主要讲解目前大数据领域最热门.最火爆.最有前景的技术——Spark.在本课程中,会从浅入深,基于大量案例实战,深度剖析和讲解Spark,并且会包含完全从企业真实复杂业务需求中抽取出的案例实战.课 ...
- 【Visual C++】游戏编程学习笔记之一:五毛钱特效之透明和半透明处理
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44163799 作者:ZeeCod ...
- 实训任务04 MapReduce编程入门
实训任务04 MapReduce编程入门 1.实训1:画图mapReduce处理过程 使用有短句“A friend in need is a friend in deed”,画出使用MapReduce ...
- 2.4 Scala函数式编程
一.函数定义与使用 1.函数的定义 2.匿名函数 举例: Scala自动推断变量类型,不用声明: 一个下划线只能表示这一个参数的一次出现 二.高阶函数 定义:函数定义的括号里仍然是个函数的函数,叫作高 ...
- Hive实现WordCount详解
一.WordCount原理 初学MapReduce编程,WordCount作为入门经典,类似于初学编程时的Hello World.WordCount的逻辑就是给定一个/多个文本,统计出文本中每次单词/ ...
随机推荐
- 单例Singleton模式的两种实现方法
在设计模式中,有一种叫Singleton模式的,用它可以实现一次只运行一个实例.就是说在程序运行期间,某个类只能有一个实例在运行.这种模式用途比较广泛,会经常用到,下面是Singleton模式的两种实 ...
- confluence安装、破解+MariaDB驱动、汉化
下载所需文件:http://fansik.edusaas.com/confluence/安装包:atlassian-confluence-5.8.10-x64.bin 汉化包:Confluence-5 ...
- SpringMVC的映射器,适配器,控制器
一.各司其职 (1)HandlerMapping映射器 根据客户端请求的url,找到处理本次请求的处理器,即将请求的路径和controller关联起来 (2)HandlerAdapter适配器 对 ...
- [golang note] 数组切片
数组 √ golang数组包含的每个数据称为数组元素(element),数组包含的元素个数被称为数组长度(length). √ golang数组的长度在定义后不可更改,并且在声明时可以是一个常量或常量 ...
- JS:parseInt("08")或parseInt("09")转换返回0的原因
一.parseInt用法 parseInt(s); parseInt(s,radix) 二.第一个方式不再多说,第二个方式,radix是s所基于的进制.范围为2-36(不在此范围函数将返回NaN). ...
- for…else和while…else
当while语句配备else子句时,如果while子句内嵌的循环体在整个循环过程中没有执行break语句(循环体中没有break语句,或者循环体中有break语句但是始终未执行),那么循环过程结束后, ...
- Linux系统——NFS网络文件系统
在企业集群架构的工作场景中,NFS网络文件系统一般被用来存储共享视频,图片,附件等静态资源文件,通常网站用户上传的文件都会放到NFS共享里,然后前端所有的节点访问这些静态资源时都会读取NFS存储上的资 ...
- MySQL临时表的简单用法(复制)
当工作在非常大的表上时,你可能偶尔需要运行很多查询获得一个大量数据的小的子集,不是对整个表运行这些查询,而是让MySQL每次找出所需的少数记录,将记录选择到一个临时表可能更快些,然后在这些表运行查 ...
- 【web Api性能提升技巧】(2)从DataReader手工创建Json字符串
这个思路是从 一篇文章,关于<提升web api的性能>上看到的.自己实践了一番,写下步骤. 传统的DataReader是遵循这样的一个步骤: While(reader.Read()) { ...
- Ubuntu下pycharm设定任务栏图标后打开出现问号图标
事情是这样的: ubuntu16.04,安装好pycharm后,bin下只有一个sh执行文件,想要弄成任务栏图标,所以在/usr/share/applications下新建文件pycharm.desk ...