欢迎转载,转载请注意出处,徽沪一郎。

“源码走读系列”从代码层面分析了storm的具体实现,接下来通过具体的实例来说明storm的使用。因为目前storm已经正式迁移到Apache,文章系列也由twitter storm转为apache storm.

WordCountTopology 使用storm来统计文件中的每个单词的出现次数。

通过该例子来说明tuple发送时的几个要素

  1. source component   发送源
  2. destination component 接收者
  3. stream 消息通道
  4. tuple    消息本身

本文涉及到的开发环境搭建可以参考前面的两篇博文。

  1. arch linux简明安装指南
  2. 在archlinux上搭建storm cluster

awk实现

其实对文件中的单词进行统计是Linux下一个很常见的任务,用awk就可以轻松的解决(如果文件不是太大的话),下面是进行word counting的awk脚本,将其保存为名为wordcount.awk文件。

wordcount.awk

{
for (i = ; i<=NF; i++)
freq[$i]++
}
END{
for (word in freq)
printf "%s\t%d\n",word,freq[word]
}

运行该脚本,对文件中的单词进行统计

gawk -f wordcount.awk filename

原始版本

从github上复制内容

git clone https://github.com/nathanmarz/storm-starter.git

编译运行

lein deps
lein compile
java -cp $(lein classpath) WordCountTopology

main函数

main函数的主要内容

    TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("spout", new RandomSentenceSpout(), 5);
builder.setBolt("split", new SplitSentence(), 8).shuffleGrouping("spout");
builder.setBolt("count", new WordCount(), 12).fieldsGrouping("split", new Fields("word"));

注意:grouping操作的时候,如果没有显示指定stream id,则使用的是default stream. 如shuffleGrouping("spout")表示从名为spout的component中接收从default stream发送过来的tuple.

改进版本

在原始版本中,spout不停的向split bolt随机发送句子,Count bolt统计每个单词出现的次数。

那么能不能让Spout在读取完文件之后,通知下游的bolt显示最柊的统计结果呢?

要想达到上述的改进目标,采用如上图所示的结构即可。改变的地方如下,

  1. 在Spout中添加一个SUCCESS_STREAM
  2. 添加只有一个运行实例的statistics bolt
  3. 当spout读取完文件内容之后,通过SUCCESS_STREAM告诉statistics bolt,文件已经处理完毕,可以打印当前的统计结果

RandomSentenceSpout.java

declareOutputFields

添加SUCCESS_STREAM

@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
declarer.declareStream("SUCCESS_STREAM",new Fields("word"));
}

nextTuple

使用SUCCESS_STREAM通知下游,文件处理完毕

@Override
public void nextTuple() {
Utils.sleep(100);
String[] sentences = new String[]{ "the cow jumped over the moon", "an apple a day keeps the doctor away",
"four score and seven years ago", "snow white and the seven dwarfs", "i am at two with nature" };
if ( count == sentences.length )
{
System.out.println(count+" try to emit tuple by success_stream");
_collector.emit("SUCCESS_STREAM",new Values(sentences[0]));
count++;
}else if ( count < sentences.length ){
_collector.emit(new Values(sentences[count]));
count++;
}
}

WordCountTopology.java

添加静态类WordCount2

public static class WordCount2 extends BaseBasicBolt {
Map<String, Integer> counts = new HashMap<String, Integer>(); @Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
if ( tuple.getSourceStreamId() == "SUCCESS_STREAM" ) {
System.out.println("prepare to print the statistics");
for (String key : counts.keySet()) {
System.out.println(key+"\t"+counts.get(key));
}
System.out.println("finish printing");
}else { String word = tuple.getString(0);
Integer count = counts.get(word);
if (count == null)
count = 0;
count++;
counts.put(word, count);
}
}

main函数

将spout的并行数由5改为1

 builder.setSpout("spout", new RandomSentenceSpout(), 1);

在原有的Topology中添加WordCount2 Bolt

 builder.setBolt("count2", new WordCount2(), 1).globalGrouping("count").globalGrouping("spout","SUCCESS_STREAM");

WordCount2 Bolt会接收从Count Bolt通过default stream发送的tuple,同时接收Spout通过SUCCESS_STREAM发送的tuple,也就是说wordcount2会接收从两个stream来的数据。

编译

编译修改后的源文件

cd $STROM_STARTER
lein compile storm.starter

可能会出现以下异常信息,该异常可以忽略。

Exception in thread "main" java.io.FileNotFoundException: Could not locate storm/starter/WordCountTopology__init.class or storm/starter/WordCountTopology.clj on classpath:

运行

在local模式下运行修改后的WordCountTopology

java -cp $(lein classpath) storm.starter.WordCountTopology

如果一切正常,日志如下所示,线程的名字可能会有所不同。

moon    1
score    1
cow    1
doctor    1
over    1
nature    1
snow    1
four    1
keeps    1
with    1
a    1
white    1
dwarfs    1
at    1
the    4
and    2
i    1
two    1
away    1
seven    2
apple    1
am    1
an    1
jumped    1
day    1
years    1
ago    1

结果验证

可以将WordCountTopology的运行结果和awk脚本的运行结果相比对,结果应该是一致的。

小技巧

  1. awk脚本的执行结果存为一个文件result1.log, WordCountTopology的输出中单词统计部分存为result2.log
  2. 用vim打开result1.log,进行sorting,保存结果;用vim打开result2.log,进行sorting,保存。
  3. 然后用vimdiff来进行比较 vimdiff result1.log result2.log

Apache Storm技术实战之1 -- WordCountTopology的更多相关文章

  1. Apache Storm技术实战之3 -- TridentWordCount

    欢迎转载,转载请注明出处. 介绍TridentTopology的使用,重点分析newDRPCStream和stateQuery的实现机理. 使用TridentTopology进行数据处理的时候,经常会 ...

  2. Apache Storm技术实战之2 -- BasicDRPCTopology

    欢迎转载,转载请注明出处,徽沪一郎. 本文通过BasicDRPCTopology的实例来分析DRPCTopology在提交的时候, Topology中究竟含有哪些内容? BasicDRPCTopolo ...

  3. Apache Spark技术实战之6 --Standalone部署模式下的临时文件清理

    问题导读 1.在Standalone部署模式下,Spark运行过程中会创建哪些临时性目录及文件? 2.在Standalone部署模式下分为几种模式? 3.在client模式和cluster模式下有什么 ...

  4. Apache Spark技术实战之4 -- 利用Spark将json文件导入Cassandra

    欢迎转载,转载请注明出处. 概要 本文简要介绍如何使用spark-cassandra-connector将json文件导入到cassandra数据库,这是一个使用spark的综合性示例. 前提条件 假 ...

  5. Apache Spark技术实战之3 -- Spark Cassandra Connector的安装和使用

    欢迎转载,转载请注明出处,徽沪一郎. 概要 前提 假设当前已经安装好如下软件 jdk sbt git scala 安装cassandra 以archlinux为例,使用如下指令来安装cassandra ...

  6. Apache Spark技术实战之9 -- 日志级别修改

    摘要 在学习使用Spark的过程中,总是想对内部运行过程作深入的了解,其中DEBUG和TRACE级别的日志可以为我们提供详细和有用的信息,那么如何进行合理设置呢,不复杂但也绝不是将一个INFO换为TR ...

  7. Apache Spark技术实战之8:Standalone部署模式下的临时文件清理

    未经本人同意严禁转载,徽沪一郎. 概要 在Standalone部署模式下,Spark运行过程中会创建哪些临时性目录及文件,这些临时目录和文件又是在什么时候被清理,本文将就这些问题做深入细致的解答. 从 ...

  8. Apache Spark技术实战之7 -- CassandraRDD高并发数据读取实现剖析

    未经本人同意,严禁转载,徽沪一郎. 概要 本文就 spark-cassandra-connector 的一些实现细节进行探讨,主要集中于如何快速将大量的数据从cassandra 中读取到本地内存或磁盘 ...

  9. Apache Spark技术实战之6 -- spark-submit常见问题及其解决

    除本人同意外,严禁一切转载,徽沪一郎. 概要 编写了独立运行的Spark Application之后,需要将其提交到Spark Cluster中运行,一般会采用spark-submit来进行应用的提交 ...

随机推荐

  1. 化工厂装箱员(洛谷 P2530)

    题目描述 118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须 ...

  2. 【Ubuntu日常技巧】【解决】Ubuntu 16 右上角的音量调节通知框不停地闪烁问题

    一. 先上干货 解决问题 1.1 安装工具alsa-tools-gui sudo apt-get install alsa-tools-gui 1.2 通过hdajackretask设置 直接执行命令 ...

  3. Java Hour 54 Spring Framework 1

    总之,Srping Framework 很好很强大. 1 Spring Framework 介绍 省下你和transcation APIs, JMX APIs, JMS APIs 交流的功夫. 1.1 ...

  4. kinect学习笔记(一)—— Openni平台的搭建~、

    一.简述         Openni平台是开源的平台,也就是说所有的源代码都可以查询,可以有助于我们对于整个程序框架的学习和理解,相对于微软的SDK,我更倾向于这个平台,但是由于个各种原因,现在这个 ...

  5. 源码安装Memcached服务器及其2种PHP客户端

    本文所用源码包皆为当时最新stable稳定版. 安装memcached服务器 先安装libevent, 最新版为2.0.21 tar -zxvf libevent-2.0.21-stable.tar. ...

  6. 浅析C#中的Attribute(转)

    最近用到了,所以静下心来找些资料看了一下,终于把这东西搞清楚了. 一.什么是Attribute 先看下面的三段代码: 1.自定义Attribute类:VersionAttribute [Attribu ...

  7. HTML-Canvas03

    颜色合成 globalCompositeOperation 属性: //先绘制一个图形. ctx.fillStyle = "#00ff00"; ctx.fillRect(10,10 ...

  8. 自爽:DOTNET 笔试题

    2-3年经验估计,求轻拍~ 在多态中,经常用到virtual和abstract,请问区别是什么?并描述其适用场景. 请描述Action,Action<T>,Func<T>,Fu ...

  9. TYVJ P1036 统计数字 Label:坑!!!(用queue+map做出来的水)

    背景 NOIP2007年提高组第一题 描述 某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*109).已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数 ...

  10. ajax返回数据解析总结

    ajax即异步 JavaScript 和 XML(Asynchronous JavaScript and XML). 简短地说,在不重载整个网页的情况下,AJAX 通过后台加载数据,并在网页上进行显示 ...