flink+drools动态规则示例之温度跳变告警

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(",");
            /*
             * 1,10000,30.0
             * 1,10000,45.0
             * 1,10001,66.0
             * 1,10001,69.0
             */
            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";
                /*
                 *根据前端的动作参数(其动作代表了意图)
                 * 构建ruleContent
                 * 一个独立的任务处理
                 * params in redis->generate ruleContent->sink mysql->flink-mysql-source->broadcast stream
                 */
                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 {
        // 属性:id,时间戳,温度值
        private String id;
        private Long timestamp;
        private Double temperature;

    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值