getting start with storm 翻译 第八章 part-2
转载请注明出处:http://blog.csdn.net/lonelytrooper/article/details/12435641
The Bolts
首先我们看一下该topology中的标准bolts:
public class UserSplitterBoltimplementsIBasicBolt{
private static final longserialVersionUID=1L;
@Override
public voiddeclareOutputFields(OutputFieldsDeclarerdeclarer) {
declarer.declareStream("users",newFields("txid","tweet_id","user"));
}
@Override
public Map<String,Object>getComponentConfiguration() {
return null;
}
@Override
publicvoidprepare(Map stormConf,TopologyContext context) {
}
@Override
publicvoidexecute(Tuple input,BasicOutputCollector collector) {
String tweet =input.getStringByField("tweet");
String tweetId =input.getStringByField("tweet_id");
StringTokenizer strTok =newStringTokenizer(tweet," ");
TransactionAttempt tx = (TransactionAttempt)input.getValueByField("txid");
HashSet<String>users= newHashSet<String>();
while(strTok.hasMoreTokens()) {
String user =strTok.nextToken();
// Ensure this is an actual user, and that it's not repeated in the tweet
if(user.startsWith("@") && !users.contains(user)) {
collector.emit("users",newValues(tx,tweetId,user));
users.add(user);
}
}
}
@Override
publicvoidcleanup() {
}
}
正如本章前边提到的,UserSplitterBolt接收元组,解析tweets的文本,并发送@后边的单词或者Twitter用户。HashtagSplitterBolt以一种非常简单的方式工作。
public class HashtagSplitterBoltimplementsIBasicBolt{
private static final longserialVersionUID=1L;
@Override
public voiddeclareOutputFields(OutputFieldsDeclarerdeclarer) {
declarer.declareStream("hashtags",newFields("txid","tweet_id","hashtag"));
}
@Override
public Map<String,Object>getComponentConfiguration() {
return null;
}
@Override
public voidprepare(Map stormConf,TopologyContext context) {
}
@Override
public voidexecute(Tuple input,BasicOutputCollector collector) {
String tweet =input.getStringByField("tweet");
String tweetId =input.getStringByField("tweet_id");
StringTokenizer strTok =newStringTokenizer(tweet," ");
TransactionAttempt tx = (TransactionAttempt)input.getValueByField("txid");
HashSet<String>words= newHashSet<String>();
while(strTok.hasMoreTokens()) {
String word =strTok.nextToken();
if(word.startsWith("#") && !words.contains(word)) {
collector.emit("hashtags",newValues(tx,tweetId,word));
words.add(word);
}
}
}
@Override
publicvoidcleanup() {
}
}
我们现在看下在UserHashtagJoinBolt中发生了什么。首先要注意到的最重要的事情是它是一个BaseBatchBolt。这意味着会对接收到的元组执行execute方法但不会发送任何新的元组。逐步的,当批次结束的时候,Storm会调用finishBatch方法。
public voidexecute(Tuple tuple) {
String source =tuple.getSourceStreamId();
String tweetId =tuple.getStringByField("tweet_id");
if("hashtags".equals(source)) {
String hashtag =tuple.getStringByField("hashtag");
add(tweetHashtags,tweetId,hashtag);
} else if("users".equals(source)) {
String user =tuple.getStringByField("user");
add(userTweets,user,tweetId);
}
}
因为你需要将一条tweet中所有的标签与该tweet中提到的用户关联起来并且计数他们出现的次数,你需要对前边bolt的两条流做连接。对整个批次都这样处理,一旦完成了,finishBatch方法会被调用。
@Override
publicvoidfinishBatch() {
for(String user:userTweets.keySet()) {
Set<String>tweets= getUserTweets(user);
HashMap<String,Integer>hashtagsCounter =new HashMap<String,Integer>();
for(String tweet:tweets) {
Set<String>hashtags= getTweetHashtags(tweet);
if(hashtags!=null) {
for(String hashtag:hashtags) {
Integer count =hashtagsCounter.get(hashtag);
if(count==null)
;
count ++;
hashtagsCounter.put(hashtag,count);
}
}
}
for (String hashtag:hashtagsCounter.keySet()) {
int count=hashtagsCounter.get(hashtag);
collector.emit(newValues(id,user,hashtag, count));
}
}
}
在该方法中,对每一个用户--标签以及它出现的次数,生成并发射一个元组。
你可以在GitHub看到完整的可下载的代码。
提交者 Bolts
正如你已经知道的,在topology中批量的元组被协调器和发射器发送。这些批量的元组被并行的处理,并没有特定的顺序。
coordinator bolts或者是实现了ICommitter接口的特殊批量bolts,或者它在TransactionalTopologyBuilder中被用setCommiterBolt方法设置过。它与常规的批量bolts的主要不同在于当该批次准备好被提交时会执行提交者 bolts的finishBatch方法。这在所有前边的事务被成功的提交后会发生。另外,finishBatch方法被顺序的执行。所以,当事务ID为1的批次和事务ID为2的批次在topology中被并行的处理时,正在处理事务ID为2的批次的提交者bolt的finishBatch方法只有在事务ID为1的批次的finishBatch方法结束并且没有任何错误的情况下才会被执行。
该类的实现如下:
public class RedisCommiterCommiterBoltextendsBaseTransactionalBolt
implements ICommitter{
public static final String LAST_COMMITED_TRANSACTION_FIELD="LAST_COMMIT";
TransactionAttempt id;
BatchOutputCollector collector;
Jedis jedis;
@Override
public voidprepare(Map conf,TopologyContext context,
BatchOutputCollector collector,TransactionAttempt id) {
this.id=id;
this.collector=collector;
this.jedis=newJedis("localhost");
}
HashMap<String,Long>hashtags = new HashMap<String,Long>();
HashMap<String,Long>users = newHashMap<String,Long>();
HashMap<String,Long>usersHashtags =new HashMap<String,Long>();
private voidcount(HashMap<String,Long>map, String key,intcount) {
Long value =map.get(key);
if(value==null)
;
value +=count;
map.put(key,value);
}
@Override
public voidexecute(Tuple tuple) {
String origin =tuple.getSourceComponent();
if("users-splitter".equals(origin)) {
String user =tuple.getStringByField("user");
);
} else if("hashtag-splitter".equals(origin)) {
String hashtag =tuple.getStringByField("hashtag");
);
} else if("user-hashtag-merger".equals(origin)) {
String hashtag =tuple.getStringByField("hashtag");
String user =tuple.getStringByField("user");
String key =user+ ":" + hashtag;
Integer count =tuple.getIntegerByField("count");
count(usersHashtags,key,count);
}
}
@Override
publicvoidfinishBatch() {
String lastCommitedTransaction = jedis.get(LAST_COMMITED_TRANSACTION_FIELD);
String currentTransaction =""+id.getTransactionId();
if(currentTransaction.equals(lastCommitedTransaction))
return;
Transaction multi =jedis.multi();
multi.set(LAST_COMMITED_TRANSACTION_FIELD,currentTransaction);
Set<String>keys= hashtags.keySet();
for(String hashtag:keys) {
Long count =hashtags.get(hashtag);
multi.hincrBy("hashtags",hashtag,count);
}
keys =users.keySet();
for(String user:keys) {
Long count = users.get(user);
multi.hincrBy("users",user,count);
}
keys =usersHashtags.keySet();
for(String key:keys) {
Long count =usersHashtags.get(key);
multi.hincrBy("users_hashtags",key,count);
}
multi.exec();
}
@Override
publicvoiddeclareOutputFields(OutputFieldsDeclarer declarer) {
}
}
这些都很直观,但是在finishBatch方法中有一个非常重要的细节。
...
multi.set(LAST_COMMITED_TRANSACTION_FIELD,currentTransaction);
...
这里你正在存储上一个被提交的事务ID到数据库。你为什么要那样做?记住当一个事务失败时,如果有必要的话Storm将重放它足够多次。如果你不确定你已经处理过该事务,那么你可以高估,这样整个topology的事务性含义都没意义了。所以记住:存储上一个被提交的事务ID并且提交前核对它。
getting start with storm 翻译 第八章 part-2的更多相关文章
- getting start with storm 翻译 第八章 part-1
转载请注明出处:http://blog.csdn.net/lonelytrooper/article/details/12434915 第八章 事务性Topologies 在Storm中,正如本书前边 ...
- 大数据入门第十六天——流式计算之storm详解(一)入门与集群安装
一.概述 今天起就正式进入了流式计算.这里先解释一下流式计算的概念 离线计算 离线计算:批量获取数据.批量传输数据.周期性批量计算数据.数据展示 代表技术:Sqoop批量导入数据.HDFS批量存储数据 ...
- The Django Book
The Django Book Table of contents 2.0, English -> Chinese Django book 2.0 的中文翻译. 最近更新 - 贡献者 方便自己也 ...
- 深入理解Magento – 第四章 – 模型和ORM基础
深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第四章 – 模型和ORM基础 对于任何一个MVC架构,模型(Model)层的实现都是占据了很大一部分.对于Mage ...
- 深入理解Magento – 第三章 – 布局,块和模板
深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第三章 – 布局,块和模板 我们接着研究Magento.根据我们第二章讲的Magento MVC的架构,我们接下来 ...
- 深入理解Magento – 第二章 – Magento请求分发与控制器
深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第二章 – Magento请求分发与控制器 Model-View-Controller (MVC) ,模型-视图- ...
- 深入理解Magento - 第一章 - Magento强大的配置系统
深入理解Magento 作者:Alan Storm翻译:zhlmmc 前言第一章 - Magento强大的配置系统第二章 - Magento请求分发与控制器第三章 - 布局,块和模板第四章 - 模型和 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (42) ------ 第八章 POCO之使用POCO
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第八章 POCO 对象不应该知道如何保存它们,加载它们或者过滤它们.这是软件开发中熟 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (46) ------ 第八章 POCO之领域对象测试和仓储测试
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-8 测试领域对象 问题 你想为领域对象创建单元测试. 这主要用于,测试特定的数 ...
随机推荐
- SQL Server中的死锁
简介 死锁的本质是一种僵持状态,是多个主体对于资源的争用而导致的.理解死锁首先需要对死锁所涉及的相关观念有一个理解. 一些基础知识 要理解SQL Server中的死锁,更好的方式是通过类比从更大的面理 ...
- [转]一个备份MySQL数据库的简单Shell脚本
本文翻译自 iSystemAdmin 的 <A Simple Shell Script to Backup MySQL Database> Shell脚本是我们写不同类型命令的一种脚本,这 ...
- cocos2dx JAVA,C++互相调用函数
C++调用JAVA 例子 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "platform/android/jni/Jni ...
- 【BZOJ1036】【树链剖分】树的统计Count
Description 一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. ...
- SQL服务器名称的更改
SQL服务器名称的更改 1.使用select @@ServerName可以看到当前数据库的服务器名称 2.从Sys.SysServers表中可以看到当前的所有服务器名称 3.使用 sp_drops ...
- ng的数据绑定
ng创建了一个自己的事件循环,当浏览器事件(常用的dom事件,xhr事件等)发生时,对DOM对应的数据进行检查,若更改了,则标记为脏值,并进入更新循环,修改对应的(可能是多个) DOM的参数.这样就实 ...
- 浏览器中的WebSocket("ws://127.0.0.1:9988");
<script type="text/javascript"> function WebSocketTest() { if ("WebSocket" ...
- Java常量和变量
1.Java运行原理 编译+解释型语言: 程序代码经编译后转换为一种称为java字节码(.class文件)的中间语言 file.java--->Class.class java虚拟机JVM将字节 ...
- 如何用DOS 链接mysql
1.Ctrl+R 打开DOS窗口 2.键入 cd\ 回车进入C盘根目录 3.进入mysql bin目录下 操作mysql命令 4.输入连接数据库命令 mysql -hlocalhost -uroot ...
- 在iOS7中修改状态栏字体的颜色-b
状态栏的字体为黑色: UIStatusBarStyleDefault 状态栏的字体为白色: UIStatusBarStyleLightContent 一.在 info.plist 中,将 View ...