目录
- 规则下逻辑表达和条件的抽象
- 表达逻辑的编码和抽象
 
- 规则&规则集合
- 条件
- 操作符
- 规则
- 规则执行
- 表达式遍历进行操作符计算添加
- 具体条件的执行
 
- 规则执行完成后得到最后的结果
 
 
规则下逻辑表达和条件的抽象
对于任何一个规则,包括多个条件,都可以抽象成如下的json形式
1,2,3分别代表3个条件,这个规则如何执行,则是"1 & (2 | 3)"
{
    "logic": "1 & (2 | 3)",
    "conditions":[
        {
            "isNot":true,
            "itemId":1,
            "left":{
                "value":"1",
                "isVar":true
            },
            "operator":"<",
            "right":{
                "value":"3",
                "isVar":true
            }
        },
        {
            "isNot":false,
            "itemId":2,
            "left":{
                "value":"1",
                "isVar":true
            },
            "operator":"==",
            "right":{
                "value":"3",
                "isVar":true
            }
        },
        {
            "isNot":false,
            "itemId":3,
            "left":{
                "value":"number",
                "isVar":true
            },
            "operator":"startsWith",
            "right":{
                "value":"666",
                "isVar":true
            }
        }
    ]
}
而每个条件抽象成如下,包括对应ID,用来关联逻辑表达式。以及条件的三要素:左变量, 右变量, 操作符
{
   "isNot":false,
   "itemId":1,
     "left":{
         "value":"1",
         "isVar":true
     },
     "operator":"<",
     "right":{
         "value":"3",
         "isVar":true
     }
}
表达逻辑的编码和抽象
1 & (2 | 3)仍然类似后缀表达式, 2 | 3 执行的结果在和 1 进行 &。1 & (2 | 3)解析后如下:

直接利用操作符表达式:包含操作数据和操作符
public class OperatorExpr implements Expr {
	private List<Expr> operands;
	private String operator;
	/**
	 * !标志,not在表达式和操作符中都可能出现,用这个key来区分这两种情况,主要用于统计分析
	 *
	 * 其余取值无意义
	 */
	private String notToken;
	/**
	 * 表达式的标识,不是所有的Operator都有
	 */
	private int id = -1;
	public OperatorExpr(String operator, List<Expr> operands) {
		this(operator, operands, "");
    }
	public OperatorExpr(String operator, List<Expr> operands, String notToken) {
		this.operator = operator;
		this.operands = operands;
		this.notToken = notToken;
	}
	public List<Expr> getOperands() {
		return operands;
	}
	public void setOperands(List<Expr> operands) {
		this.operands = operands;
	}
	public String getOperator() {
		return operator;
	}
	public void setOperator(String operator) {
		this.operator = operator;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	@Override
	public void accept(ExprVisitor visitor) {
		visitor.visit(this);
	}
}
规则&规则集合
条件
public class Condition {
    /**
     * 序号。
     *
     * 一般从 1 开始。
     */
    private int itemId;
    /**
     * 操作符。
     *
     * 比如 : 大于,不等于 等
     */
    private String operator;
    /**
     *
     */
    private boolean isNot;
    /**
     * 左变量
     */
    private Operand left;
    /**
     * 右变量
     */
    private Operand right;
操作符

public abstract class AbstractBaseOperator extends AbstractIdentifiableOperator{
    /**
     * @param context 引擎执行上下文
     * @return 识别结果
     */
    @Override
    public EvalResult doEval(EngineExecutionContext context) {
        Variable op1 = operands.get(0);
        Variable op2 = operands.get(1);
        if (op1 == null || op2 == null) {
            throw new IllegalArgumentException("argument in  operator can't  be null.");
        }
        Object a, b = null;
        a = op1.eval(context);
        //op2.eval()是个耗时操作。如果op1是Unknown,op2.eval就没必要做了。
        if (a == EvalResult.Unknown) {
            return EvalResult.Unknown;
        }
        if (op2 != null) {
            b = op2.eval(context);
        }
        if (b == EvalResult.Unknown) {
            return EvalResult.Unknown;
        }
        return invokeOperator(a, b, context);
    }
    private EvalResult invokeOperator(Object a, Object b, EngineExecutionContext context) {
        try {
            // 第一遍求值时,忽略高耗时操作符
            return EvalResult.valueOf(apply(a, b, context));
        } catch (Throwable e) {
            throw e;
        } finally {
        }
    }
    /**
     * 操作符具体逻辑
     *
     * @param a       左操作实参
     * @param b       右操作实参
     * @param context 上下文
     * @return true/false
     */
    protected abstract Boolean apply(Object a, Object b, EngineExecutionContext context);
    @Override
    public void accept(EvaluableVisitor visitor) {
        visitor.visit(this);
    }
}
- 需要进行左右操作数取数求值的逻辑,eval方法
- 执行操作符运算,accept方法
之所以使用接口,主要是实现延迟运行或者说用时操作,即需要执行的时候才执行,可参考复习:https://doctording.blog.csdn.net/article/details/121593411
规则
public class Rule implements Serializable, Evaluable<RuleResult>{
    protected String id;
    protected String title;
    private RuleEntry ruleEntry;
    protected volatile Evaluable<EvalResult> expression;
    public Rule() {
    }
    public Rule(RuleEntry entry) {
        this.id = entry.getId();
        this.expression = parse(entry);
        this.ruleEntry = entry;
    }
    @Override
    public RuleResult eval(EngineExecutionContext context) {
        long startTime = System.nanoTime();
        RuleResult result = new RuleResult(EvalResult.False, this);
        try {
            EvalResult evalResult = getExpression().eval(context);
            result.setEvalResult(evalResult);
        } catch (Exception ab) {
            result = new RuleResult(ab);
        } finally {
            result.setCost(System.nanoTime() - startTime);
        }
        return result;
    }
    @Override
    public void accept(EvaluableVisitor visitor) {
        visitor.visit(this);
    }
    //
    public Evaluable<EvalResult> getExpression() {
        return expression;
    }
    // parse表达式并执行
    public Evaluable<EvalResult> parse(RuleEntry rawRule) {
        try {
            Expr expr = parseExpr(rawRule.getExpression());
            return toEvaluable(rawRule, expr);
        } catch (Exception e) {
            throw new IllegalArgumentException("parse rule error, ruleId: " + rawRule.getId(), e);
        }
    }
    public Expr parseExpr(Expression rawExpr) {
        if (rawExpr == null) {
            throw new IllegalArgumentException("absence of raw expression");
        }
        return parseExpr(rawExpr.getLogic(), rawExpr.getConditions());
    }
    public Expr parseExpr(String logic, List<Condition> conditions) {
        ExprParser parser = new ExprParser(logic, conditions);
        return parser.expr();
    }
    public static Evaluable<EvalResult> toEvaluable(RuleEntry rawRule, Expr expr) {
        if (expr == null) {
            return null;
        }
        String ruleId = rawRule.getId();
        EvalExprVisitor visitor = new EvalExprVisitor();
        expr.accept(visitor);
        return visitor.getEvalExpr();
    }
}
- 规则属性包含条件表达式及其运算逻辑
- 规则初始化就把条件表达式初始化好了,并做校验
- 规则的执行则是执行表达式的过程
规则执行
public class RuleTest {
    public static void main(String[] args) {
        String logic = "1 &(2|3)";
        List<Condition > conditions = new ArrayList<>();
        Condition condition1 = new Condition();
        condition1.setItemId(1);
        Operand operandLeft = new Operand();
        operandLeft.setIsVar(true);
        operandLeft.setValue("age");
        operandLeft.setModifier("age");
        condition1.setLeft(operandLeft);
        condition1.setOperator(Operator.GT);
        Operand operandRight = new Operand();
        operandRight.setIsVar(false);
        operandRight.setValue("18");
        operandRight.setType("int");
        condition1.setRight(operandRight);
        conditions.add(condition1);
        Condition condition2 = new Condition();
        condition2.setItemId(2);
        Operand operandLeft2 = new Operand();
        operandLeft2.setIsVar(false);
        operandLeft2.setValue("2");
        condition2.setLeft(operandLeft2);
        condition2.setOperator(Operator.LT);
        Operand operandRight2 = new Operand();
        operandRight2.setIsVar(false);
        operandRight2.setValue("1");
        condition2.setRight(operandRight2);
        conditions.add(condition2);
        Condition condition3 = new Condition();
        condition3.setItemId(3);
        Operand operandLeft3 = new Operand();
        operandLeft3.setIsVar(true);
        operandLeft3.setValue("number");
        operandLeft3.setModifier("number");
        condition3.setLeft(operandLeft3);
        condition3.setOperator(Operator.CONTAINS_STRING);
        Operand operandRight3 = new Operand();
        operandRight3.setIsVar(false);
        operandRight3.setValue("666");
        condition3.setRight(operandRight3);
        conditions.add(condition3);
        Expression expression = new Expression(logic, conditions);
        RuleEntry ruleEntry = new RuleEntry();
        ruleEntry.setId("1");
        ruleEntry.setExpression(expression);
        Rule rule = new Rule(ruleEntry);
        EngineExecutionContext engineExecutionContext = new EngineExecutionContext();
        Map<String, Object> ctx = new HashMap<>();
        ctx.put("age", 19);
        ctx.put("number", "666abc");
        engineExecutionContext.setData(ctx);
        RuleResult ruleResult = rule.eval(engineExecutionContext);
        System.out.println(ruleResult);
    }
}
表达式遍历进行操作符计算添加
public class EvalExprVisitor implements ExprVisitor {
	private Operator<?, EvalResult> expr = null;
	private Operator<Evaluable<?>, ?> currentParent = null;
	@Override
	public boolean visit(IdentifierExpr x) {
		if (null != currentParent && null != x) {
			currentParent.addOperand(new Identifier(x.getConditionId(),x.getName()));
		}
		return false;
	}
	@Override
	public boolean visit(LiteralExpr x) {
		if (null != currentParent && null != x) {
			currentParent.addOperand(new Literal(x.getValue()));
		}
		return false;
	}
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public boolean visit(OperatorExpr x) {
		String operator = x.getOperator();
		// 	获取操作符实际例子
		Operator opexpr = OperatorLoader.getOperator(operator);
		if (expr == null) {
			expr = opexpr;
		}else {
			currentParent.addOperand(opexpr);
		}
		Operator<Evaluable<?>, ?> oldParent = currentParent;
		currentParent = opexpr;
		List<Expr> operands = x.getOperands();
		if (operands != null && !operands.isEmpty()) {
			for (Expr expr : operands) {
				expr.accept(this);
			}
		}
		currentParent = oldParent;
		return false;
	}
	public Evaluable<EvalResult> getEvalExpr() {
		return expr;
	}
}
不同的表达式类型
public interface ExprVisitor {
    /**
     * 访问变量表达式
     *
     * @param identifierExpr
     * @return
     */
    boolean visit(IdentifierExpr identifierExpr);
    /**
     * 访问常量表达式
     *
     * @param literalExpr
     * @return
     */
    boolean visit(LiteralExpr literalExpr);
    /**
     * 访问操作符表达式
     *
     * @param operatorExpr
     * @return
     */
    boolean visit(OperatorExpr operatorExpr);
}
- 表达式可以通过在程序启动前就缓存起来
- 可以开放SPI,支持用户自定义的表达式
具体条件的执行
规则下某个条件的执行,实际上是某个操作符的执行
- 第一步: 获取左右操作数, 需要根据context动态执行获取最终的值
- 第二步:执行操作符的具体判断比较
- 第三步:得到结果,或者作为其它操作符的执行的操作数
public abstract class AbstractBaseOperator extends AbstractIdentifiableOperator{
    /**
     * @param context 引擎执行上下文
     * @return 识别结果
     */
    @Override
    public EvalResult doEval(EngineExecutionContext context) {
        Variable op1 = operands.get(0);
        Variable op2 = operands.get(1);
        if (op1 == null || op2 == null) {
            throw new IllegalArgumentException("argument in  operator can't  be null.");
        }
        Object a, b = null;
        a = op1.eval(context);
        //op2.eval()是个耗时操作。如果op1是Unknown,op2.eval就没必要做了。
        if (a == EvalResult.Unknown) {
            return EvalResult.Unknown;
        }
        if (op2 != null) {
            b = op2.eval(context);
        }
        if (b == EvalResult.Unknown) {
            return EvalResult.Unknown;
        }
        return invokeOperator(a, b, context);
    }
    private EvalResult invokeOperator(Object a, Object b, EngineExecutionContext context) {
        try {
            // 第一遍求值时,忽略高耗时操作符
            return EvalResult.valueOf(apply(a, b, context));
        } catch (Throwable e) {
            throw e;
        } finally {
        }
    }
    /**
     * 操作符具体逻辑
     *
     * @param a       左操作实参
     * @param b       右操作实参
     * @param context 上下文
     * @return true/false
     */
    protected abstract Boolean apply(Object a, Object b, EngineExecutionContext context);
    @Override
    public void accept(EvaluableVisitor visitor) {
        visitor.visit(this);
    }
规则执行完成后得到最后的结果

在规则执行过程中可以记录每个条件的执行情况:耗时,异常,取数问题等等。而在返回的结果中,也可以记录,以方便后续的问题排查。



















