基于规则引擎实现的疾病评估得分卡

基于规则引擎实现的疾病评估得分卡,第1张

基于规则引擎实现的疾病评估得分

评估配置功能

 

评估计算功能

基础功能:

  • 实现自定义表单展示,包含项目的展示和得分规则计算
  • 实现所有项目结果的评估结果组合计算和展示

数据库定义

 

 

 

实现原理

类似问卷调查配置表单,数据库有一个脚本保存匹配规则,类似   itemValue.include('option1633763947226'),每一项项目的得分是通过规则引擎匹配规则脚本,  匹配成功则返回该得分,计算评估结果也是和项目选项同一个原理

核心代码

规则引擎

@Slf4j
public class RuleEngineManager {

    private scriptEngine engine;

    private Bindings bindings = new SimpleBindings();

    private String extendscript = "";

    private String rulescript;

    public static RuleEngineManager instance() {
        RuleEngineManager instance = new RuleEngineManager();
        scriptEngineManager manager = new scriptEngineManager();
        instance.engine = manager.getEngineByName("Javascript");
        instance.extendscript();
        return instance;
    }


    public RuleEngineManager addParam(String key, Object value) {
        bindings.put(key, value);
        return this;
    }

    public RuleEngineManager addParam(Map map) {
        bindings.putAll(map);
        return this;
    }

    public RuleEngineManager setRulescript(String rulescript) {
        this.rulescript = rulescript;
        return this;
    }

    @SuppressWarnings("unchecked")
    public  T eval() {
        try {
            String evalscript = extendscript + ";" + rulescript;
            log.debug("RuleEngineManager eval script={}, bindings={}", rulescript, JsonUtil.objectToString(bindings));
            return (T) engine.eval(evalscript, bindings);
        } catch (scriptException e) {
            log.error("", e);
            return null;
        }
    }

    public BigDecimal eval2() {
        return new BigDecimal(eval().toString());
    }

    public boolean match() {
        try {
            String evalscript = extendscript + ";" + rulescript;
            log.debug("RuleEngineManager eval script={}, bindings={}", rulescript, JsonUtil.objectToString(bindings));
            return (Boolean) engine.eval(evalscript, bindings);
        } catch (scriptException e) {
            log.error("", e);
            return false;
        }
    }

    private RuleEngineManager extendscript() {
        this.extendscript = scriptConstant.INCLUDE + ";" + scriptConstant.EXCLUDE;
        log.debug("RuleEngineManager extend script = {}", this.extendscript);
        return this;
    }

    public static void main(String[] args) throws scriptException {

        String s = "0.0391*a+0.7917*b+1.3388*c ";
        Object result1 = RuleEngineManager.instance()
                .addParam("a", new BigDecimal(1))
                .addParam("b", new BigDecimal(2))
                .addParam("c", new BigDecimal(3))
                .setRulescript(s)
                .eval();
        System.out.println(new BigDecimal(result1.toString()));
        Object result2 = RuleEngineManager.instance()
                .addParam("a", 1)
                .setRulescript("function contain(a){ return a.indexOf('a')} contain('aaa')")
                .eval();
        System.out.println(result2);

        Object result3 = RuleEngineManager.instance()
                .addParam("a", "0")
                .addParam("b", "a")
                .setRulescript("a === '0'")
                .eval();
        System.out.println(result3);
    }
}

js扩展

public class scriptConstant {

    public static String INCLUDE =
            "String.prototype.include = function(s) {"
                    + " return this.indexOf(s) >= 0"
                    + "}";

    public static String EXCLUDE =
            "String.prototype.exclude = function(s) {"
                    + " return this.indexOf(s) < 0"
                    + "}";
}

计算引擎 

@Slf4j
@Service
public class AssessRuleEngine {

    public AssessModelResult eval(AssessModelVO modelVO, Map param) {

        // 构建项目编码->项目得分 map
        Map resultItemMap = new HashMap<>();
        // 循环计算每个项目的得分
        modelVO.getItemList().forEach(item -> {

            String itemCode = item.getItemCode();
            Object itemValue = param.get(itemCode);
            AssertUtil.notNull(itemValue, MessageEnum.ASSESS_PARAM_ERROR);

            ScoreTypeEnum scoreType = ScoreTypeEnum.getByCode(item.getScoreType());
            AssertUtil.notNull(scoreType, MessageEnum.ASSESS_CONFIG_ERROR);

            // 项目得分
            BigDecimal itemScore = BigDecimal.ZERO;
            // 直接得分
            if (scoreType == ScoreTypeEnum.RETURN_SCORE) {
                // 多选积分求和, 单选单个得分
                for (AssessModelOption option : item.getOptionList()) {
                    if (itemValue.toString().contains(option.getOptionCode())) {
                        itemScore = itemScore.add(option.getScore());
                    }
                }
                log.info("计算项目得分 itemName={}, 直接得分={}", item.getItemName(), itemScore);
            }
            // 匹配规则 或 表达式
            else {

                RuleEngineManager engineInstance = RuleEngineManager.instance()
                        .addParam(DefaultVariableEnum.ITEM_VALUE.getCode(), itemValue);

                for (AssessModelRule rule : item.getRuleList()) {
                    String script = rule.getScoreExp();
                    boolean match = engineInstance.setRulescript(script).match();
                    if (match) {
                        itemScore = rule.getScore();
                        break;
                    }
                }
                log.info("计算项目得分 itemName={}, 匹配规则={}", item.getItemName(), itemScore);
            }

            AssertUtil.notNull(itemScore, MessageEnum.ASSESS_CONFIG_ERROR);
            resultItemMap.put(itemCode, itemScore);
        });

        
        ResultTypeEnum resultType = ResultTypeEnum.getByCode(modelVO.getResultType());
        AssertUtil.notNull(resultType, MessageEnum.ASSESS_CONFIG_ERROR);
        // 得分求和
        if (Objects.equals(resultType, ResultTypeEnum.SUM)) {

            BigDecimal totalScore = resultItemMap.keySet().stream()
                    .map(key -> (BigDecimal) resultItemMap.get(key))
                    .reduce(BigDecimal::add).get();
            resultItemMap.put(DefaultVariableEnum.TOTAL_SCORE.getCode(), totalScore);
            log.info("计算项目总得分 totalScore={}", totalScore);
        }
        // 得分表达式
        else if (Objects.equals(resultType, ResultTypeEnum.EXP_TEXT)) {

            AssertUtil.notNull(modelVO.getResultExp(), MessageEnum.ASSESS_CONFIG_ERROR);
            BigDecimal totalScore = RuleEngineManager.instance()
                    .addParam(resultItemMap)
                    .setRulescript(modelVO.getResultExp())
                    .eval2();
            resultItemMap.put(DefaultVariableEnum.TOTAL_SCORE.getCode(), totalScore);
            log.info("计算项目得分表达式 totalScore={}, resultExp = {}", totalScore, modelVO.getResultExp());
        }

        // 匹配非默认结果
        AssessModelResult matchResult = null;
        for (AssessModelResult modelResult : modelVO.getResultList()) {
            if (modelResult.getDefaultResult() == null || !modelResult.getDefaultResult()) {
                String script = modelResult.getResultExp();
                boolean match = RuleEngineManager.instance().addParam(resultItemMap)
                        .setRulescript(script)
                        .match();
                if (match) {
                    matchResult = modelResult;
                    break;
                }
            } else {
                matchResult = modelResult;
            }
        }

        AssertUtil.notNull(matchResult, MessageEnum.ASSESS_CONFIG_ERROR);
        // 计算匹配结果自定义值
        if (StringUtils.isNotEmpty(matchResult.getCustomExp())) {
            String script = matchResult.getCustomExp();
            BigDecimal value = RuleEngineManager.instance().addParam(resultItemMap)
                    .setRulescript(script)
                    .eval2();
            matchResult.setCustomValue(value);
        }

        log.info("返回默认结果 modelResult={}", JsonUtil.objectToString(matchResult));
        return matchResult;
    }
}

项目地址

 sescore: 基于java jdk自带scriptEngineManager 实现规则引擎 疾病评估

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/3974712.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-10-21
下一篇 2022-10-21

发表评论

登录后才能评论

评论列表(0条)

保存