基于YOLOv12的棉花叶片病害识别系统开发指南
2026/10/29 3:59:38
这段时间工作上,需要开发一个功能,可以动态选择表和字段形成一条条规则,然后规则又可以进行不通的组合,比如三条中至少满足一条并且满足另外一条这种刁钻的规则条件,具体功能描述可以看图。当时还真是为了实现这个功能考虑到头大,他难点在于既要实现规则的判断,又要满足下面条件的二次判断,好在也在同事的帮助下想出了思路,这里和大家分享下,后续类似地方都可以参考这个思路。
在系统中,我们需要实现以下功能:
为了解决这些问题,我们采用了以下设计思路:
将规则系统分为两个核心部分:
使用树形结构来表示规则之间的逻辑关系,支持三种节点类型:
使用递归算法来处理树形结构,实现规则树的转换和解析。
@Data@EqualsAndHashCode(callSuper=false)@Accessors(chain=true)@TableName("MON_RULE_DEFINITIONS")@ApiModel(value="MonRuleDefinitions对象",description="判定规则定义表")publicclassMonRuleDefinitionsextendsModel<MonRuleDefinitions>{@ApiModelProperty(value="主键")@TableId(value="ID",type=IdType.ASSIGN_ID)privateStringid;@ApiModelProperty(value="规则组id")@TableField("RULE_GROUP_ID")privateStringruleGroupId;@ApiModelProperty(value="来源字典编码【字典】;table_name")@TableField("FROM_DICT_CODE")privateStringfromDictCode;@ApiModelProperty(value="具体字段编码")@TableField("SPECIFIC_FIELD_CODE")privateStringspecificFieldCode;@ApiModelProperty(value="匹配值代码【字典】;more_range")@TableField("MATCH_TYPE_CODE")privateStringmatchTypeCode;@ApiModelProperty(value="指标值")@TableField("ITEM_VALUE")privateStringitemValue;// ... 其他字段}代码分析:
@Data@EqualsAndHashCode(callSuper=false)@Accessors(chain=true)@TableName("MON_RULE_CONFIG")@ApiModel(value="MonBaseRuleConfig对象",description="判定规则配置表")publicclassMonBaseRuleConfigextendsModel<MonBaseRuleConfig>{@ApiModelProperty(value="主键")@TableId(value="ID",type=IdType.ASSIGN_ID)privateStringid;@ApiModelProperty(value="规则类型 1-疾病分级 2-患者管理 3-质控")@TableField("RULE_TYPE")privateStringruleType;@ApiModelProperty(value="规则组id")@TableField("RULE_GROUP_ID")privateStringruleGroupId;@ApiModelProperty(value="父节点ID,用于构建树结构")@TableField("PARENT_NODE_ID")privateStringparentNodeId;@ApiModelProperty(value="节点类型(RULE、OPERATOR、GROUP)")@TableField("NODE_TYPE")privateStringnodeType;@ApiModelProperty(value="逻辑运算符(AND、OR);more_range")@TableField("OPERATOR")privateStringoperator;@ApiModelProperty(value="如果节点是规则,则关联规则ID")@TableField("RULE_ID")privateStringruleId;@ApiModelProperty(value="对于GROUP类型,最少满足的规则数量;item_result_unit_code")@TableField("MIN_COUNT")privateStringminCount;@ApiModelProperty(value="对于GROUP类型,最多满足的规则数量")@TableField("MAX_COUNT")privateStringmaxCount;// ... 其他字段}代码分析:
publicstaticvoidconvertAndCollectNodes(RuleNodeDTOcurrentNode,StringruleGroupId,StringparentNodeId,List<MonBaseRuleConfig>allNodes){if("RULE".equals(currentNode.getNodeType())&¤tNode.getRuleId()==null){thrownewBaseException(998,"规则节点缺少规则ID");}// 转换当前DTO为数据库实体MonBaseRuleConfigdbNode=newMonBaseRuleConfig();BeanUtil.copyProperties(currentNode,dbNode);dbNode.setRuleGroupId(ruleGroupId);// 特殊处理GROUP类型if("GROUP".equals(currentNode.getNodeType())){dbNode.setRuleId(String.join(",",(List<String>)currentNode.getRuleId()));if("min".equals(currentNode.getCountType())){dbNode.setMinCount(currentNode.getCount());dbNode.setMaxCount("");}else{dbNode.setMaxCount(currentNode.getCount());dbNode.setMinCount("");}}allNodes.add(dbNode);// 递归处理子节点if(!CollectionUtils.isEmpty(currentNode.getChildren())){for(RuleNodeDTOchild:currentNode.getChildren()){convertAndCollectNodes(child,ruleGroupId,currentNode.getId(),allNodes);}}}代码分析:
publicstaticRuleNodeDTObuildNode(MonBaseRuleConfigcurrentNode,Map<String,List<MonBaseRuleConfig>>parentMap){// 转换为DTORuleNodeDTOnodeDTO=BeanUtil.copyProperties(currentNode,RuleNodeDTO.class);// 获取当前节点的子节点列表List<MonBaseRuleConfig>children=parentMap.getOrDefault(currentNode.getId(),newArrayList<>());// 递归构建子节点List<RuleNodeDTO>childDTOs=children.stream().map(child->buildNode(child,parentMap)).collect(Collectors.toList());// GROUP节点特殊处理if("GROUP".equals(currentNode.getNodeType())){if(!childDTOs.isEmpty()){List<Object>ruleIds=childDTOs.stream().map(RuleNodeDTO::getRuleId).collect(Collectors.toList());RuleNodeDTOruleNodeDTO=childDTOs.get(0);ruleNodeDTO.setRuleId(ruleIds);nodeDTO.setChildren(Collections.singletonList(ruleNodeDTO));}else{nodeDTO.setChildren(childDTOs);}}else{// 非GROUP节点保留完整嵌套结构nodeDTO.setChildren(childDTOs);}returnnodeDTO;}代码分析:
publicIntegersaveNode(List<RuleNodeDTO>judgeGroup,StringruleGroupId,List<MonRuleDefinitions>ruleDefinitions){if(CollectionUtils.isEmpty(judgeGroup)){return0;}// 收集所有转换后的数据库实体List<MonBaseRuleConfig>allNodes=newArrayList<>();// 处理顶级节点(递归处理所有子节点)for(RuleNodeDTOrootNode:judgeGroup){RuleNodeUtil.convertAndCollectNodes(rootNode,ruleGroupId,null,allNodes);}// 批量插入数据库if(!CollectionUtils.isEmpty(allNodes)){// 删除旧的规则配置List<MonBaseRuleConfig>list=this.lambdaQuery().eq(MonBaseRuleConfig::getRuleGroupId,ruleGroupId).list();list.removeIf(judge->allNodes.stream().map(MonBaseRuleConfig::getId).collect(Collectors.toList()).contains(judge.getId()));List<String>monConfigDel=list.stream().map(MonBaseRuleConfig::getId).collect(Collectors.toList());this.removeByIds(monConfigDel);// 保存新的规则配置this.saveOrUpdateBatch(allNodes);}returnallNodes.size();}代码分析:
高血压分级 = (收缩压 > 140mmHg OR 舒张压 > 90mmHg) AND 年龄 > 65岁高危患者 = (糖尿病 AND 血压 > 130/80mmHg) OR (冠心病 AND 血脂异常)质控合格 = (病历书写完整率 > 95%) AND (随访及时率 > 90%) AND (患者满意度 > 85%)通过以上分析,我们可以看到这套规则引擎实现方案具有以下特点:
在实际应用中,我们可以根据具体业务需求,灵活配置各种判定规则,提高系统的灵活性和可维护性。
// 优化建议:添加事务管理@Transactional(rollbackFor=Exception.class)publicIntegersaveNode(List<RuleNodeDTO>judgeGroup,StringruleGroupId,List<MonRuleDefinitions>ruleDefinitions){// ... 原有代码}通过以上优化,可以进一步提高规则引擎的性能和可靠性。