getting start with storm 翻译 第八章 part-2

时间:2022-11-10 21:59:12

转载请注明出处: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的更多相关文章

  1. getting start with storm 翻译 第八章 part-1

    转载请注明出处:http://blog.csdn.net/lonelytrooper/article/details/12434915 第八章 事务性Topologies 在Storm中,正如本书前边 ...

  2. 大数据入门第十六天——流式计算之storm详解(一)入门与集群安装

    一.概述 今天起就正式进入了流式计算.这里先解释一下流式计算的概念 离线计算 离线计算:批量获取数据.批量传输数据.周期性批量计算数据.数据展示 代表技术:Sqoop批量导入数据.HDFS批量存储数据 ...

  3. The Django Book

    The Django Book Table of contents 2.0, English -> Chinese Django book 2.0 的中文翻译. 最近更新 - 贡献者 方便自己也 ...

  4. 深入理解Magento – 第四章 – 模型和ORM基础

    深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第四章 – 模型和ORM基础 对于任何一个MVC架构,模型(Model)层的实现都是占据了很大一部分.对于Mage ...

  5. 深入理解Magento – 第三章 – 布局,块和模板

    深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第三章 – 布局,块和模板 我们接着研究Magento.根据我们第二章讲的Magento MVC的架构,我们接下来 ...

  6. 深入理解Magento – 第二章 – Magento请求分发与控制器

    深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第二章 – Magento请求分发与控制器 Model-View-Controller (MVC) ,模型-视图- ...

  7. 深入理解Magento - 第一章 - Magento强大的配置系统

    深入理解Magento 作者:Alan Storm翻译:zhlmmc 前言第一章 - Magento强大的配置系统第二章 - Magento请求分发与控制器第三章 - 布局,块和模板第四章 - 模型和 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 &lpar;42&rpar; ------ 第八章 POCO之使用POCO

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第八章 POCO 对象不应该知道如何保存它们,加载它们或者过滤它们.这是软件开发中熟 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 &lpar;46&rpar; ------ 第八章 POCO之领域对象测试和仓储测试

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-8  测试领域对象 问题 你想为领域对象创建单元测试. 这主要用于,测试特定的数 ...

随机推荐

  1. shell中&dollar;0&comma;&dollar;&quest;&comma;&dollar;&excl;等变量意义

    变量说明:   $$     #Shell本身的PID(ProcessID) $!     #Shell最后运行的后台Process的PID $?     #最后运行的命令的结束代码(返回值) $- ...

  2. 转:VC include 路径解析

    VC include 路径解析 要了解vc中使用#include命令包含头文件所搜寻的路径,必须先了解vc中的几种路径: 1. 系统路径 系统路径在vc中是"Tools->Option ...

  3. 前端自动化神器LiveReload配合浏览器和less&sol;sass使用方法

    前言:搜了半天,各种推荐,什么十大工具啦.优秀工具集合啦之类的咸淡文章,就是没有一个讲怎么弄的.配合官网的article自己研究了半天总算配置好了.顺便吐槽下官网关于sass/less设置这块说的模糊 ...

  4. javascript进行url转义方法比较escape、encodeURI和encodeURIComponent

    escape会将除了 ASCII 字母.数字和特定的符号(* @ - _ + . /)以外的字符全部进行转义编码,因此如果想对URL编码,最好不要使用此方法,因为它会让你的URL变的不可读. 提示:E ...

  5. 深入浅出ES6(十):集合

    作者 Jason Orendorff  github主页  https://github.com/jorendorff 前段时间,官方名为“ECMA-262,第六版,ECMAScript 2015语言 ...

  6. Remarks on a preprint

    Page 2 Line 1, "reads" should be "read". Page 2 Line 5, "are initial veloci ...

  7. fastjson将bean转成字符串时首字母变小写问题

    一个项目需求要求返回值为JSON格式,且大多数字段是首字母大写,还有些是类似N_TX这样的格式,在输出这样的结果时遇到了问题,由于时间紧,就直接拷贝需要的结果字段建立JavaBean类,本以为最后直接 ...

  8. 窗口绘制有关的消息整理 WM&lowbar;PAINT&comma; WM&lowbar;NCPAINT&comma; WM&lowbar;ERASEBKGND

    WM_PAINTWM_PAINT是Windows窗口系统中一条重要的消息,应用程序通过处理该消息实现在窗口上的绘制工作. WM_NCPAINT当窗口客户区以外的部分(如窗口标题栏.菜单栏等)需要需要重 ...

  9. The Elements of Statistical Learning第3章导读

    1. 公式(3.4)的推导. 可以直接对公式(3.3)中的$\beta_0$求导就得到$\hat{\beta}_0=\bar{y}-\beta_1\bar{x}$. 对公式(3.3)中的$\beta_ ...

  10. 让 &period;NET 更方便的导入导出 Excel

    让 .Net 更方便的导入导出Excel Intro 因为前一段时间需要处理一些 excel 数据,主要是导入/导出操作,将 Excel 数据转化为对象再用程序进行处理和分析,没有找到比较满意的库,于 ...