storm入门程序单词计数
1.创建maven,java工程导入依赖
<dependencies>
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
在本地运行时<scope>provided</scope>
注释掉,集群运行不注释,不然会冲突。
2.开发spout,随机选择一些单词发送到下一个bolt
package cn.itcast.storm.wordcount;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import java.util.Map;
import java.util.Random;
public class RandomSpout extends BaseRichSpout{
// spout 随机发送 hello world , hello kafka , storm hadoop , hive storm
// 单词切割bolt 按照空格进行切割 hello 1
// 单词计数bolt Map<String,Integer > map = new HashMap<String,Integer>();
private SpoutOutputCollector collector;
private String[] arrays;
private Random random;
/**
* 这个方法就是一个初始化的方法,只会被调用一次
* @param conf
* @param context
* @param collector
*/
@Override
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.collector = collector;
arrays = new String[]{"hello world","hello kafka","storm hadoop","hive storm"};
}
/**
* nextTuple 这个方法会反复被storm框架进行调用,所有的数据发送都封装到这个方法里面来
*/
@Override
public void nextTuple() {
try {
random = new Random();
//限制random取值范围
int index = random.nextInt(arrays.length);
//取出来一条数据
String sentence = arrays[index];
//通过collector来调用emit方法进行我们的数据发送
collector.emit(new Values(sentence));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* declareOutputFields 为我们发送的数据指定一个字段,方便我们下面取数据,下面的bolt就可以通过这个字段来进行获取数据
* @param declarer
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("sentence"));
}
}
3.开发SplitBolt 将英文句子切割成一个个的单词
package cn.itcast.storm.wordcount;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
/**
* 千万不要继承 BaseRicheBolt 有可能会出现内存的溢出
*/
public class SplitBolt extends BaseBasicBolt {
/**
* 这个execute方法也会被storm框架不断的调用,用于处理我们的数据
* tuple:里面包含一些信息,包括我们发送的数据也在tuple里面
* @param input
* @param collector
*/
@Override
public void execute(Tuple input, BasicOutputCollector collector) {
//获取我们发送的数据过来
String sentence = input.getStringByField("sentence");
String[] split = sentence.split(" "); //storm hadoop ==> storm 1 hadoop 1
if(split.length >0){
//循环获取我们的单词
for (String words : split) {
//注意我这里发了两个数据
collector.emit(new Values(words,1));
}
}
}
/**
* declareOutputFields 为我们发送的数据指定一个字段,方便我们下面取数据,下面的bolt就可以通过这个字段来进行获取数据
* @param declarer
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("words","num"));
}
}
4.开发计数器CountBolt
package cn.itcast.storm.wordcount;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Tuple;
import java.util.HashMap;
import java.util.Map;
public class CountBolt extends BaseBasicBolt {
private HashMap<String,Integer> hashMap;
/**
* 这个就是初始化的方法
* @param stormConf
* @param context
*/
@Override
public void prepare(Map stormConf, TopologyContext context) {
hashMap = new HashMap<String,Integer>();
super.prepare(stormConf, context);
}
/**
* 这个execute方法会被storm框架不断的调用
* @param input
* @param collector
*/
@Override
public void execute(Tuple input, BasicOutputCollector collector) {
//获取我们的单词
String words = input.getStringByField("words");
//获取我们单词的次数
Integer num = input.getIntegerByField("num");
//搞hashMap存起来,进行累加
//判断hashMap当中有没有这个单词作为key,如果有,直接取出来,加一次再存进去,如果没有直接存进去,次数为1
if(hashMap.containsKey(words)){
//存在,先取出来,然后再存进去
hashMap.put(words,hashMap.get(words)+num);
}else{
//不存在
hashMap.put(words,num);
}
System.out.println(hashMap);
}
/**
* 如果没有继续要处理的bolt,这个方法里面的内容就不要写了
*
* @param declarer
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
5.组装程序向storm集群进行提交
package cn.itcast.storm.wordcount;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.AlreadyAliveException;
import org.apache.storm.generated.AuthorizationException;
import org.apache.storm.generated.InvalidTopologyException;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.topology.TopologyBuilder;
public class WordCountTopology {
public static void main(String[] args) throws Exception {
TopologyBuilder builder = new TopologyBuilder();
//设置我们的数据源,也就是我们的spout
builder.setSpout("randomSpout",new RandomSpout(),3);
//通过executor来设置我们的线程的数量 wrods 1
builder.setBolt("splitBolt",new SplitBolt(),3).localOrShuffleGrouping("randomSpout");//通过shuffleGrouping来进行分组,表示我们通过什么分组策略来接收上一个组件的数据
//通过executor来设置我们的线程的数量
builder.setBolt("countBolt",new CountBolt(),3).localOrShuffleGrouping("splitBolt");
//设置Storm集群的一些配置
Config config =new Config();
/**
* storm提交有两种运行模式,一种集群提交,还有一种本地运行模式,就是模拟我们的集群模式运行,方便我们的调试
*/
//判断,如果这个程序跟的参数大于0,我们就认为是集群提交模式,否则就是本地运行模式
if(args.length > 0){
//通过workders来设置我们的进程的数量
config.setNumWorkers(2);
config.setDebug(false);
//通过StormSubmitter来进行提交我们的storm的程序
StormTopology topology = builder.createTopology();
StormSubmitter.submitTopology(args[0],config,topology);
}else{
//storm运行的是本地模式,方便我们的测试与调试
config.setDebug(true);
LocalCluster cluster = new LocalCluster();
//本地模式提交我们的storm代码
cluster.submitTopology("wordCount",config,builder.createTopology());
}
}
}
喜欢就点赞评论+关注吧
感谢阅读,希望能帮助到大家,谢谢大家的支持!