刚刚架设好一台Storm单实例服务器https://blog.csdn.net/xxkalychen/article/details/117014994,需要写个Java程序来测试一下。
使用Idea创建一个Java项目。
一、pom依赖
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>2.2.0</version>
</dependency>
就这一个依赖,注意版本,版本一定要和服务器使用的版本一致。
二、创建数据源处理类DataSourceSpout,主要任务是模拟本地数据,并且源源不断地提供给流水线
package com.chris.storm;
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 org.apache.storm.utils.Utils;
import java.util.Map;
/**
* @author Chris Chan
* Create on 2021/5/19 9:43
* Use for:
* Explain:
*/
public class DataSourceSpout extends BaseRichSpout {
//数据收集器
private SpoutOutputCollector collector;
//模拟数据
private static final String[] mockData = {
"I am a chinese",
"I love my homeland",
"My name is chris"
};
//当前数据指针
private int index = 0;
/**
* 初始化操作
*
* @param map
* @param topologyContext
* @param spoutOutputCollector
*/
@Override
public void open(Map<String, Object> map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
this.collector = spoutOutputCollector;
}
/**
* 处理数据
*/
@Override
public void nextTuple() {
//将模拟数据逐行读取出来,打包成元组数据,交给流水线的下一个bolt处理
this.collector.emit(new Values(mockData[this.index++].trim()));
//循环反复
if (this.index >= mockData.length) {
this.index = 0;
}
//休眠一小会,便于查看日志
Utils.sleep(500);
}
/**
* 定义输出流和字段
*
* @param outputFieldsDeclarer
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
//把数据存储在元组中名为line的字段里面
outputFieldsDeclarer.declare(new Fields("line"));
}
}
三、创建第一个处理环节LineBolt,主要任务是把一行文字按照分隔符拆分为单词
package com.chris.storm;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
import java.util.Arrays;
import java.util.Map;
/**
* @author Chris Chan
* Create on 2021/5/19 9:44
* Use for:
* Explain:
*/
public class LineBolt extends BaseRichBolt {
//bolt数据收集器
private OutputCollector collector;
/**
* 初始化操作
*
* @param map
* @param topologyContext
* @param outputCollector
*/
@Override
public void prepare(Map<String, Object> map, TopologyContext topologyContext, OutputCollector outputCollector) {
this.collector = outputCollector;
}
/**
* 处理数据
*
* @param tuple
*/
@Override
public void execute(Tuple tuple) {
//再上一个流水线spout中我们把一行行数据放在元组中的line字段,在这里我们把它读取出来
String line = tuple.getStringByField("line");
//根据数据特性,用空格进行分割
String[] words = line.split(" ");
//过滤掉空数据,然后发送给下一个bolt进行处理
Arrays.stream(words).filter(word -> !"".equals(word.trim())).forEach(word -> this.collector.emit(new Values(word)));
}
/**
* 定义输出数据元组字段
*
* @param outputFieldsDeclarer
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
//我们把拆分后的单词放到元组中名为word的字段中
outputFieldsDeclarer.declare(new Fields("word"));
}
}
四、创建一个最终处理环节PrintBolt,主要任务是把处理好的单词输出到控制台
package com.chris.storm;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Tuple;
import java.util.Map;
/**
* @author Chris Chan
* Create on 2021/5/19 9:44
* Use for:
* Explain:
*/
public class PrintBolt extends BaseRichBolt {
@Override
public void prepare(Map<String, Object> map, TopologyContext topologyContext, OutputCollector outputCollector) {
}
@Override
public void execute(Tuple tuple) {
//打印输出
String word = tuple.getStringByField("word");
System.out.printf("%s: %s\n", "接收到单词", word);
}
/**
* 这是流水线上的终点,不需要在发给下一环,所以无须再定义元组字段
*
* @param outputFieldsDeclarer
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
}
}
五、创建主程序MyTopology,构建并执行任务
package com.chris.storm;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.topology.TopologyBuilder;
/**
* @author Chris Chan
* Create on 2021/5/19 9:42
* Use for:
* Explain:
*/
public class MyTopology {
public static void main(String[] args) throws Exception {
new MyTopology().execute(args);
}
private void execute(String[] args) throws Exception {
//拓扑构造器
TopologyBuilder builder = new TopologyBuilder();
//设置流水线数据源spout
builder.setSpout("data", new DataSourceSpout(), 1);
//设置流水线的各个处理环节bolt shuffleGrouping对应上一环节的id
builder.setBolt("line", new LineBolt(), 2).shuffleGrouping("data");
builder.setBolt("print", new PrintBolt(), 2).shuffleGrouping("line");
//配置
Config config = new Config();
config.setDebug(false);
//本地提交
LocalCluster cluster = new LocalCluster.Builder().build();
cluster.submitTopology("test_topo", config, builder.createTopology());
}
}
六、运行MyTopology的main方法
按照预期输出了分割好的单词。
不过这个小程序是不能提交到远程服务器上去的。远程提交和本地提交区别很大,而且服务器上UI查看日志也有点问题,在没有解决日志查看问题之前,使用控制台打印输出来测试不容易看到效果。我们还需要将程序进行一些修改,才可以提交到远程服务器去执行。