Flink整合Drools规则引擎

业务功能:根据告警规则,从告警流中将主告警和次告警进行关联。

pom maven配置:

    6.5.0.Final
    1.10.0

       
            org.apache.flink
            flink-java
            ${flink.version}
            
        
        
            org.apache.flink
            flink-streaming-java_${scala.binary.version}
            ${flink.version}
            
        

       
            org.drools
            drools-core
            ${drools.version}
        
        
        
            org.drools
            drools-compiler
            ${drools.version}
        

        
            org.drools
            drools-decisiontables
            ${drools.version}
        
        
            org.drools
            drools-templates
            ${drools.version}
        

        
            org.kie
            kie-api
            ${drools.version}
        

1、普通的Java 的POJO(对应Drools中的fact 对象)

package www.lxk.com;


import java.io.Serializable;
import java.util.Date;

public class Alarm implements Serializable{
    private String alarmId;
    private Date eventTime;
    private String relatedType;

    public String getAlarmId() {
        return alarmId;
    }

    public void setAlarmId(String alarmId) {
        this.alarmId = alarmId;
    }

    public Date getEventTime() {
        return eventTime;
    }

    public void setEventTime(Date eventTime) {
        this.eventTime = eventTime;
    }

    public String getRelatedType() {
        return relatedType;
    }

    public void setRelatedType(String relatedType) {
        this.relatedType = relatedType;
    }

    @Override
    public String toString() {
        return "Alarm{" +
                "alarmId='" + alarmId + '\'' +
                ", eventTime=" + eventTime +
                ", relatedType='" + relatedType + '\'' +
                '}';
    }
}

2、规则文件rules2.drl

package rules

import com.asiainfo.aisware.oss.sink.Alarm
import java.util.ArrayList

global java.util.List list

declare Alarm
    @role(event)        //声明为事件
    @timestamp(eventTime)  //事件时间戳
    @expire(5S)      //事件过期时间10分钟,过期后不再匹配任何规则
 end

rule "rule2"
    no-loop true
    duration 3000
     when
           $pAlarm : Alarm( $qq: alarmId memberOf ["111"] ) from entry-point "Demo02"
           $sList:ArrayList(size >=10 ) from collect (
                             Alarm(alarmId memberOf ["222","333"] )
                             from entry-point "Demo02"
                         )
     then
           $pAlarm.setRelatedType("主告警");
           System.out.println("匹配到主告警" + $pAlarm.toString());
           System.out.println($qq);
           //drools.insert($pAlarm);
           $sList.forEach(x -> {
               ((Alarm)x).setRelatedType("子告警");
               System.out.println("匹配到子告警"  + x.toString());
           });
end

3、处理类--规则的编译、收集和执行

package www.lxk.com;

import com.asiainfo.aisware.oss.sink.Alarm;
import com.asiainfo.aisware.oss.sink.Rule;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.source.SourceFunction;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

public class Demo02 {
    public static void main(String[] args) throws Exception {
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // 非常关键,一定要设置启动检查点!!
        env.enableCheckpointing(5000);
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE); //精确一次

        env.setParallelism(1);
        //告警流
        DataStream dataStream = env.addSource(new MyAlarmSource());
       //规则流
        DataStream ruleStream = env.addSource(new MyRuleSource());
        
        //dataStream.print();
        //ruleStream.print();
        dataStream.connect(ruleStream).flatMap(new RuleAlarmFunction()).print();

        env.execute("Drools Demo01");
    }

    //自定义类,继承SourceFunction,每条数据是一个规则对象(根据业务自定义)
    public static class MyAlarmSource implements SourceFunction{
        // 定义一个标识,表示数据源是否继续运行
        private Boolean running = true;
        private static AtomicInteger counter = new AtomicInteger(0);


        @Override
        public void run(SourceContext sourceContext) throws Exception {
            String[] ids = {"111","222","333"};
            while (running){
                Alarm alarm = new Alarm();
                alarm.setAlarmId(ids[counter.getAndIncrement()%3]);
                alarm.setEventTime(new Date());
                Thread.sleep(500);
                sourceContext.collect(alarm);
            }
        }

        @Override
        public void cancel() {
            running = false;
        }
    }

    //自定义类,继承SourceFunction,每条数据是一个规则对象(根据业务自定义)
    public static class MyRuleSource implements SourceFunction{
        // 定义一个标识,表示数据源是否继续运行
        private boolean running = true;

        @Override
        public void run(SourceContext sourceContext) throws Exception {
            while (running){
                    //counter = 1;
                    Thread.sleep(500);
                    Rule rule = new Rule();
                    File file = new File("F:\\04_drools\\fm-rule\\src\\main\\resources\\rules\\rules2.drl");
                    FileReader reader = new FileReader(file);
                    BufferedReader br = new BufferedReader(reader);// 建立一个对象,它把文件内容转成计算机能读懂的语言

                    String line;
                    StringBuffer sb = new StringBuffer();
                    //网友推荐更加简洁的写法
                    while ((line = br.readLine()) != null) {
                        // 一次读入一行数据
                        sb.append(line).append("\n");
                    }
                    rule.setDrlStr(sb.toString());
                    rule.setOperate(1);
                    rule.setName("rule2");
                    sourceContext.collect(rule);
            }
        }

        @Override
        public void cancel() {
            this.running = false;
        }
    }

}
package www.lxk.com;

import com.asiainfo.aisware.oss.sink.Alarm;
import com.asiainfo.aisware.oss.sink.Rule;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.co.RichCoFlatMapFunction;
import org.apache.flink.util.Collector;
import org.drools.core.impl.KnowledgeBaseImpl;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.EntryPoint;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.utils.KieHelper;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RuleAlarmFunction extends RichCoFlatMapFunction {
    private  KieHelper kieHelper;
    private  KnowledgeBaseImpl kieBase;
    private  KieSession kieSession;
    private  EntryPoint entryPoint;
    private Lock lock = new ReentrantLock();

    @Override
    public void open(Configuration parameters) throws Exception {
        if(kieSession == null ){
            kieHelper = new KieHelper();
            //kieHelper.addContent(drlStr, ResourceType.DRL);
            KieBaseConfiguration config = KieServices.Factory.get().newKieBaseConfiguration();
            config.setOption( EventProcessingOption.STREAM );
            try{
                kieBase =(KnowledgeBaseImpl) kieHelper.build();
                kieSession = kieBase.newStatefulSession();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    @Override
    public void close() throws Exception {
        Thread.sleep(1000);
        kieSession.destroy();
    }


    @Override
    public void flatMap1(Alarm alarm, Collector collector) throws Exception {
        lock.lock();
        try{
            entryPoint = kieSession.getEntryPoint("Demo02");
            if(entryPoint != null){
                entryPoint.insert(alarm);
                int fireNum = kieSession.fireAllRules();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        collector.collect(alarm);
    }

    @Override
    public void flatMap2(Rule rule, Collector collector) throws Exception {
        if(rule.getOperate() == 0){
            lock.lock();
            try{
                kieBase.removeRule("rules", rule.getName());
                kieSession = kieBase.newKieSession();
            }finally {
                lock.unlock();
            }
        }else{
            // 规则名是ruleId
            org.kie.api.definition.rule.Rule ruleCache = kieBase.getRule("rules", rule.getName());

            // 规则如果已存在,不需要再次新增
            if(ruleCache !=null && rule.getName().equals(ruleCache.getName())){
                System.out.println("规则已经存在,ruleName="+ ruleCache.getName());
            }else {
                //重新添加规则
                KnowledgeBuilder kb = KnowledgeBuilderFactory.newKnowledgeBuilder();
                //装入规则,可以装入多个
                kb.add(ResourceFactory.newByteArrayResource(rule.getDrlStr().getBytes("utf-8")), ResourceType.DRL);
                kieBase.addKnowledgePackages(kb.getKnowledgePackages());
                kieSession = kieBase.newKieSession();
            }
        }
    }
}

 4、运行测试

"C:\Program Files\Java\jdk1.8.0_201\bin\java" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA...Alarm{alarmId='111', eventTime=Sun Jun 07 17:01:17 CST 2020, relatedType='null'}
规则已经存在,ruleName=rule2
Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:18 CST 2020, relatedType='null'}
规则已经存在,ruleName=rule2
匹配到主告警Alarm{alarmId='111', eventTime=Sun Jun 07 17:01:14 CST 2020, relatedType='主告警'}
111
匹配到子告警Alarm{alarmId='333', eventTime=Sun Jun 07 17:01:09 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:09 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:10 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='333', eventTime=Sun Jun 07 17:01:11 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:12 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='333', eventTime=Sun Jun 07 17:01:12 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:13 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='333', eventTime=Sun Jun 07 17:01:14 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:15 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='333', eventTime=Sun Jun 07 17:01:15 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:16 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='333', eventTime=Sun Jun 07 17:01:17 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='222', eventTime=Sun Jun 07 17:01:18 CST 2020, relatedType='子告警'}
匹配到子告警Alarm{alarmId='333', eventTime=Sun Jun 07 17:01:18 CST 2020, relatedType='子告警'}
匹配到主告警Alarm{alarmId='111', eventTime=Sun Jun 07 17:01:13 CST 2020, relatedType='主告警'}

Process finished with exit code 0

你可能感兴趣的:(Drools规则引擎,Flink基础,drools)