storm

实例来自书籍《Oreilly.Getting.Started.with.Storm.Aug.2012》

先讲下我们这次所需涉及到的概念:Topology、Spout、Blot

Topology:Storm的运行单位,相当于Hadoop中的job,一个topology是spouts和bolts组成的图, 通过stream groupings将图中的spouts和bolts连接起来


Spout:消息源,topology里面的消息生产者,一般来说消息源会从一个外部源读取数据并且向topology里面发出消息:tuple。

Blot:所有的消息处理逻辑被封装在bolts里面。Bolts可以做很多事情:过滤,聚合,查询数据库等等。

一下是实例的流程图


words.txt--将要执行wordcount操作的文件

[plain]  view plain copy
  1. storm  
  2. test  
  3. are  
  4. great  
  5. is  
  6. an  
  7. storm  
  8. simple  
  9. application  
  10. but  
  11. very  
  12. powerfull  
  13. really  
  14. StOrm  
  15. is  
  16. great  

1、Topology的创建

[java]  view plain copy
  1. <span style="white-space:pre">  </span>//Topology definition  
  2.     TopologyBuilder builder = new TopologyBuilder();  
  3.     builder.setSpout("word-reader",new WordReader());  
  4.     builder.setBolt("word-normalizer"new WordNormalizer())  
  5.         .shuffleGrouping("word-reader");  
  6.     builder.setBolt("word-counter"new WordCounter(),1)  
  7.         .fieldsGrouping("word-normalizer"new Fields("word"));  
  8.       
  9.        //Configuration  
  10.     Config conf = new Config();  
  11.     conf.put("wordsFile", args[0]);  
  12.     conf.setDebug(false);  
  13.        //Topology run  
  14.     conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 1);  
  15.     LocalCluster cluster = new LocalCluster();  
  16.     cluster.submitTopology("Getting-Started-Toplogie", conf, builder.createTopology());  
  17.     Thread.sleep(1000);  
  18.     cluster.shutdown();  
从上面代码我们可以看到,Topology是通过TopologyBuilder的createTopology来创建。通过TopologyBuilder对象设置Spout以及Blot。

Config对象用于设置集群计算所需的参数,这里的参数是要执行wordcount操作的文件路径。

例子是以本地集群方式运行。

Topology提交通过cluster对象的submitTopology方法来提交。参数包括任务名、配置、以及Topology对象。

注:我们可以看下这里的TopologyBuilder对象的创建。

[java]  view plain copy
  1. TopologyBuilder builder = new TopologyBuilder();  
  2. builder.setSpout("word-reader",new WordReader());  
  3. builder.setBolt("word-normalizer"new WordNormalizer())  
  4.     .shuffleGrouping("word-reader");  
  5. builder.setBolt("word-counter"new WordCounter(),1)  
  6.     .fieldsGrouping("word-normalizer"new Fields("word"));  
可以看出,这里有一个流程的执行关系。也可以说是一定订阅关系。第一个blot设置了shuffleGrouping的名称为Spout的名称,而第二个blot则指定了第一个blot的名称。就如我们上面的流程图执行流程一致。

2、Spout(WordReader)

[java]  view plain copy
  1. package spouts;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.FileNotFoundException;  
  5. import java.io.FileReader;  
  6. import java.util.Map;  
  7. import backtype.storm.spout.SpoutOutputCollector;  
  8. import backtype.storm.task.TopologyContext;  
  9. import backtype.storm.topology.OutputFieldsDeclarer;  
  10. import backtype.storm.topology.base.BaseRichSpout;  
  11. import backtype.storm.tuple.Fields;  
  12. import backtype.storm.tuple.Values;  
  13.   
  14. public class WordReader extends BaseRichSpout {  
  15.   
  16.     private SpoutOutputCollector collector;  
  17.     private FileReader fileReader;  
  18.     private boolean completed = false;  
  19.     public void ack(Object msgId) {  
  20.         System.out.println("OK:"+msgId);  
  21.     }  
  22.     public void close() {}  
  23.     public void fail(Object msgId) {  
  24.         System.out.println("FAIL:"+msgId);  
  25.     }  
  26.   
  27.     /** 
  28.      * The only thing that the methods will do It is emit each  
  29.      * file line 
  30.      */  
  31.     public void nextTuple() {  
  32.         /** 
  33.          * The nextuple it is called forever, so if we have been readed the file 
  34.          * we will wait and then return 
  35.          */  
  36.         if(completed){  
  37.             try {  
  38.                 Thread.sleep(1000);  
  39.             } catch (InterruptedException e) {  
  40.                 //Do nothing  
  41.             }  
  42.             return;  
  43.         }  
  44.         String str;  
  45.         //Open the reader  
  46.         BufferedReader reader = new BufferedReader(fileReader);  
  47.         try{  
  48.             //Read all lines  
  49.             while((str = reader.readLine()) != null){  
  50.                 /** 
  51.                  * By each line emmit a new value with the line as a their 
  52.                  */  
  53.                 this.collector.emit(new Values(str),str);  
  54.             }  
  55.         }catch(Exception e){  
  56.             throw new RuntimeException("Error reading tuple",e);  
  57.         }finally{  
  58.             completed = true;  
  59.         }  
  60.     }  
  61.   
  62.     /** 
  63.      * We will create the file and get the collector object 
  64.      */  
  65.     public void open(Map conf, TopologyContext context,  
  66.             SpoutOutputCollector collector) {  
  67.         try {  
  68.             this.fileReader = new FileReader(conf.get("wordsFile").toString());  
  69.         } catch (FileNotFoundException e) {  
  70.             throw new RuntimeException("Error reading file ["+conf.get("wordFile")+"]");  
  71.         }  
  72.         this.collector = collector;  
  73.     }  
  74.   
  75.     /** 
  76.      * Declare the output field "line" 
  77.      */  
  78.     public void declareOutputFields(OutputFieldsDeclarer declarer) {  
  79.         declarer.declare(new Fields("line"));  
  80.     }  
  81. }  
* declareOutputFields方法用于定义输出字段名

* 首先集群提交Topology之后,会先调用open方法,open内部使用config对象获取文件并获取fileReader对象。

* nextTuple()方法通过BufferReader读取到fileReader数据之后,读取每一行数据,然后通过emit方法发送数据到订阅了数据的blot上。
3、第一个Blot(拆分出所有的wordcount传入下一个blot)

[java]  view plain copy
  1. package bolts;  
  2.   
  3. import backtype.storm.topology.BasicOutputCollector;  
  4. import backtype.storm.topology.OutputFieldsDeclarer;  
  5. import backtype.storm.topology.base.BaseBasicBolt;  
  6. import backtype.storm.tuple.Fields;  
  7. import backtype.storm.tuple.Tuple;  
  8. import backtype.storm.tuple.Values;  
  9.   
  10. public class WordNormalizer extends BaseBasicBolt {  
  11.   
  12.     public void cleanup() {}  
  13.   
  14.     /** 
  15.      * The bolt will receive the line from the 
  16.      * words file and process it to Normalize this line 
  17.      *  
  18.      * The normalize will be put the words in lower case 
  19.      * and split the line to get all words in this  
  20.      */  
  21.     public void execute(Tuple input, BasicOutputCollector collector) {  
  22.         String sentence = input.getString(0);  
  23.         String[] words = sentence.split(" ");  
  24.         for(String word : words){  
  25.             word = word.trim();  
  26.             if(!word.isEmpty()){  
  27.                 word = word.toLowerCase();  
  28.                 collector.emit(new Values(word));  
  29.             }  
  30.         }  
  31.     }  
  32.       
  33.   
  34.     /** 
  35.      * The bolt will only emit the field "word"  
  36.      */  
  37.     public void declareOutputFields(OutputFieldsDeclarer declarer) {  
  38.         declarer.declare(new Fields("word"));  
  39.     }  
  40. }  
这个blot基本上没做什么事情,只是在execute方法中将words切分然后emit到下一个blot

4、第二个blot(执行单词统计)

[java]  view plain copy
  1. package bolts;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import backtype.storm.task.TopologyContext;  
  7. import backtype.storm.topology.BasicOutputCollector;  
  8. import backtype.storm.topology.OutputFieldsDeclarer;  
  9. import backtype.storm.topology.base.BaseBasicBolt;  
  10. import backtype.storm.tuple.Tuple;  
  11.   
  12. public class WordCounter extends BaseBasicBolt {  
  13.   
  14.     Integer id;  
  15.     String name;  
  16.     Map<String, Integer> counters;  
  17.   
  18.     /** 
  19.      * At the end of the spout (when the cluster is shutdown 
  20.      * We will show the word counters 
  21.      */  
  22.     @Override  
  23.     public void cleanup() {  
  24.         System.out.println("-- Word Counter ["+name+"-"+id+"] --");  
  25.         for(Map.Entry<String, Integer> entry : counters.entrySet()){  
  26.             System.out.println(entry.getKey()+": "+entry.getValue());  
  27.         }  
  28.     }  
  29.   
  30.     /** 
  31.      * On create  
  32.      */  
  33.     @Override  
  34.     public void prepare(Map stormConf, TopologyContext context) {  
  35.         this.counters = new HashMap<String, Integer>();  
  36.         this.name = context.getThisComponentId();  
  37.         this.id = context.getThisTaskId();  
  38.     }  
  39.   
  40.     @Override  
  41.     public void declareOutputFields(OutputFieldsDeclarer declarer) {}  
  42.   
  43.   
  44.     @Override  
  45.     public void execute(Tuple input, BasicOutputCollector collector) {  
  46.         String str = input.getString(0);  
  47.         /** 
  48.          * If the word dosn't exist in the map we will create 
  49.          * this, if not We will add 1  
  50.          */  
  51.         if(!counters.containsKey(str)){  
  52.             counters.put(str, 1);  
  53.         }else{  
  54.             Integer c = counters.get(str) + 1;  
  55.             counters.put(str, c);  
  56.         }  
  57.     }  
  58. }  
这里定义了一个HashMap counters用于存储单词的统计结果。在execute方法中执行单词统计。


转载请注明来源地址:http://blog.csdn.net/weijonathan/article/details/17399077

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值