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.youkuaiyun.com/weijonathan/article/details/17399077

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值