我们知道drools提供了12种关系操作符
但是有些时候这12种操作符依然不能满足我们的业务需求,我们可以扩展自己的操作符,下面是为某一航空公司做项目时扩展了操作符,在这分享下
首先,我们要实现的逻辑是对航班记录 frFfpTravelDetail的票价级别etFareBasis属性做比配(逻辑:票价级别 去除非英文和数字字符后,第二位开始包含“ID**”或“DG**”或“AD**”(**为数字)),这个逻辑太复杂,用以上12种关系操作符都不能满足,为此要进行扩展。
第一步:新增CsairEvaluatorDefinition类
package com.csair.cbd.rules.drools.services.impl; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import org.drools.base.ValueType; import org.drools.base.evaluators.EvaluatorDefinition; import org.drools.base.evaluators.Operator; import org.drools.spi.Evaluator; public class CsairEvaluatorDefinition implements EvaluatorDefinition { public static final Operator STR_COMPARE = Operator.addOperatorToRegistry( "csair", false); public static final Operator NOT_STR_COMPARE = Operator .addOperatorToRegistry("csair", true); private static final String[] SUPPORTED_IDS = { STR_COMPARE .getOperatorString() }; public enum Operations { FbInculde } private Evaluator[] evaluator; public Evaluator getEvaluator(ValueType type, Operator operator) { return this.getEvaluator(type, operator.getOperatorString(), operator .isNegated(), null); } public Evaluator getEvaluator(ValueType type, Operator operator, String parameterText) { return this.getEvaluator(type, operator.getOperatorString(), operator .isNegated(), parameterText); } public Evaluator getEvaluator(ValueType type, String operatorId, boolean isNegated, String parameterText) { return getEvaluator(type, operatorId, isNegated, parameterText, Target.FACT, Target.FACT); } public Evaluator getEvaluator(ValueType type, String operatorId, boolean isNegated, String parameterText, Target leftTarget, Target rightTarget) { CsairEvaluator evaluator = new CsairEvaluator(type, isNegated); evaluator.setParameterText(parameterText); return evaluator; } public String[] getEvaluatorIds() { return SUPPORTED_IDS; } public Target getTarget() { return Target.FACT; } public boolean isNegatable() { return true; } public boolean supportsType(ValueType arg0) { return true; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { evaluator = (Evaluator[]) in.readObject(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(evaluator); } }
第二步骤,新增CsairEvaluator类
package com.csair.cbd.rules.drools.services.impl; import org.drools.base.BaseEvaluator; import org.drools.base.ValueType; import org.drools.common.InternalWorkingMemory; import org.drools.rule.VariableRestriction.VariableContextEntry; import org.drools.spi.FieldValue; import org.drools.spi.InternalReadAccessor; import com.csair.cbd.rules.drools.services.impl.CsairEvaluatorDefinition.Operations; public class CsairEvaluator extends BaseEvaluator { private Operations parameter; public void setParameterText(String parameterText) { this.parameter = Operations.valueOf(parameterText); } public Operations getParameter() { return parameter; } public CsairEvaluator(final ValueType type, final boolean isNegated) { super(type, isNegated ? CsairEvaluatorDefinition.NOT_STR_COMPARE: CsairEvaluatorDefinition.STR_COMPARE); } public boolean evaluate(InternalWorkingMemory workingMemory, InternalReadAccessor extractor, Object object, FieldValue value) { final Object objectValue = extractor.getValue(workingMemory, object); switch (parameter) { case FbInculde: String sObjectValue = String.valueOf(objectValue); String sObjectValueTrim = sObjectValue.replaceAll("[^a-zA-Z0-9]",""); String sFieldvalue = String.valueOf(value.getValue()); boolean ret =sObjectValueTrim.substring(1).matches("^.*["+sFieldvalue+"][0-9]+.*$"); return ret; default: throw new IllegalAccessError("Illegal str comparison parameter"); } } public boolean evaluate(InternalWorkingMemory arg0, InternalReadAccessor arg1, Object arg2, InternalReadAccessor arg3, Object arg4) { return false; } public boolean evaluateCachedLeft(InternalWorkingMemory arg0, VariableContextEntry arg1, Object arg2) { return false; } public boolean evaluateCachedRight(InternalWorkingMemory arg0, VariableContextEntry arg1, Object arg2) { return false; } }
第三步骤,配置使drools规则引擎能够识别你定制的逻辑操作符
System.setProperty("drools.dateformat", "yyyy-MM-dd"); System.setProperty("drools.dialect.java.compiler", "JANINO"); //修改默认Java Dialect编译器 Properties props = new Properties(); //set default java compiler //TODO use a file property to allow configuration props.setProperty("drools.dialect.java.compiler", "JANINO"); PackageBuilderConfiguration pkgBuilderCfg = new PackageBuilderConfiguration(props); //扩展csair条件比配操作符,caozhipingpkgBuilderCfg.setOption(EvaluatorOption.get("csair",new CsairEvaluatorDefinition())); // 声明新的KnowledgeBuilder对象 KnowledgeBuilder kbuilder = KnowledgeBuilderFactory .newKnowledgeBuilder(pkgBuilderCfg);
经过以上三步后,你就可以正常使用你自己的关系操作符csair[FBInculde]了,这里贴上项目中的规则
rule "MingZhuKa-KeDuiHuanLiCheng-500000000001751-p20130727013" salience 1 no-loop false activation-group "1" ruleflow-group "1" when mileages : ArrayList() mileageRuleMiddleValue : MileageRuleMiddleValue() and frFfpTravelDetail : FrFfpTravelDetail(cumulateCabin == "E") and FrFfpTravelDetail(this == frFfpTravelDetail && etFareBasis csair[FbInculde] "(ID)|(DG)|(AD)" ) then Date[] dates = ruleGlobalUtil.getMileageRuleCalculate().getValidBeginEndDatesFromTheDate(55,mileageRuleMiddleValue.getBeginValidDate()); Mileage mileage = new Mileage("000001", "000001", mileageRuleMiddleValue.getBaseMileage()*44*0.01, mileageRuleMiddleValue.getRemark(),"ruleId", dates[0], dates[1], "travel-basic-award-1"); mileages.add(mileage); end
参考资料