storm编程指南

@(博客文章)[storm|大数据]

本文介绍了storm的基本编程,关于trident的编程,请见???

本示例使用storm运行经典的wordcount程序,拓扑如下:

sentence-spout—>split-bolt—>count-bolt—>report-bolt

分别完成句子的产生、拆分出单词、单词数量统计、统计结果输出

完整代码请见 https://github.com/jinhong-lu/stormdemo

以下是关键代码的分析。

(一)创建spout

public class SentenceSpout extends BaseRichSpout {
private SpoutOutputCollector collector;
private int index = 0;
private String[] sentences = { "when i was young i'd listen to the radio",
"waiting for my favorite songs", "when they played i'd sing along",
"it make me smile",
"those were such happy times and not so long ago",
"how i wondered where they'd gone",
"but they're back again just like a long lost friend",
"all the songs i love so well", "every shalala every wo'wo",
"still shines.", "every shing-a-ling-a-ling",
"that they're starting", "to sing so fine"}; public void open(Map conf, TopologyContext context,
SpoutOutputCollector collector) {
this.collector = collector;
} public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("sentence"));
} public void nextTuple() {
this.collector.emit(new Values(sentences[index]));
index++;
if (index >= sentences.length) {
index = 0;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
//e.printStackTrace();
}
}
}

上述类中,将string数组中内容逐行发送出去,主要的方法有:

(1)open()方法完成spout的初始化工作,与bolt的prepare()方法类似

(2)declareOutputFileds()定义了发送内容的字段名称与字段数量,bolt中的方法名称一样。

(3)nextTuple()方法是对每一个需要处理的数据均会执行的操作,也bolt的executor()方法类似。它是整个逻辑处理的核心,通过emit()方法将数据发送到拓扑中的下一个节点。

(二)创建split-bolt

public class SplitSentenceBolt extends BaseRichBolt{
private OutputCollector collector; public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.collector = collector;
} public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
} public void execute(Tuple input) {
String sentence = input.getStringByField("sentence");
String[] words = sentence.split(" ");
for(String word : words){
this.collector.emit(new Values(word));
//System.out.println(word);
}
}
}

三个方法的含义与spout类似,这个类根据空格把收到的句子进行拆分,拆成一个一个的单词,然后把单词逐个发送出去。

input.getStringByField("sentence”)可以根据上一节点发送的关键字获取到相应的内容。

(三)创建wordcount-bolt

public class WordCountBolt extends BaseRichBolt{
private OutputCollector collector;
private Map<String,Long> counts = null; public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.collector = collector;
this.counts = new HashMap<String, Long>();
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word","count"));
} public void execute(Tuple input) {
String word = input.getStringByField("word");
Long count = this.counts.get(word);
if(count == null){
count = 0L;
}
count++;
this.counts.put(word, count);
this.collector.emit(new Values(word,count));
//System.out.println(count);
}
}

本类将接收到的word进行数量统计,并把结果发送出去。

这个bolt发送了2个filed:

        declarer.declare(new Fields("word","count"));
this.collector.emit(new Values(word,count));

(四)创建report-bolt

public class ReportBolt extends BaseRichBolt{
private Map<String, Long> counts; public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.counts = new HashMap<String,Long>();
}
public void declareOutputFields(OutputFieldsDeclarer declarer) { } public void execute(Tuple input) {
String word = input.getStringByField("word");
Long count = input.getLongByField("count");
counts.put(word, count);
} public void cleanup() {
System.out.println("Final output");
Iterator<Entry<String, Long>> iter = counts.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Long> entry = iter.next();
String word = (String) entry.getKey();
Long count = (Long) entry.getValue();
System.out.println(word + " : " + count);
} super.cleanup();
} }

本类将从wordcount-bolt接收到的数据进行输出。

先将结果放到一个map中,当topo被关闭时,会调用cleanup()方法,此时将map中的内容输出。

(五)创建topo

public class WordCountTopology {
private static final String SENTENCE_SPOUT_ID = "sentence-spout";
private static final String SPLIT_BOLT_ID = "split-bolt";
private static final String COUNT_BOLT_ID = "count-bolt";
private static final String REPORT_BOLT_ID = "report-bolt";
private static final String TOPOLOGY_NAME = "word-count-topology"; public static void main(String[] args) {
SentenceSpout spout = new SentenceSpout();
SplitSentenceBolt splitBolt = new SplitSentenceBolt();
WordCountBolt countBolt = new WordCountBolt();
ReportBolt reportBolt = new ReportBolt(); TopologyBuilder builder = new TopologyBuilder(); builder.setSpout(SENTENCE_SPOUT_ID, spout);
builder.setBolt(SPLIT_BOLT_ID, splitBolt).shuffleGrouping(
SENTENCE_SPOUT_ID);
builder.setBolt(COUNT_BOLT_ID, countBolt).fieldsGrouping(SPLIT_BOLT_ID,
new Fields("word"));
builder.setBolt(REPORT_BOLT_ID, reportBolt).globalGrouping(
COUNT_BOLT_ID); Config conf = new Config(); if (args.length == 0) {
LocalCluster cluster = new LocalCluster(); cluster.submitTopology(TOPOLOGY_NAME, conf,
builder.createTopology());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
cluster.killTopology(TOPOLOGY_NAME);
cluster.shutdown();
} else {
try {
StormSubmitter.submitTopology(args[0], conf,builder.createTopology());
} catch (AlreadyAliveException e) {
e.printStackTrace();
} catch (InvalidTopologyException e) {
e.printStackTrace();
} }
}
}

关键步骤为:

(1)创建TopologyBuilder,并为这个builder指定spout与bolt

        builder.setSpout(SENTENCE_SPOUT_ID, spout);
builder.setBolt(SPLIT_BOLT_ID, splitBolt).shuffleGrouping(
SENTENCE_SPOUT_ID);
builder.setBolt(COUNT_BOLT_ID, countBolt).fieldsGrouping(SPLIT_BOLT_ID,
new Fields("word"));
builder.setBolt(REPORT_BOLT_ID, reportBolt).globalGrouping(
COUNT_BOLT_ID);

(2)创建conf对象

    Config conf = new Config();

这个对象用于指定一些与拓扑相关的属性,如并行度、nimbus地址等。

(3)创建并运行拓扑,这里使用了2种方式

一是当没有参数时,建立一个localcluster,在本地上直接运行,运行10秒后,关闭集群:

LocalCluster cluster = new LocalCluster();
cluster.submitTopology(TOPOLOGY_NAME, conf,builder.createTopology());
Thread.sleep(10000);
cluster.killTopology(TOPOLOGY_NAME);
cluster.shutdown();

二是有参数是,将拓扑提交到集群中:

StormSubmitter.submitTopology(args[0], conf,builder.createTopology());

第一个参数为拓扑的名称。

6、本地运行

直接在eclipse中运行即可,输出结果在console中看到

7、集群运行

(1)编译并打包

mvn clean compile

(2)把编译好的jar包上传到nimbus机器上,然后

storm jar com.ljh.storm.5_stormdemo  com.ljh.storm.wordcount.WordCountTopology  topology_name

将拓扑提交到集群中。

storm编程指南的更多相关文章

  1. storm-kafka编程指南

    目录 storm-kafka编程指南 一.原理及关键步骤介绍 (一)使用storm-kafka的关键步骤 1.创建ZkHosts 2.创建KafkaConfig 3.设置MultiScheme 4.创 ...

  2. trident原理及编程指南

    目录 trident原理及编程指南 一.理论介绍 1.trident是什么? 2.trident处理单位 3.事务类型 二.编程指南 1.定义输入流 2.统计单词数量 3.输出统计结果 4.split ...

  3. OpenGL编程指南(第七版)

    OpenGL编程指南(第七版) 转自:http://blog.csdn.net/w540982016044/article/details/21287645 在接触OpenGL中,配置显得相当麻烦,特 ...

  4. 编译opengl编程指南第八版示例代码通过

    最近在编译opengl编程指南第八版的示例代码,如下 #include <iostream> #include "vgl.h" #include "LoadS ...

  5. 高质量C++/C编程指南(林锐)

    推荐-高质量C++/C编程指南(林锐) 版本/状态 作者 参与者 起止日期 备注 V 0.9 草稿文件 林锐   2001-7-1至 2001-7-18 林锐起草 V 1.0 正式文件 林锐   20 ...

  6. iOS ---Extension编程指南

    当iOS 8.0和OS X v10.10发布后,一个全新的概念出现在我们眼前,那就是应用扩展.顾名思义,应用扩展允许开发者扩展应用的自定义功能和内容,能够让用户在使用其他app时使用该项功能.你可以开 ...

  7. Lambda 表达式(C# 编程指南) 微软microsoft官方说明

    Visual Studio 2013 其他版本 Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地 ...

  8. KVC/KVO原理详解及编程指南

    一.简介 1.KVC简介 2.KVO简介 二.KVC相关技术 1.Key和Key Path 2.点语法和KVC 3.一对多关系(To-Many)中的集合访问器方法 4.键值验证(Key-Value V ...

  9. iOS多线程编程指南(二)线程管理

    当应用程序生成一个新的线程的时候,该线程变成应用程序进程空间内的一个实体.每个线程都拥有它自己的执行堆栈,由内核调度独立的运行时间片.一个线程可以和其他线程或其他进程通信,执行I/O操作,甚至执行任何 ...

随机推荐

  1. touch---创建文件或更改文件日期

  2. python2 python3 m2crypto 安装(rsa 私钥文件加密)

    转自作者:大道至简_Andy 原文链接:https://www.jianshu.com/p/b308357ef649 第一种方式:使用apt-get(以Python2版本进行测试的) sudo apt ...

  3. 18/9/21模拟赛-Updated

    18/9/21模拟赛 期望得分:100:实际得分:0  qwq 拿到题目第一眼,我去,这不是洛谷原题(仓鼠找Sugar)吗 又多看了几眼,嗯,对,除了是有多组数据外,就是原题 然后码码码....自以为 ...

  4. 【Codecraft-18 and Codeforces Round #458 (Div. 1 + Div. 2, combined) B】 Conan and Agasa play a Card Game

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 最大值出现次数是偶数. 那么就取次大值. 次大值也是偶数? =>再次 因为你绝对不能取偶数个的. 取了对方就总是能面对一个奇数 ...

  5. 【Codeforces Round #426 (Div. 2) B】The Festive Evening

    [Link]:http://codeforces.com/contest/834/problem/B [Description] [Solution] 模拟水题; 注意一个字母单个出现的时候,结束和开 ...

  6. HTML中行内元素与块级元素有哪些及区别

    二.行内元素与块级元素有什么不同? 块级元素和行内元素的区别是,块级元素会占一行显示,而行内元素可以在一行并排显示. 通过样式控制,它们可以相互转换. 1.尺寸-块级元素和行内元素之间的一个重要的不同 ...

  7. malloc,colloc,realloc内存分配,动态库,静态库的生成与调用

     1.在main方法里面直接定义一个很大的数组的时候.可能会出现栈溢出:错误代码演示: #include<stdio.h> #include<stdlib.h> void ...

  8. 欧洲的VPS 1天内收到几万次ssh端口访问,99%的访问量来自中国

    欧洲的VPS 1天内收到几万次ssh端口访问,99%的访问量来自中国 前几天开了个欧洲的VPS,当备用的,没怎么用.就这样的VPS在1天之内也收到不少来自中国网民的见面礼 用了别人的一条命令: gre ...

  9. git 工具的使用总结(6)-提交合并处理

    1.撤消修改 1)revert:反转提交,它就是把你的一个提交先撤消掉,但是,它跟reset不同的是,你的这次这小会留下记录,这样在你下次需要的时候,可以通过这个节点把撤消的提交恢复 zhangshu ...

  10. 前端项目中常用es6知识总结 -- let、const及数据类型延伸

    项目开发中一些常用的es6知识,主要是为以后分享小程序开发.node+koa项目开发以及vueSSR(vue服务端渲染)做个前置铺垫. 项目开发常用es6介绍 1.块级作用域 let const  2 ...