(二十五)Storm本地編程案例

此編程在windows下的idea編譯器,運用maven項目

此時還沒有搭建Storm集羣,只是簡單地本地測試

pom文件

<dependency>
  <groupId>org.apache.storm</groupId>
  <artifactId>storm-core</artifactId>
  <version>1.2.2</version>
</dependency>

 

案例一

需求:1+2+3+….=???

實現方案:

  • Spout發送數字作爲input
  • 使用Bolt來處理業務邏輯:求和
  • 將結果輸出到控制檯

實現代碼

package com.bigdata;

import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
import org.apache.storm.utils.Utils;

import java.util.Map;

/**
 * 使用Storm實現積累求和的操作
 */
public class LocalSumStormTopology {


    /**
     * Spout需要繼承BaseRichSpout
     * 數據源需要產生數據併發射
     */
    public static class DataSourceSpout extends BaseRichSpout {

        private SpoutOutputCollector collector;
        /**
         * 初始化方法,只會被調用一次
         * @param conf  配置參數
         * @param context  上下文
         * @param collector 數據發射器
         */
        public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
            this.collector = collector;
        }

        int number = 0;

        /**
         * 會產生數據,在生產上肯定是從消息隊列中獲取數據
         *
         * 這個方法是一個死循環,會一直不停的執行
         */
        public void nextTuple() {
            this.collector.emit(new Values(++number));

            System.out.println("Spout: " + number);

            // 防止數據產生太快
            Utils.sleep(1000);

        }

        /**
         * 聲明輸出字段
         * @param declarer
         */
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("num"));
        }
    }


    /**
     * 數據的累積求和Bolt:接收數據並處理
     */
    public static class SumBolt extends BaseRichBolt {

        /**
         * 初始化方法,會被執行一次
         * @param stormConf
         * @param context
         * @param collector
         */
        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {

        }

        int sum = 0;

        /**
         * 其實也是一個死循環,職責:獲取Spout發送過來的數據
         * @param input
         */
        public void execute(Tuple input) {

            // Bolt中獲取值可以根據index獲取,也可以根據上一個環節中定義的field的名稱獲取(建議使用該方式)
            Integer value = input.getIntegerByField("num");
            sum += value;

            System.out.println("Bolt: sum = [" + sum + "]");
        }

        public void declareOutputFields(OutputFieldsDeclarer declarer) {

        }
    }

    public static void main(String[] args) {

        // TopologyBuilder根據Spout和Bolt來構建出Topology
        // Storm中任何一個作業都是通過Topology的方式進行提交的
        // Topology中需要指定Spout和Bolt的執行順序
        TopologyBuilder builder = new TopologyBuilder();
        builder.setSpout("DataSourceSpout", new DataSourceSpout());
        builder.setBolt("SumBolt", new SumBolt()).shuffleGrouping("DataSourceSpout");
        // 創建一個本地Storm集羣:本地模式運行,不需要搭建Storm集羣
        LocalCluster cluster = new LocalCluster();
        cluster.submitTopology("LocalSumStormTopology", new Config(),
                builder.createTopology());

    }

}

 

案例二

需求:

讀取指定目錄的數據,並實現單詞計數的功能

實現方案:

  • Spout來讀取指定目錄的數據,作爲後續Bolt處理的input
  • 使用一個Bolt把input的數據,按照逗號進行分割
  • 使用一個Bolt來進行最終的單詞次數統計操作

實現代碼:

增加一個工具在pom中增加依賴

 <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
 </dependency>

程序代碼:

package com.bigdata;

import org.apache.commons.io.FileUtils;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 使用Storm完成詞頻統計功能
 */
public class LocalWordCountStormTopology {

    public static class DataSourceSpout extends BaseRichSpout {
        private SpoutOutputCollector collector;

        public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
            this.collector = collector;
        }

        /**
         * 業務:
         * 1) 讀取指定目錄的文件夾下的數據:G://wc
         * 2) 把每一行數據發射出去
         */
        public void nextTuple() {

            // 獲取所有文件
            Collection<File> files = FileUtils.listFiles(new File("G://wc"),
                    new String[]{"txt"},true);

            for(File file : files) {
                try {
                    // 獲取文件中的所有內容
                    List<String> lines = FileUtils.readLines(file);

                    // 獲取文件中的每行的內容
                    for(String line : lines) {

                        // 發射出去
                        this.collector.emit(new Values(line));
                    }

                    // TODO... 數據處理完之後,改名,否則一直重複執行
                    FileUtils.moveFile(file, new File(file.getAbsolutePath() + System.currentTimeMillis()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("line"));
        }
    }


    /**
     * 對數據進行分割
     */
    public static class SplitBolt extends BaseRichBolt {

        private OutputCollector collector;

        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
            this.collector = collector;
        }

        /**
         * 業務邏輯:
         *   line: 對line進行分割,按照逗號
         */
        public void execute(Tuple input) {
            String line = input.getStringByField("line");
            String[] words = line.split(",");

            for(String word : words) {
                this.collector.emit(new Values(word));
            }

        }

        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("word"));
        }
    }


    /**
     * 詞頻彙總Bolt
     */
    public static class CountBolt extends  BaseRichBolt {

        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {

        }


        Map<String,Integer> map = new HashMap<String, Integer>();
        /**
         * 業務邏輯:
         * 1)獲取每個單詞
         * 2)對所有單詞進行彙總
         * 3)輸出
         */
        public void execute(Tuple input) {
            // 1)獲取每個單詞
            String word = input.getStringByField("word");
            Integer count = map.get(word);
            if(count == null) {
                count = 0;
            }

            count ++;

            // 2)對所有單詞進行彙總
            map.put(word, count);

            // 3)輸出
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~");
            Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
            for(Map.Entry<String,Integer> entry : entrySet) {
                System.out.println(entry);
            }

        }

        public void declareOutputFields(OutputFieldsDeclarer declarer) {

        }
    }

    public static void main(String[] args) {

        // 通過TopologyBuilder根據Spout和Bolt構建Topology
        TopologyBuilder builder = new TopologyBuilder();
        builder.setSpout("DataSourceSpout", new DataSourceSpout());
        builder.setBolt("SplitBolt", new SplitBolt()).shuffleGrouping("DataSourceSpout");
        builder.setBolt("CountBolt", new CountBolt()).shuffleGrouping("SplitBolt");

        // 創建本地集羣
        LocalCluster cluster = new LocalCluster();
        cluster.submitTopology("LocalWordCountStormTopology",
                new Config(), builder.createTopology());

    }

}

這個代碼需要在windows的G盤中創建一個wc目錄,裏面有要統計的文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章