From e7921a26a43993d96c96a91f03055a8748489a33 Mon Sep 17 00:00:00 2001 From: "DESKTOP-DDTUS3E\\yaxin" Date: Wed, 30 Oct 2024 18:20:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A8=E6=96=B0=E6=A8=A1=E5=9E=8B=E5=88=86?= =?UTF-8?q?=E6=9E=90=E6=96=B9=E6=B3=95=E5=88=9D=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constant/IndexRuleConstants.java | 9 + .../supervision/police/domain/ModelIndex.java | 5 + .../dto/indexRule/AtomicResultContent.java | 24 -- .../police/dto/indexRule/IndexRule.java | 50 +++ .../police/dto/indexRule/Operand.java | 10 +- .../police/dto/indexRule/RuleCondition.java | 19 + .../dto/indexRule/RuleConditionGroup.java | 19 + .../police/service/ModelService.java | 2 + .../police/service/impl/ModelServiceImpl.java | 368 +++++++++++++++++- .../supervision/utils/CalculationUtil.java | 75 ++++ 10 files changed, 548 insertions(+), 33 deletions(-) delete mode 100644 src/main/java/com/supervision/police/dto/indexRule/AtomicResultContent.java create mode 100644 src/main/java/com/supervision/police/dto/indexRule/IndexRule.java create mode 100644 src/main/java/com/supervision/police/dto/indexRule/RuleCondition.java create mode 100644 src/main/java/com/supervision/police/dto/indexRule/RuleConditionGroup.java create mode 100644 src/main/java/com/supervision/utils/CalculationUtil.java diff --git a/src/main/java/com/supervision/common/constant/IndexRuleConstants.java b/src/main/java/com/supervision/common/constant/IndexRuleConstants.java index ac7c38f..424a5c4 100644 --- a/src/main/java/com/supervision/common/constant/IndexRuleConstants.java +++ b/src/main/java/com/supervision/common/constant/IndexRuleConstants.java @@ -63,4 +63,13 @@ public class IndexRuleConstants { public static final String OPERATOR_EARLY = "早于"; public static final String OPERATOR_LATE = "晚于"; public static final String OPERATOR_CONTAIN = "包含"; + + /** + * 评估结果 1:真实 2:虚构 3:存在 4:不存在 5:未知 + */ + public static final String EVALUATE_RESULT_TRUE = "1"; + public static final String EVALUATE_RESULT_FALSE = "2"; + public static final String EVALUATE_RESULT_EXIST = "3"; + public static final String EVALUATE_RESULT_NOT_EXIST = "4"; + public static final String EVALUATE_RESULT_UNKNOWN = "5"; } diff --git a/src/main/java/com/supervision/police/domain/ModelIndex.java b/src/main/java/com/supervision/police/domain/ModelIndex.java index 2b54b0e..8ff532d 100644 --- a/src/main/java/com/supervision/police/domain/ModelIndex.java +++ b/src/main/java/com/supervision/police/domain/ModelIndex.java @@ -70,6 +70,11 @@ public class ModelIndex implements Serializable { */ private String judgeLogic; + /** + * 指标规则 + */ + private String indexRule; + @TableField(exist = false) @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") diff --git a/src/main/java/com/supervision/police/dto/indexRule/AtomicResultContent.java b/src/main/java/com/supervision/police/dto/indexRule/AtomicResultContent.java deleted file mode 100644 index 044c312..0000000 --- a/src/main/java/com/supervision/police/dto/indexRule/AtomicResultContent.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.supervision.police.dto.indexRule; - -import lombok.Data; - -import java.util.Map; - -/** - * 原子指标结果容器 - */ -@Data -public class AtomicResultContent { - - private String atomicIndexId; - - private String atomicIndexType; - - /** - * 原子指标结果 -1:未知, 0:不存在, 1存在 - */ - private String result; - - - private Map properties; -} diff --git a/src/main/java/com/supervision/police/dto/indexRule/IndexRule.java b/src/main/java/com/supervision/police/dto/indexRule/IndexRule.java new file mode 100644 index 0000000..7fc686e --- /dev/null +++ b/src/main/java/com/supervision/police/dto/indexRule/IndexRule.java @@ -0,0 +1,50 @@ +package com.supervision.police.dto.indexRule; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.supervision.common.constant.IndexRuleConstants; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class IndexRule { + /** + * 条件组之间逻辑关系 默认或 + */ + + private String logic = "2"; + + /** + * 规则条件组 + */ + private List ruleConditionGroupList = new ArrayList<>(); + + public static void main(String[] args) { + // 准备一套样例数据,并转换为JSON字符串打印 + IndexRule indexRule = new IndexRule(); + RuleConditionGroup ruleConditionGroup = new RuleConditionGroup(); + RuleCondition ruleCondition = new RuleCondition(); + OperandUnit operandUnit = new OperandUnit(); + Operand operandLeft = new Operand(); + operandLeft.setAtomicIndexId("1");//原子指标ID + operandLeft.setOperandType(IndexRuleConstants.OPERAND_TYPE_STRUCTURE);//结构化 + operandLeft.setValueType(IndexRuleConstants.VALUE_TYPE_STRING);//文本 + operandLeft.setPropertyKey("合同金额");//属性键 + operandLeft.setAggregateType(IndexRuleConstants.AGGREGATE_TYPE_ANY);//聚合类型 任一 + Operand operandRight = new Operand(); + operandRight.setOperandType(IndexRuleConstants.OPERAND_TYPE_VALUE); + operandRight.setValueType(IndexRuleConstants.VALUE_TYPE_STRING); + operandUnit.setLeftOperand(operandLeft); + operandUnit.setOperator("="); + operandUnit.setRightOperand(operandRight); + ruleCondition.setOperandUnitList(List.of(operandUnit)); + ruleConditionGroup.setRuleConditionList(List.of(ruleCondition)); + indexRule.setRuleConditionGroupList(List.of(ruleConditionGroup)); + //转成JSON字符串并打印 + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + String json = gson.toJson(indexRule); + System.out.println(json); + } +} diff --git a/src/main/java/com/supervision/police/dto/indexRule/Operand.java b/src/main/java/com/supervision/police/dto/indexRule/Operand.java index 521f44b..5a29bc3 100644 --- a/src/main/java/com/supervision/police/dto/indexRule/Operand.java +++ b/src/main/java/com/supervision/police/dto/indexRule/Operand.java @@ -2,6 +2,9 @@ package com.supervision.police.dto.indexRule; import lombok.Data; +import java.util.HashSet; +import java.util.Set; + /** * 操作数 */ @@ -24,9 +27,14 @@ public class Operand{ */ private String value; + /** + * 值类型 + */ + private String valueType; + /** * - * 操作数类型 0:人工定义类型 1:数据库查询类型 2:图谱生成类型 3:结构提取类型 4:值 + * 操作数类型 */ private String operandType; diff --git a/src/main/java/com/supervision/police/dto/indexRule/RuleCondition.java b/src/main/java/com/supervision/police/dto/indexRule/RuleCondition.java new file mode 100644 index 0000000..8017b3b --- /dev/null +++ b/src/main/java/com/supervision/police/dto/indexRule/RuleCondition.java @@ -0,0 +1,19 @@ +package com.supervision.police.dto.indexRule; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class RuleCondition { + /** + * 条件内逻辑关系 默认或 + */ + private String logic = "2"; + + /** + * 条件内操作单元 + */ + private List operandUnitList = new ArrayList<>(); +} diff --git a/src/main/java/com/supervision/police/dto/indexRule/RuleConditionGroup.java b/src/main/java/com/supervision/police/dto/indexRule/RuleConditionGroup.java new file mode 100644 index 0000000..fe6807b --- /dev/null +++ b/src/main/java/com/supervision/police/dto/indexRule/RuleConditionGroup.java @@ -0,0 +1,19 @@ +package com.supervision.police.dto.indexRule; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class RuleConditionGroup { + /** + * 条件组内逻辑关系 默认或 + */ + private String logic = "2"; + + /** + * 规则条件 + */ + private List ruleConditionList = new ArrayList<>(); +} diff --git a/src/main/java/com/supervision/police/service/ModelService.java b/src/main/java/com/supervision/police/service/ModelService.java index 9b1c62e..f96900d 100644 --- a/src/main/java/com/supervision/police/service/ModelService.java +++ b/src/main/java/com/supervision/police/service/ModelService.java @@ -11,6 +11,8 @@ public interface ModelService { R analyseCase(AnalyseCaseDTO analyseCaseDTO); + R analyseCaseNew(AnalyseCaseDTO analyseCaseDTO); + /** * 获取案件详情 * @param caseId 案件id diff --git a/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java b/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java index 220609e..7ef005a 100644 --- a/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java +++ b/src/main/java/com/supervision/police/service/impl/ModelServiceImpl.java @@ -8,28 +8,30 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.deepoove.poi.XWPFTemplate; + import com.google.gson.Gson; import com.supervision.common.domain.R; import com.supervision.common.utils.StringUtils; import com.supervision.constant.JudgeResultEnum; import com.supervision.neo4j.dto.ResultDTO; import com.supervision.neo4j.utils.Neo4jUtils; import com.supervision.police.domain.*; -import com.supervision.police.dto.AnalyseCaseDTO; -import com.supervision.police.dto.AtomicData; -import com.supervision.police.dto.CaseStatus; -import com.supervision.police.dto.JudgeLogic; +import com.supervision.police.dto.*; import com.supervision.police.dto.caseScore.CaseScore; import com.supervision.police.dto.caseScore.CaseScoreDetailBuilder; import com.supervision.police.dto.caseScore.CaseScoreDetailDTO; +import com.supervision.police.dto.indexRule.IndexRule; +import com.supervision.police.dto.indexRule.Operand; import com.supervision.police.mapper.*; import com.supervision.police.mybatis.RowSqlMapper; import com.supervision.police.service.*; +import com.supervision.utils.CalculationUtil; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.neo4j.driver.Driver; import org.neo4j.driver.Result; import org.neo4j.driver.Session; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; @@ -40,8 +42,12 @@ import java.io.InputStream; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import static com.supervision.common.constant.IndexRuleConstants.*; +import static com.supervision.common.constant.NotePromptConstants.TYPE_STRUCTURAL_REASONING; + @Slf4j @Service @RequiredArgsConstructor @@ -73,6 +79,18 @@ public class ModelServiceImpl implements ModelService { private final NoteRecordService noteRecordService; + @Autowired + private NotePromptService notePromptService; + + @Autowired + private EvidenceDirectoryService evidenceDirectoryService; + + @Autowired + private CaseEvidenceService caseEvidenceService; + + @Autowired + private ModelAtomicResultService modelAtomicResultService; + @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public R analyseCase(AnalyseCaseDTO analyseCaseDTO) { @@ -116,7 +134,7 @@ public class ModelServiceImpl implements ModelService { analyseGraphCase(analyseCaseDTO, result, ql, casePerson.getName()); } else if ("4".equals(atomicIndex.getIndexSource())) { // - }else if ("5".equals(atomicIndex.getIndexSource())) { + } else if ("5".equals(atomicIndex.getIndexSource())) { // todo: 结构化推理 //analyseStructuredInference(analyseCaseDTO, result); } @@ -152,12 +170,346 @@ public class ModelServiceImpl implements ModelService { return R.ok(); } + @Override + public R analyseCaseNew(AnalyseCaseDTO analyseCaseDTO) { + log.info("数据准备阶段"); + String caseId = analyseCaseDTO.getCaseId(); + Map typeScoreMap = new HashMap<>(); + // 查出案件信息 + ModelCase modelCase = modelCaseMapper.selectById(caseId); + // 获取案件行为人ID + CasePerson casePerson = casePersonMapper.selectOne(new LambdaQueryWrapper() + .eq(CasePerson::getCaseId, analyseCaseDTO.getCaseId()) + .eq(CasePerson::getCaseActorFlag, 1) + .eq(CasePerson::getRoleCode, "1") + .eq(StrUtil.isNotEmpty(analyseCaseDTO.getLawActorName()), CasePerson::getName, analyseCaseDTO.getLawActorName())); + if (ObjectUtil.isEmpty(casePerson)) { + throw new RuntimeException("未找到的行为人" + analyseCaseDTO.getLawActorName()); + } + // 查出指标信息 + List modelIndices = modelIndexMapper.selectByCaseType(modelCase.getCaseType()); + // 查出原子指标信息 + List atomicIndices = modelAtomicIndexMapper.selectByCaseType(modelCase.getCaseType()); + // 查出提示词信息 + List notePrompts = notePromptService.list(new LambdaQueryWrapper().eq(NotePrompt::getType, TYPE_STRUCTURAL_REASONING)); + // 查出证据目录信息 + List evidenceDirectories = evidenceDirectoryService.list(new LambdaQueryWrapper().eq(EvidenceDirectory::getCaseId, caseId)); + // 查出证据信息 + List caseEvidences = caseEvidenceService.list(new LambdaQueryWrapper().eq(CaseEvidence::getCaseId, caseId)); + // 遍历指标集合,处理每个指标的判断逻辑,得出结果 + modelIndices.forEach(modelIndex -> { + String indexRuleStr = modelIndex.getIndexRule(); + Gson gson = new Gson(); + IndexRule indexRule = gson.fromJson(indexRuleStr, IndexRule.class); + Set ruleConditionGroupResultList = new HashSet<>(); + indexRule.getRuleConditionGroupList().forEach(ruleConditionGroup -> { + Set ruleConditionResultSet = new HashSet<>(); + ruleConditionGroup.getRuleConditionList().forEach(ruleCondition -> { + Set operandUnitResultSet = new HashSet<>(); + ruleCondition.getOperandUnitList().forEach(operandUnit -> { + Operand left = operandUnit.getLeftOperand(); + Operand right = operandUnit.getRightOperand(); + ModelAtomicIndex modelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(left.getAtomicIndexId())).findAny().orElse(null); + if (modelAtomicIndex == null) { + log.error("原子指标不存在,跳出当前循环。原子指标ID:{}", left.getAtomicIndexId()); + return; + } + // 定义原子指标结果共有属性 + ModelAtomicResult result = new ModelAtomicResult(); + result.setIndexId(modelIndex.getId()); + result.setCasePersonId(casePerson.getId()); + result.setCaseId(analyseCaseDTO.getCaseId()); + result.setAtomicId(modelAtomicIndex.getId()); + result.setAtomicResult(JudgeResultEnum.NOT_EXIST.getCode()); + ModelAtomicResult exist = modelAtomicResultMapper.selectByCaseIdAndAtomicId(caseId, casePerson.getId(), modelIndex.getId(), modelAtomicIndex.getId()); + if (exist != null) { + result.setId(exist.getId()); + } + switch (left.getOperandType()) { + case OPERAND_TYPE_MANUAL: + operandUnitResultSet.add(manualIndexAnalysis(left, caseId)); + break; + case OPERAND_TYPE_DB: + operandUnitResultSet.add(dbIndexAnalysis(caseId, modelAtomicIndex.getQueryLang(), result)); + break; + case OPERAND_TYPE_GRAPH: + operandUnitResultSet.add(graphIndexAnalysis(modelIndex, casePerson, modelAtomicIndex, analyseCaseDTO, result)); + break; + case OPERAND_TYPE_STRUCTURE: + operandUnitResultSet.add(structureIndexAnalysis(left, right, operandUnit.getOperator(), modelAtomicIndex, atomicIndices, notePrompts, evidenceDirectories, caseEvidences, result)); + break; + default: + break; + } + }); + ruleConditionResultSet.add(CalculationUtil.calculateBooleanSet(operandUnitResultSet, ruleCondition.getLogic())); + }); + ruleConditionGroupResultList.add(CalculationUtil.calculateBooleanSet(ruleConditionResultSet, ruleConditionGroup.getLogic())); + }); + boolean result = CalculationUtil.calculateBooleanSet(ruleConditionGroupResultList, indexRule.getLogic()); + if (result) { + Integer score = typeScoreMap.getOrDefault(modelIndex.getIndexType(), 0); + typeScoreMap.put(modelIndex.getIndexType(), score + modelIndex.getIndexScore()); + } + }); + log.info("计算分数(共性+入罪/共性+出罪 取最大值)"); + Integer gx = typeScoreMap.getOrDefault("1", 0); + Integer rz = typeScoreMap.getOrDefault("2", 0); + Integer cz = typeScoreMap.getOrDefault("3", 0); + int max = Integer.max(gx + rz, gx + cz); + modelCase.setTotalScore(max); + log.info("更新案件得分情况"); + caseStatusManageService.whenAnalyseCaseSuccess(analyseCaseDTO.getCaseId(), modelCase.getTotalScore()); + noteRecordService.uploadFileToLangChainChat(analyseCaseDTO.getCaseId()); + return R.ok(); + } + + /** + * 人工定义指标分析 + * + * @param left 左操作数 + * @param caseId 案件ID + */ + private boolean manualIndexAnalysis(Operand left, String caseId) { + boolean flag = false; + List modelAtomicResults = modelAtomicResultMapper.selectList( + new LambdaQueryWrapper().eq(ModelAtomicResult::getCaseId, caseId) + .eq(ModelAtomicResult::getAtomicId, left.getAtomicIndexId())); + if (modelAtomicResults != null && !modelAtomicResults.isEmpty()) { + ModelAtomicResult modelAtomicResult = CollUtil.getFirst(modelAtomicResults); + flag = EVALUATE_RESULT_EXIST.equals(modelAtomicResult.getAtomicResult()); + } + return flag; + } + + /** + * 数据库查询指标分析 + * + * @param caseId 案件ID + * @param sql 查询语句 + * @param atomicResult 原子指标结果 + * @return 是否存在 + */ + private boolean dbIndexAnalysis(String caseId, String sql, ModelAtomicResult atomicResult) { + Map params = new HashMap<>(); + params.put("caseId", caseId); + List mapList = rowSqlMapper.selectList(sql, params, Map.class); + boolean flag = false; + if (mapList != null && !mapList.isEmpty()) { + flag = true; + String evidenceIds = mapList.stream().map(map -> map.get("id").toString()).collect(Collectors.joining(",")); + atomicResult.setEvidenceId(evidenceIds); + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + } + modelAtomicResultService.saveOrUpdate(atomicResult); + return flag; + } + + /** + * 图谱查询指标分析 + * + * @param modelIndex 大指标 + * @param casePerson 行为人 + * @param modelAtomicIndex 原子指标 + * @param analyseCaseDTO 案件信息 + * @return 是否存在 + */ + private boolean graphIndexAnalysis(ModelIndex modelIndex, CasePerson casePerson, ModelAtomicIndex modelAtomicIndex, AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult atomicResult) { + boolean flag = false; + Session session = driver.session(); + //图谱 + Map params = new HashMap<>(); + // 行为人 + params.put("lawActor", casePerson.getName()); + // 案号 + params.put("caseId", analyseCaseDTO.getCaseId()); + Result run = null; + try { + run = session.run(modelAtomicIndex.getQueryLang(), params); + } catch (Exception e) { + log.error("图数据库查询出现错误,查询语句{},参数{}", modelAtomicIndex.getQueryLang(), JSONUtil.toJsonStr(params), e); + } + List res = Neo4jUtils.getResultDTOList(run); + if (!res.isEmpty()) { + // 进行遍历,如果有存在的,就设置为有 + for (ResultDTO resultDTO : res) { + if (StringUtils.isNotEmpty(resultDTO.getRelId())) { + //存在关系 + flag = true; + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + atomicResult.setRecordId(resultDTO.getRecordId()); + // 在退出循环之前先合并相关文本分片id + String recordSplitIdJoin = res.stream().filter(r -> + StringUtils.isNotEmpty(r.getRelId()) + && StringUtils.isNotEmpty(r.getRecordSplitId())) + .map(ResultDTO::getRecordSplitId).collect(Collectors.joining(",")); + atomicResult.setRecordSplitId(recordSplitIdJoin); + } + } + } + modelAtomicResultService.saveOrUpdate(atomicResult); + return flag; + } + + /** + * 结构化查询指标分析 + * + * @param left 左操作数 + * @param right 右操作数 + * @param modelAtomicIndex 原子指标 + * @param atomicIndices 原子指标集合 + * @param notePrompts 提示词集合 + * @param evidenceDirectories 证据目录集合 + * @param caseEvidences 证据集合 + * @param atomicResult 原子指标结果 + * @return 是否存在 + */ + private boolean structureIndexAnalysis(Operand left, Operand right, String operator, ModelAtomicIndex modelAtomicIndex, List atomicIndices, List notePrompts, List evidenceDirectories, List caseEvidences, ModelAtomicResult atomicResult) { + boolean flag = false; + List evidences = getEvidencesByPromptId(modelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts); + ModelAtomicIndex rightModelAtomicIndex = null; + if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) { + log.info("右操作数为结构化查询,提前查好对应的原子指标"); + rightModelAtomicIndex = atomicIndices.stream().filter(atomicIndex -> atomicIndex.getId().equals(left.getAtomicIndexId())).findAny().orElse(null); + if (rightModelAtomicIndex == null || StringUtils.isEmpty(rightModelAtomicIndex.getPromptId())) { + log.error("原子指标不存在。原子指标ID:{}", left.getAtomicIndexId()); + return flag; + } + } + if (!evidences.isEmpty()) { + log.info("聚合类型为【{}】,右操作数操作类型为:【{}】", AGGREGATE_TYPE_SUM.equals(left.getAggregateType()) ? "求和" : AGGREGATE_TYPE_COUNT.equals(left.getAggregateType()) ? "计数" : "任一", OPERAND_TYPE_STRUCTURE.equals(right.getOperandType()) ? "结构化查询" : "值"); + switch (left.getAggregateType()) { + case AGGREGATE_TYPE_SUM: + if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) { + List rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts); + if (CalculationUtil.evaluateExpression(String.valueOf(getSumFromEvidences(left, evidences)), operator, String.valueOf(getSumFromEvidences(right, rightEvidences)))) { + atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(","))); + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + modelAtomicResultService.saveOrUpdate(atomicResult); + return true; + } + } else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) { + if (CalculationUtil.evaluateExpression(String.valueOf(getSumFromEvidences(left, evidences)), operator, right.getValue())) { + atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(","))); + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + modelAtomicResultService.saveOrUpdate(atomicResult); + return true; + } + } + break; + case AGGREGATE_TYPE_COUNT: + if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) { + List rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts); + if (CalculationUtil.evaluateExpression(String.valueOf(evidences.size()), operator, String.valueOf(rightEvidences.size()))) { + atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(","))); + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + modelAtomicResultService.saveOrUpdate(atomicResult); + return true; + } + } else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) { + if (CalculationUtil.evaluateExpression(String.valueOf(evidences.size()), operator, right.getValue())) { + atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(","))); + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + modelAtomicResultService.saveOrUpdate(atomicResult); + return true; + } + } + break; + case AGGREGATE_TYPE_ANY: + if (OPERAND_TYPE_STRUCTURE.equals(right.getOperandType())) { + List rightEvidences = getEvidencesByPromptId(rightModelAtomicIndex.getPromptId(), caseEvidences, evidenceDirectories, notePrompts); + Set leftValueSet = getValueSetFromEvidences(left, evidences); + Set rightValueSet = getValueSetFromEvidences(right, rightEvidences); + // 使用CalculationUtil.evaluateExpression方法遍历比较leftValueSet和rightValueSet的任一值,一旦有一个满足(返回true),则return true + if (leftValueSet.stream().anyMatch(leftValue -> rightValueSet.stream().anyMatch(rightValue -> CalculationUtil.evaluateExpression(leftValue, operator, rightValue)))) { + atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(","))); + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + modelAtomicResultService.saveOrUpdate(atomicResult); + return true; + } + } else if (OPERAND_TYPE_VALUE.equals(right.getOperandType())) { + Set leftValueSet = getValueSetFromEvidences(left, evidences); + if (leftValueSet.stream().anyMatch(leftValue -> CalculationUtil.evaluateExpression(leftValue, operator, right.getValue()))) { + atomicResult.setEvidenceId(evidences.stream().map(CaseEvidence::getId).collect(Collectors.joining(","))); + atomicResult.setAtomicResult(JudgeResultEnum.EXIST.getCode()); + modelAtomicResultService.saveOrUpdate(atomicResult); + return true; + } + } + break; + default: + break; + } + } else { + log.error("证据不存在。提示词ID:{}", modelAtomicIndex.getPromptId()); + } + return flag; + } + + private Double getSumFromEvidences(Operand operand, List evidences) { + AtomicReference sum = new AtomicReference<>(0.0); + if (evidences != null && !evidences.isEmpty()) { + evidences.forEach(e -> { + List properties = e.getProperty(); + if (properties != null && !properties.isEmpty()) { + properties.forEach(p -> { + if (p.getAttrName().equals(operand.getPropertyKey())) { + if (StringUtils.isNotEmpty(p.getAttrValue())) { + sum.updateAndGet(v -> v + NumberUtil.parseDouble(p.getAttrValue())); + } + } + }); + } + }); + } + return sum.get(); + } + + private Set getValueSetFromEvidences(Operand operand, List evidences) { + Set valueSet = new HashSet<>(); + evidences.forEach(e -> { + List properties = e.getProperty(); + if (properties != null && !properties.isEmpty()) { + properties.forEach(p -> { + if (p.getAttrName().equals(operand.getPropertyKey())) { + if (StringUtils.isNotEmpty(p.getAttrValue())) { + valueSet.add(p.getAttrValue()); + } + } + }); + } + }); + return valueSet; + } + + /** + * 根据原子指标ID获取证据集合 + * + * @param promptId 提示词ID + * @param caseEvidences 全量案件证据集合 + * @param evidenceDirectories 证据目录集合 + * @param notePrompts 提示词集合 + * @return 证据集合 + */ + private static List getEvidencesByPromptId(String promptId, List caseEvidences, List evidenceDirectories, List notePrompts) { + List evidences = new ArrayList<>(); + NotePrompt notePrompt = notePrompts.stream().filter(n -> n.getId().equals(promptId)).findAny().orElse(null); + if (notePrompt == null) { + log.error("提示词不存在。提示词ID:{}", promptId); + return evidences; + } + List directories = evidenceDirectories.stream().filter(e -> e.getCategoryId().equals(notePrompt.getEvidenceCategoryId())).toList(); + List directoryIds = directories.stream().map(EvidenceDirectory::getId).toList(); + evidences = caseEvidences.stream().filter(e -> directoryIds.contains(e.getDirectoryId())).toList(); + return evidences; + } + /** * 手动定义原子指标处理 * - * @param analyseCaseDTO - * @param result - * @param atomicIndex + * @param analyseCaseDTO 案件信息 + * @param result 原子指标结果 + * @param atomicIndex 原子指标 */ private void manuallyDefinedCase(AnalyseCaseDTO analyseCaseDTO, ModelAtomicResult result, ModelAtomicIndex atomicIndex) { List modelAtomicResults = modelAtomicResultMapper.selectList( diff --git a/src/main/java/com/supervision/utils/CalculationUtil.java b/src/main/java/com/supervision/utils/CalculationUtil.java new file mode 100644 index 0000000..2028e66 --- /dev/null +++ b/src/main/java/com/supervision/utils/CalculationUtil.java @@ -0,0 +1,75 @@ +package com.supervision.utils; + +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.util.Set; + +import static com.supervision.common.constant.IndexRuleConstants.LOGIC_AND; +import static com.supervision.common.constant.IndexRuleConstants.LOGIC_OR; + +public class CalculationUtil { + + /** + * 计算表达式结果 + * + * @param leftOperand 左操作数 + * @param operator 操作符 + * @param rightOperand 右操作数 + * @return 计算结果 + */ + public static boolean evaluateExpression(String leftOperand, String operator, String rightOperand) { + // 构建表达式 + String expression = leftOperand + " " + operator + " " + rightOperand; + + // 初始化SpEL解析器 + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + + // 计算结果 + return Boolean.TRUE.equals(parser.parseExpression(expression).getValue(context, Boolean.class)); + } + + /** + * 计算布尔值集合的逻辑运算结果 + * + * @param booleanSet 布尔值集合 + * @param logic 逻辑运算符 + * @return 计算结果 + */ + public static boolean calculateBooleanSet(Set booleanSet, String logic) { + // 判断是否为空 + if (booleanSet == null || booleanSet.isEmpty()) { + throw new IllegalArgumentException("Boolean set cannot be null or empty"); + } + + // 判断是"且"还是"或" + String operator; + if (LOGIC_AND.equals(logic)) { + operator = " and "; + } else if (LOGIC_OR.equals(logic)) { + operator = " or "; + } else { + throw new IllegalArgumentException("Invalid logic value, use 1 for AND, 2 for OR."); + } + + // 构建表达式 + StringBuilder expressionBuilder = new StringBuilder(); + boolean first = true; + for (Boolean bool : booleanSet) { + if (!first) { + expressionBuilder.append(operator); + } + expressionBuilder.append(bool); + first = false; + } + + // 初始化SpEL解析器 + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + + // 计算结果 + return Boolean.TRUE.equals(parser.parseExpression(expressionBuilder.toString()).getValue(context, Boolean.class)); + } +}