package com.uplooking.bigdata.storm.group;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.GlobalStreamId;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.grouping.CustomStreamGrouping;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.task.WorkerTopologyContext;
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.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 使用自定义分组进行数据的接收制定
* 将偶数分配到一个executor中,将奇数分派到另一个线程中
*/
public class CustomerGroupingSumTopology {
/**
* 当前spout用于接收数据源的数据
*/
static class SumNumSpout extends BaseRichSpout {
private Map conf;
private TopologyContext context;
private SpoutOutputCollector collector;
/**
* 这是一个生命周期方法,一个SumNumSpout实例只运行一次,主要完成初始化的参数设置
* @param conf ---->storm程序以及storm集群相关的配置信息
* @param context ---->整个Topology上下文对象,可以通过该context获得相关topology应用属性
* @param collector ---->主要用于收集数据,并将数据发射到下一个阶段
*/
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.conf = conf;
this.context = context;
this.collector = collector;
}
/*
storm程序只要nextTuple方法,完成数据采集,处理,发射到下游bolt
*/
int num = 0;
public void nextTuple() {
// num++;//数据自增
// Values
System.out.println("spout产生的数据:" + num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
collector.emit(new Values(num++));//使用collector发射数据
}
//是对发射到下游bolt中的数据的一个说明
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("num"));
}
}
/**
* 对接收到spout中的数据的处理逻辑
*/
static class SumNumBolt extends BaseRichBolt {
private Map conf;
private TopologyContext context;
private OutputCollector collector;
public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
this.conf = conf;
this.context = context;
this.collector = collector;
}
int sum = 0;
//这里面对接收上游数据的一个处理
public void execute(Tuple tuple) {
int num = tuple.getIntegerByField("num");
System.out.println("thread id: " + Thread.currentThread().getId() + "-----:" + num);
sum += num;
System.out.println("sum----:" + sum);
}
//类似于spout中的declareOutputFields方法,如果还有下游bolt操作,那需要在这里面进行一个说明
//如果没有下面bolt操作,这个方法就可以不用进行任何操作
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}
public static void main(String[] args) throws Exception {
//主要就是用来组织spout和bolt成为一个Topology拓扑,提交到集群
//构建Topology是通过TopologyBuilder来进行设置
TopologyBuilder topologyBuilder = new TopologyBuilder();
//set spout
//spout_id-->
String spoutID = "sumNumSpout_id";
topologyBuilder.setSpout(spoutID, new SumNumSpout());
//设置bolt
//.shuffleGrouping(spoutID)--->设置数据来源
String boltID = "sumNumBolt_id";
topologyBuilder.setBolt(boltID, new SumNumBolt(), 2)//
.customGrouping(spoutID, new MyCustomGrouping());
//产生topology
StormTopology stormTopology = topologyBuilder.createTopology();
String topologyName = CustomerGroupingSumTopology.class.getSimpleName();
Config config = new Config();
if(args == null || args.length < 1) {//如果没有参数就在本地运行
//因为咱们本地运行,所以使用LocalCluster就可以
LocalCluster cluster = new LocalCluster();
cluster.submitTopology(topologyName, config, stormTopology);
} else {//集群运行
StormSubmitter.submitTopology(topologyName, config, stormTopology);
}
}
}
class MyCustomGrouping implements CustomStreamGrouping {
private WorkerTopologyContext context;
private GlobalStreamId stream;
private List<Integer> targetTasks;
/**
* 主要做分组前的准备工作
* @param context 是当前topology 在相应worker进程中的运行上下文
* @param stream 当前topology对应的stream数据ID
* @param targetTasks 当前worker中运行的task的列表
*/
public void prepare(WorkerTopologyContext context, GlobalStreamId stream, List<Integer> targetTasks) {
this.context = context;
this.stream = stream;
this.targetTasks = targetTasks;
System.out.println("custom grouping=========targetTasks: " + targetTasks);
}
/**
* 分组,就是选项相应的task去运行相应的数据
* @param taskId --->当前taskID
* @param values --->就是tuple
* @return 在哪一个task运行该数据
*/
public List<Integer> chooseTasks(int taskId, List<Object> values) {
System.out.println("custom grouping--------values: " + values);
Object obj = values.get(0);//取出当前tuple中数据
//奇数和偶数分别到不同的task中
int num = Integer.valueOf(obj.toString());
if(num % 2 == 0) {//偶数
//从task列表中取出一个task,这里从中取出第一个task
return Arrays.asList(targetTasks.get(0));
} else {//奇数
//从task列表中取出另外一个task,取出第二个task来运行
return Arrays.asList(targetTasks.get(1));
}
}
}
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.GlobalStreamId;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.grouping.CustomStreamGrouping;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.task.WorkerTopologyContext;
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.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 使用自定义分组进行数据的接收制定
* 将偶数分配到一个executor中,将奇数分派到另一个线程中
*/
public class CustomerGroupingSumTopology {
/**
* 当前spout用于接收数据源的数据
*/
static class SumNumSpout extends BaseRichSpout {
private Map conf;
private TopologyContext context;
private SpoutOutputCollector collector;
/**
* 这是一个生命周期方法,一个SumNumSpout实例只运行一次,主要完成初始化的参数设置
* @param conf ---->storm程序以及storm集群相关的配置信息
* @param context ---->整个Topology上下文对象,可以通过该context获得相关topology应用属性
* @param collector ---->主要用于收集数据,并将数据发射到下一个阶段
*/
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.conf = conf;
this.context = context;
this.collector = collector;
}
/*
storm程序只要nextTuple方法,完成数据采集,处理,发射到下游bolt
*/
int num = 0;
public void nextTuple() {
// num++;//数据自增
// Values
System.out.println("spout产生的数据:" + num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
collector.emit(new Values(num++));//使用collector发射数据
}
//是对发射到下游bolt中的数据的一个说明
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("num"));
}
}
/**
* 对接收到spout中的数据的处理逻辑
*/
static class SumNumBolt extends BaseRichBolt {
private Map conf;
private TopologyContext context;
private OutputCollector collector;
public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
this.conf = conf;
this.context = context;
this.collector = collector;
}
int sum = 0;
//这里面对接收上游数据的一个处理
public void execute(Tuple tuple) {
int num = tuple.getIntegerByField("num");
System.out.println("thread id: " + Thread.currentThread().getId() + "-----:" + num);
sum += num;
System.out.println("sum----:" + sum);
}
//类似于spout中的declareOutputFields方法,如果还有下游bolt操作,那需要在这里面进行一个说明
//如果没有下面bolt操作,这个方法就可以不用进行任何操作
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}
public static void main(String[] args) throws Exception {
//主要就是用来组织spout和bolt成为一个Topology拓扑,提交到集群
//构建Topology是通过TopologyBuilder来进行设置
TopologyBuilder topologyBuilder = new TopologyBuilder();
//set spout
//spout_id-->
String spoutID = "sumNumSpout_id";
topologyBuilder.setSpout(spoutID, new SumNumSpout());
//设置bolt
//.shuffleGrouping(spoutID)--->设置数据来源
String boltID = "sumNumBolt_id";
topologyBuilder.setBolt(boltID, new SumNumBolt(), 2)//
.customGrouping(spoutID, new MyCustomGrouping());
//产生topology
StormTopology stormTopology = topologyBuilder.createTopology();
String topologyName = CustomerGroupingSumTopology.class.getSimpleName();
Config config = new Config();
if(args == null || args.length < 1) {//如果没有参数就在本地运行
//因为咱们本地运行,所以使用LocalCluster就可以
LocalCluster cluster = new LocalCluster();
cluster.submitTopology(topologyName, config, stormTopology);
} else {//集群运行
StormSubmitter.submitTopology(topologyName, config, stormTopology);
}
}
}
class MyCustomGrouping implements CustomStreamGrouping {
private WorkerTopologyContext context;
private GlobalStreamId stream;
private List<Integer> targetTasks;
/**
* 主要做分组前的准备工作
* @param context 是当前topology 在相应worker进程中的运行上下文
* @param stream 当前topology对应的stream数据ID
* @param targetTasks 当前worker中运行的task的列表
*/
public void prepare(WorkerTopologyContext context, GlobalStreamId stream, List<Integer> targetTasks) {
this.context = context;
this.stream = stream;
this.targetTasks = targetTasks;
System.out.println("custom grouping=========targetTasks: " + targetTasks);
}
/**
* 分组,就是选项相应的task去运行相应的数据
* @param taskId --->当前taskID
* @param values --->就是tuple
* @return 在哪一个task运行该数据
*/
public List<Integer> chooseTasks(int taskId, List<Object> values) {
System.out.println("custom grouping--------values: " + values);
Object obj = values.get(0);//取出当前tuple中数据
//奇数和偶数分别到不同的task中
int num = Integer.valueOf(obj.toString());
if(num % 2 == 0) {//偶数
//从task列表中取出一个task,这里从中取出第一个task
return Arrays.asList(targetTasks.get(0));
} else {//奇数
//从task列表中取出另外一个task,取出第二个task来运行
return Arrays.asList(targetTasks.get(1));
}
}
}