资讯详情

向量搜索实现原理详解

📅 2026/9/24 15:14:23 | 华诺云谱 👁 阅读
向量搜索实现原理详解
概述本文档详细分析了VectorServiceImpl.searchQuestion方法的实现原理重点讲述文档过滤策略、内容截断问题的处理方案以及如何保证检索结果的连贯性和准确性。1. 整体架构流程用户问题向量化编码Milvus向量搜索相似度计算topK筛选阈值过滤多策略内容提取内容去重与合并返回最终结果2. 文档过滤机制详解2.1 多层过滤策略我们的向量搜索采用了多层渐进式过滤机制第一层相似度阈值过滤.similarityThreshold(0.3)// 只保留相似度 ≥ 0.3 的文档设计原理0.3 阈值选择经过实际测试0.3 是一个平衡点太高如0.7可能过滤掉语义相关但表达方式不同的文档太低如0.1会引入大量噪音文档向量相似度计算使用余弦相似度公式similarity (A · B) / (||A|| × ||B||)第二层topK 数量控制.topK(5)// 最多返回5个最相似的文档为什么选择5个性能考虑避免处理过多文档影响响应速度质量保证前5个文档通常包含最相关的信息上下文限制LLM 的 context window 有限制第三层内容有效性过滤.filter(content-content!null!content.trim().isEmpty())过滤条件非空检查content ! null空白字符检查!content.trim().isEmpty()确保每个返回的内容都是有意义的文本2.2 文档排序与优先级搜索结果按以下优先级排序相似度得分主要排序依据文档完整性优先选择完整文档内容长度适中长度的文档更有价值3. 内容截断问题的解决方案3.1 截断问题的产生原因在向量化过程中长文档会被切分成多个 chunk原始文档: 董事长寄语我们公司秉承创新、精细、品牌、诚信的理念致力于为客户提供优质服务... 切分后: Chunk1: 董事长寄语我们公司秉承创新、精细、品牌、诚信的理念 Chunk2: 致力于为客户提供优质服务不断追求卓越 Chunk3: 在未来的发展中我们将继续坚持这一理念3.2 多策略内容提取机制我们实现了渐进式内容提取策略// 策略1优先使用 Spring AI 标准方法Stringcontentdoc.getText();// 策略2尝试 metadata 中的 content 字段if(contentnull||content.trim().isEmpty()){contentdoc.getMetadata().getOrDefault(content,).toString();}// 策略3尝试 metadata 中的 text 字段if(contentnull||content.trim().isEmpty()){contentdoc.getMetadata().getOrDefault(text,).toString();}// 策略4尝试 metadata 中的 data 字段if(contentnull||content.trim().isEmpty()){contentdoc.getMetadata().getOrDefault(data,).toString();}每种策略的适用场景策略方法适用场景优势1doc.getText()标准 Spring AI 文档性能最优API 标准2metadata.content自定义存储格式灵活性高支持自定义字段3metadata.text文本类文档兼容性好通用性强4metadata.data结构化数据支持复杂数据结构3.3 内容连贯性保证机制方案一上下文窗口扩展推荐实现publicListStringsearchQuestionWithContext(Stringquestion){// 1. 执行向量搜索ListDocumentdocumentsvectorStore.similaritySearch(searchRequest);// 2. 为每个文档查找相邻的 chunkListStringenhancedResultsnewArrayList();for(Documentdoc:documents){StringchunkIddoc.getMetadata().get(chunk_id).toString();StringdocIddoc.getMetadata().get(document_id).toString();// 查找相邻的 chunkListDocumentcontextChunksfindAdjacentChunks(docId,chunkId);// 合并内容StringmergedContentmergeChunks(contextChunks);enhancedResults.add(mergedContent);}returnenhancedResults;}privateListDocumentfindAdjacentChunks(StringdocId,StringchunkId){// 查找 chunk_id-1, chunk_id, chunk_id1SearchRequestcontextRequestSearchRequest.builder().filter(newFilter.Expression(Filter.ExpressionType.AND,List.of(newFilter.Expression(Filter.ExpressionType.EQ,document_id,docId),newFilter.Expression(Filter.ExpressionType.IN,chunk_id,Arrays.asList(chunkId-1,chunkId,chunkId1))))).build();returnvectorStore.similaritySearch(contextRequest);}方案二重叠窗口策略在文档切分时就考虑连贯性// 文档切分时使用重叠窗口publicListStringsplitDocumentWithOverlap(Stringdocument,intchunkSize,intoverlapSize){ListStringchunksnewArrayList();intstart0;while(startdocument.length()){intendMath.min(startchunkSize,document.length());Stringchunkdocument.substring(start,end);// 确保在句子边界切分if(enddocument.length()){intlastPeriodchunk.lastIndexOf(。);intlastExclamationchunk.lastIndexOf();intlastQuestionchunk.lastIndexOf();intsentenceEndMath.max(Math.max(lastPeriod,lastExclamation),lastQuestion);if(sentenceEndchunk.length()*0.7){// 如果句子边界在后70%位置endstartsentenceEnd1;chunkdocument.substring(start,end);}}chunks.add(chunk);startend-overlapSize;// 重叠部分}returnchunks;}4. 高级优化策略4.1 智能去重机制privateListStringdeduplicateResults(ListStringresults){SetStringseennewHashSet();ListStringdeduplicatednewArrayList();for(Stringcontent:results){// 计算内容的哈希值或使用编辑距离StringsignaturecalculateContentSignature(content);if(!seen.contains(signature)){seen.add(signature);deduplicated.add(content);}}returndeduplicated;}privateStringcalculateContentSignature(Stringcontent){// 移除标点符号和空格计算核心内容的哈希Stringnormalizedcontent.replaceAll([\\p{Punct}\\s],);returnInteger.toString(normalized.hashCode());}4.2 语义相关性增强privateListStringenhanceSemanticRelevance(Stringquestion,ListStringresults){returnresults.stream().map(content-{// 计算与问题的语义相关度doublerelevanceScorecalculateSemanticRelevance(question,content);returnnewScoredContent(content,relevanceScore);}).filter(scored-scored.score0.5)// 过滤低相关度内容.sorted((a,b)-Double.compare(b.score,a.score))// 按相关度排序.map(scored-scored.content).collect(Collectors.toList());}4.3 动态阈值调整privatedoublecalculateDynamicThreshold(Stringquestion){// 根据问题的复杂度和长度动态调整阈值intquestionLengthquestion.length();intcomplexityScorecalculateQuestionComplexity(question);doublebaseThreshold0.3;// 问题越复杂阈值越低更宽松if(complexityScore5){baseThreshold-0.1;}// 问题越短阈值越高更严格if(questionLength10){baseThreshold0.1;}returnMath.max(0.1,Math.min(0.8,baseThreshold));}5. 性能优化与监控5.1 缓存策略Cacheable(valuevectorSearch,key#question)publicListStringsearchQuestion(Stringquestion){// 实际搜索逻辑}5.2 异步处理AsyncpublicCompletableFutureListStringsearchQuestionAsync(Stringquestion){returnCompletableFuture.completedFuture(searchQuestion(question));}5.3 监控指标// 记录关键性能指标log.info(向量搜索性能指标 - 问题长度: {}, 返回文档数: {}, 耗时: {}ms,question.length(),documents.size(),duration);// 记录搜索质量指标log.info(搜索质量指标 - 平均相似度: {}, 内容完整率: {}%,averageSimilarity,contentCompletenessRate);6. 实际应用场景6.1 董事长寄语查询示例用户问题: “董事长寄语是什么”处理流程:问题向量化:[0.1, 0.8, -0.3, 0.5, ...]向量搜索: 在 Milvus 中查找相似文档结果筛选:文档1: 相似度 0.85 - 董事长寄语我们公司秉承... 文档2: 相似度 0.72 - 创新、精细、品牌、诚信是我们的核心理念... 文档3: 相似度 0.45 - 公司发展历程中董事长多次强调...内容提取与合并返回完整答案6.2 技术问题查询示例用户问题: “如何实现 Spring Boot 自动配置”处理策略:使用更严格的阈值 (0.4) 确保技术准确性优先返回代码示例和配置文件合并相关的多个技术文档片段7. 总结我们的向量搜索实现通过以下机制保证了高质量的检索结果多层过滤: 相似度阈值 topK限制 内容有效性检查容错机制: 多策略内容提取适应不同数据格式连贯性保证: 上下文窗口扩展 重叠切分策略智能优化: 去重、语义增强、动态阈值调整性能监控: 缓存、异步处理、关键指标记录这种设计确保了即使在复杂的企业知识库环境中也能准确、快速地检索到用户需要的信息为后续的 LLM 生成提供高质量的上下文支持。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。