flink+drools动态规则示例之温度跳变告警
package com.mz.test;
import com.google.common.collect.Lists;
import lombok.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.apache.flink.api.common.state.BroadcastState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.*;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.KeyedBroadcastProcessFunction;
import org.apache.flink.util.Collector;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.utils.KieHelper;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Consumer;
public class TemperatureAlarm {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
DataStream<String> dataStream = env.socketTextStream("mz-hadoop-03", 7777);
DataStream<String> ruleStream = env.socketTextStream("mz-hadoop-03", 7778);
DataStream<SensorReading> dataStream1 = dataStream.map(line -> {
String[] fields = line.split(",");
return new SensorReading(fields[0], new Long(fields[1]), new Double(fields[2]));
});
KeyedStream<SensorReading, String> keyedStream = dataStream1.keyBy(new KeySelector<SensorReading, String>() {
@Override
public String getKey(SensorReading value) throws Exception {
return value.getId();
}
});
MapStateDescriptor<String, KieSession> stateDescriptor = new MapStateDescriptor<>("ruleState", String.class, KieSession.class);
BroadcastStream<String> broadcastStream = ruleStream.broadcast(stateDescriptor);
BroadcastConnectedStream<SensorReading, String> connectedStream = keyedStream.connect(broadcastStream);
SingleOutputStreamOperator<AlarmCondition> resultStream = connectedStream.process(new KeyedBroadcastProcessFunction<String, SensorReading, String, AlarmCondition>() {
private ValueState<Double> lastTempState;
BroadcastState<String, KieSession> broadcastState;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
lastTempState = getRuntimeContext().getState(new ValueStateDescriptor<Double>("last-temp", Double.class));
}
@Override
public void processElement(SensorReading value, ReadOnlyContext ctx, Collector<AlarmCondition> out) throws Exception {
Iterator<Map.Entry<String, KieSession>> rulesIterator = broadcastState.iterator();
ArrayList<Map.Entry<String, KieSession>> rules = Lists.newArrayList(rulesIterator);
if (lastTempState.value() == null) {
lastTempState.update(value.getTemperature());
}
Double lastTemp = lastTempState.value();
lastTempState.update(value.getTemperature());
rules.forEach(new Consumer<Map.Entry<String, KieSession>>() {
@Override
public void accept(Map.Entry<String, KieSession> entry) {
KieSession kieSession = entry.getValue();
AlarmCondition alarmCondition = new AlarmCondition();
alarmCondition.setDeviceId(value.getId());
alarmCondition.setCurTemp(value.getTemperature());
alarmCondition.setLastTemp(lastTemp);
kieSession.insert(alarmCondition);
kieSession.fireAllRules();
if (alarmCondition.isFire()) {
out.collect(alarmCondition);
}
}
});
}
@Override
public void processBroadcastElement(String value, Context ctx, Collector<AlarmCondition> out) throws Exception {
broadcastState = ctx.getBroadcastState(stateDescriptor);
String ruleName = "rule1";
String intent = "package com.a.b.c\n" +
"import com.mz.test.TemperatureAlarm.AlarmCondition\n" +
"rule \"temprature alarm\"\n" +
"when \n" +
" a: AlarmCondition()\n" +
"then\n" +
" double diff = Math.abs(a.getCurTemp() - a.getLastTemp());\n" +
" a.setFire(diff >= " + value + ");\n" +
"end\n";
System.out.println("收到一条新的规则,并插入了state:" + intent);
broadcastState.put(ruleName, new KieHelper().addContent(intent, ResourceType.DRL).build().newKieSession());
}
});
resultStream.print("resultStream====>");
env.execute();
}
@Getter
@Setter
@ToString
@NoArgsConstructor
public static class AlarmCondition {
private String deviceId;
private double curTemp;
private double lastTemp;
private boolean fire;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public static class SensorReading {
private String id;
private Long timestamp;
private Double temperature;
}
}