(eid int64, req *SearchRequest)
| 1023 | } |
| 1024 | |
| 1025 | func (s *SearchService) applyEntityScopeNarrowingWithMeta(eid int64, req *SearchRequest) (*entityScopeNarrowMeta, error) { |
| 1026 | if req == nil { |
| 1027 | return nil, nil |
| 1028 | } |
| 1029 | |
| 1030 | fuzzyKeywords := normalizeEntityKeywords(req.EntityKeywords) |
| 1031 | |
| 1032 | meta := &entityScopeNarrowMeta{} |
| 1033 | originalLibraryIDs := append([]int64(nil), req.LibraryIDs...) |
| 1034 | originalFileIDs := append([]int64(nil), req.FileIDs...) |
| 1035 | signals := buildScopeSignals(req.Query, fuzzyKeywords, req.DocumentType) |
| 1036 | |
| 1037 | if len(fuzzyKeywords) == 0 { |
| 1038 | logger.SysDebugf("【实体向量匹配】无有效实体关键词,直接启用查询信号兜底: eid=%d, query=%q", eid, truncateForDebug(req.Query, 256)) |
| 1039 | fallbackLibraryIDs, narrowed, positiveScoreCount, fallbackErr := s.rankLibrariesByScopeSignals(eid, originalLibraryIDs, signals) |
| 1040 | if fallbackErr != nil { |
| 1041 | logger.SysDebugf("【实体向量匹配】查询信号兜底收敛失败: eid=%d, err=%v", eid, fallbackErr) |
| 1042 | return meta, nil |
| 1043 | } |
| 1044 | if narrowed { |
| 1045 | req.LibraryIDs = fallbackLibraryIDs |
| 1046 | logger.SysDebugf("【实体向量匹配】查询信号兜底收敛: eid=%d, 原始知识库数=%d, 最终知识库数=%d, 正向评分数=%d", |
| 1047 | eid, len(originalLibraryIDs), len(req.LibraryIDs), positiveScoreCount) |
| 1048 | } |
| 1049 | return meta, nil |
| 1050 | } |
| 1051 | |
| 1052 | logger.SysDebugf("【实体向量匹配】开始: eid=%d, keywords=%v", eid, fuzzyKeywords) |
| 1053 | likeEntities := searchEntityLikeMatchFn(s, eid, fuzzyKeywords) |
| 1054 | logger.SysDebugf("【实体向量匹配】LIKE命中: eid=%d, keywords=%v, hit=%d", eid, fuzzyKeywords, len(likeEntities)) |
| 1055 | |
| 1056 | var vectorEntities []model.Entity |
| 1057 | var vectorErr error |
| 1058 | skipVector, skipThreshold := shouldSkipEntityVectorMatch(len(likeEntities), len(fuzzyKeywords)) |
| 1059 | if skipVector { |
| 1060 | logger.SysDebugf("【实体向量匹配】LIKE命中已足够,跳过向量检索: eid=%d, keywords=%v, like_hit=%d, threshold=%d", |
| 1061 | eid, fuzzyKeywords, len(likeEntities), skipThreshold) |
| 1062 | } else { |
| 1063 | vectorEntities, vectorErr = searchEntityVectorMatchFn(s, eid, fuzzyKeywords) |
| 1064 | if vectorErr != nil { |
| 1065 | logger.SysDebugf("【实体向量匹配】向量检索失败,继续使用LIKE结果: eid=%d, keywords=%v, err=%v", eid, fuzzyKeywords, vectorErr) |
| 1066 | } |
| 1067 | logger.SysDebugf("【实体向量匹配】向量命中: eid=%d, keywords=%v, hit=%d", eid, fuzzyKeywords, len(vectorEntities)) |
| 1068 | } |
| 1069 | |
| 1070 | entities := mergeEntityMatches(likeEntities, vectorEntities) |
| 1071 | logger.SysDebugf("【实体向量匹配】合并完成: eid=%d, keywords=%v, like_hit=%d, vector_hit=%d, merged_hit=%d", |
| 1072 | eid, fuzzyKeywords, len(likeEntities), len(vectorEntities), len(entities)) |
| 1073 | |
| 1074 | if len(entities) == 0 { |
| 1075 | logger.SysDebugf("【实体向量匹配】未匹配到任何有效实体: eid=%d, keywords=%v", eid, fuzzyKeywords) |
| 1076 | fallbackLibraryIDs, narrowed, positiveScoreCount, fallbackErr := s.rankLibrariesByScopeSignals(eid, originalLibraryIDs, signals) |
| 1077 | if fallbackErr != nil { |
| 1078 | logger.SysDebugf("【实体向量匹配】查询信号兜底收敛失败: eid=%d, err=%v", eid, fallbackErr) |
| 1079 | return meta, nil |
| 1080 | } |
| 1081 | if narrowed { |
| 1082 | req.LibraryIDs = fallbackLibraryIDs |
no test coverage detected