引言

在上篇中,我们发现了KNN结果通过SubSearch机制被保留的关键事实。本篇将继续深入分析混合搜索的执行机制,揭示完整的处理流程,并解答之前的所有疑惑。

深入源码分析

1. SubSearch的执行机制

1.1 KnnScoreDocQueryBuilder的实现

KNN结果被转换为KnnScoreDocQueryBuilder,这个类负责在查询阶段重新执行KNN搜索:

// server/src/main/java/org/elasticsearch/index/query/KnnScoreDocQueryBuilder.java
public class KnnScoreDocQueryBuilder extends AbstractQueryBuilder<KnnScoreDocQueryBuilder> {private final String field;private final List<ScoreDoc> scoreDocs;@Overrideprotected Query doToQuery(SearchExecutionContext context) throws IOException {// 创建KnnScoreDocQuery,包含DFS阶段找到的文档ID和分数return new KnnScoreDocQuery(field, scoreDocs);}
}
1.2 KnnScoreDocQuery的核心逻辑
// 简化版的KnnScoreDocQuery实现
public class KnnScoreDocQuery extends Query {private final String field;private final List<ScoreDoc> scoreDocs;@Overridepublic Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) {return new Weight(this) {@Overridepublic Scorer scorer(LeafReaderContext context) {// 只对DFS阶段找到的文档进行打分return new KnnScoreDocScorer(this, context, scoreDocs);}};}
}

2. 分数计算与合并机制

2.1 主查询分数计算

主查询对10000+文档进行打分,然后应用boost:

// 主查询分数计算
float queryScore = calculateQueryScore(document);
float finalQueryScore = queryScore * 0.05; // 应用boost
2.2 KNN分数计算

KNN SubSearch只对50篇候选文档进行打分:

// KNN分数计算
float knnScore = calculateKnnScore(document);
float finalKnnScore = knnScore * 1.0; // 应用boost
2.3 分数合并逻辑

通过OR逻辑合并所有文档的分数:

// 分数合并逻辑(简化版)
Map<String, Float> finalScores = new HashMap<>();// 处理主查询结果
for (ScoreDoc scoreDoc : queryResults) {String docId = getDocId(scoreDoc);float score = scoreDoc.score * 0.05;finalScores.put(docId, score);
}// 处理KNN结果
for (ScoreDoc scoreDoc : knnResults) {String docId = getDocId(scoreDoc);float score = scoreDoc.score * 1.0;// OR逻辑:取最大值if (finalScores.containsKey(docId)) {finalScores.put(docId, Math.max(finalScores.get(docId), score));} else {finalScores.put(docId, score);}
}

3. Filter的影响路径

3.1 Filter的传递过程

KNN的filter通过以下路径传递到向量搜索:

// KnnVectorQueryBuilder.java
public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBuilder> {private final String field;private final float[] queryVector;private final int k;private final int numCandidates;private final QueryBuilder filter; // 关键:filter字段@Overrideprotected Query doToQuery(SearchExecutionContext context) throws IOException {Query filterQuery = null;if (filter != null) {filterQuery = filter.toQuery(context);}// 创建KnnVectorQuery,传入filterreturn new KnnVectorQuery(field, queryVector, k, numCandidates, filterQuery);}
}
3.2 向量搜索中的Filter应用
// DenseVectorFieldMapper.java 第903行
case FLOAT -> parentFilter != null? new DiversifyingChildrenFloatKnnVectorQuery(name(), queryVector, filter, numCands, parentFilter): new KnnFloatVectorQuery(name(), queryVector, numCands, filter);

Filter直接限制向量搜索的候选文档范围,这就是为什么KNN的filter会影响最终结果的原因。

完整执行流程图

时序图

客户端ElasticsearchDFS阶段DfsQueryPhase主查询执行KNN查询执行分数合并发送混合搜索请求开始DFS阶段执行KNN查询(应用filter)返回top 50候选文档DFS阶段完成开始DfsQueryPhaseKNN结果转换为SubSearchDfsQueryPhase完成执行主查询对10000+文档打分×0.05主查询完成执行KNN SubSearch对50文档打分×1KNN完成分数合并OR逻辑合并所有分数合并完成最终排序和分页返回前50条结果客户端ElasticsearchDFS阶段DfsQueryPhase主查询执行KNN查询执行分数合并

数据流图

混合搜索请求
DFS阶段
KNN查询执行
向量搜索
应用filter
返回top 50
DfsKnnResults
DfsQueryPhase
转换为SubSearch
KnnScoreDocQueryBuilder
主查询执行
对10000+文档打分
应用boost 0.05
KNN SubSearch执行
对50文档打分
应用boost 1
分数合并
OR逻辑合并
最终排序
应用from/size
返回结果

关键问题解答

问题1:KNN结果是否被丢弃?

答案: 不会。KNN结果通过SubSearch机制被保留在最终查询中。

问题2:Filter如何影响结果?

答案: Filter直接影响向量搜索的候选范围,限制KNN只在满足条件的文档中搜索。

问题3:分数如何合并?

答案: 通过OR逻辑合并,取每个文档的query分数×0.05和knn分数×1的最大值。

问题4:from/size的作用?

答案: 在最终分数排序后应用,选取总分最高的前50篇文档。

性能优化建议

1. 参数调优

1.1 num_candidates优化
{"knn": {"field": "q_vec","k": 50,"num_candidates": 100  // 根据数据量调整}
}
  • 小数据集: num_candidates = k * 2
  • 大数据集: num_candidates = k * 10
  • 性能与精度平衡: 根据实际需求调整
1.2 boost值调优
{"query": {"bool": {"boost": 0.05  // 根据业务需求调整}},"knn": {"boost": 1.0  // 根据业务需求调整}
}

2. 索引优化

2.1 向量索引优化
{"mappings": {"properties": {"q_vec": {"type": "dense_vector","dims": 768,"index": true,"similarity": "cosine"}}}
}
2.2 文本字段优化
{"mappings": {"properties": {"title_tks": {"type": "text","analyzer": "standard","search_analyzer": "standard"}}}
}

3. 查询优化

3.1 Filter优化
{"knn": {"filter": {"bool": {"must": [{"term": {"category": "research"  // 使用精确匹配}}]}}}
}
3.2 字段权重优化
{"query_string": {"fields": ["title_tks^10",      // 标题权重最高"important_kwd^30",  // 关键词权重最高"content_ltks^2"     // 内容权重较低]}
}

监控与调试

1. 查询性能监控

{"query": {...},"knn": {...},"profile": true  // 启用查询分析
}

2. 分数调试

{"query": {...},"knn": {...},"_source": false,"explain": true  // 启用分数解释
}

总结

通过深入源码分析,我们完全理解了Elasticsearch混合搜索的执行机制:

关键发现

  1. KNN结果不会被丢弃: 通过SubSearch机制保留
  2. Filter直接影响向量搜索: 限制候选文档范围
  3. 分数通过OR逻辑合并: 取query和knn分数的最大值
  4. boost值影响最终排序: 0.05 vs 1.0的权重差异

执行流程

  1. DFS阶段: KNN查询执行,返回候选文档
  2. DfsQueryPhase: KNN结果转换为SubSearch
  3. 主查询执行: 独立执行query和knn sub_search
  4. 分数合并: 通过OR逻辑和boost值合并分数
  5. 最终排序: 按总分排序并应用分页

实际应用

这个理解帮助我们:

  • 正确配置混合搜索参数
  • 优化查询性能
  • 调试查询问题
  • 设计更好的搜索策略

经验总结

1. 源码分析的价值

直接查看源码是理解复杂系统的最佳方式,比文档更准确、更深入。

2. 系统性思维的重要性

不能孤立地看某个组件,要理解整个系统的协作机制。

3. 实践验证的必要性

理论认知需要通过实际测试来验证,避免被表面现象误导。

4. 持续学习的态度

技术不断发展,要保持好奇心和学习热情。

参考资料

  • Elasticsearch 8.11 源码
  • server/src/main/java/org/elasticsearch/action/search/DfsQueryPhase.java
  • server/src/main/java/org/elasticsearch/search/SearchService.java
  • docs/reference/search/search-your-data/knn-search.asciidoc
  • Lucene 向量搜索文档

本文档基于Elasticsearch 8.11源码分析,如有疑问或发现错误,欢迎讨论交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/914138.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/914138.shtml
英文地址,请注明出处:http://en.pswp.cn/news/914138.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache HTTP Server 从安装到配置

一、Apache 是什么&#xff1f;Apache&#xff08;全称 Apache HTTP Server&#xff09;是当前最流行的开源Web服务器软件之一&#xff0c;由Apache软件基金会维护。它以稳定性高、模块化设计和灵活的配置著称&#xff0c;支持Linux、Windows等多平台&#xff0c;是搭建个人博客…

php中调用对象的方法可以使用array($object, ‘methodName‘)?

是的&#xff0c;在PHP中&#xff0c;array($object, methodName) 是一种标准的回调语法&#xff0c;用于表示“调用某个对象的特定方法”。这种语法可以被许多函数&#xff08;如 call_user_func()、call_user_func_array()、usort() 等&#xff09;识别并执行。 语法原理 在P…

【设计模式】单例模式 饿汉式单例与懒汉式单例

单例模式&#xff08;Singleton Pattern&#xff09;详解一、单例模式简介 单例模式&#xff08;Singleton Pattern&#xff09; 是一种 创建型设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取这个实例。&#xff08;对象创建型模式&…

vue3 el-table 行数据沾满格自动换行

在使用 Vue 3 结合 Element Plus 的 <el-table> 组件时&#xff0c;如果你希望当表格中的行数据文本过长时能够自动换行&#xff0c;而不是溢出到其他单元格或简单地截断&#xff0c;你可以通过以下几种方式来实现&#xff1a;方法 1&#xff1a;使用 CSS最简单的方法是通…

windows电脑远程win系统服务器上的wsl2

情况 我自己使用win11笔记本电脑&#xff0c;想要远程win11服务器上的wsl2 我这里只有服务器安装了wsl2&#xff0c;win11笔记本没有安装 因此下面提到的Ubuntu终端指的是win服务器上的wsl2终端 一定要区分是在哪里输入命令&#xff01;&#xff01; 安装SSH 在服务器上&#x…

神经辐射场 (NeRF):重构三维世界的AI新视角

神经辐射场 (NeRF)&#xff1a;重构三维世界的AI新视角 旧金山蜿蜒起伏的街道上&#xff0c;一辆装备12个摄像头的Waymo自动驾驶测试车缓缓驶过。它记录的280万张街景图像并未被简单地拼接成平面地图&#xff0c;而是被输入一个名为Block-NeRF的神经网络。数周后&#xff0c;一…

Kubernetes自动扩缩容方案对比与实践指南

Kubernetes自动扩缩容方案对比与实践指南 随着微服务架构和容器化的广泛采用&#xff0c;Kubernetes 自动扩缩容&#xff08;Autoscaling&#xff09;成为保障生产环境性能稳定与资源高效利用的关键技术。面对水平 Pod 扩缩容、垂直资源调整、集群节点扩缩容以及事件驱动扩缩容…

【CVPR2025】计算机视觉|SIREN: 元学习赋能!突破INR高分辨率图像分类难题

论文地址&#xff1a;https://arxiv.org/pdf/2503.18123v1 代码地址&#xff1a;https://github.com/SanderGielisse/MWT 关注UP CV缝合怪&#xff0c;分享最计算机视觉新即插即用模块&#xff0c;并提供配套的论文资料与代码。 https://space.bilibili.com/473764881 摘要 …

牛客周赛 Round 99

赛时成绩如下&#xff1a;A. Round 99题目描述 对于给定的五位整数&#xff0c;检查其中是否含有数字 99&#xff1b;换句话说&#xff0c;检查是否存在相邻的两个数位&#xff0c;其值均为 。解题思路&#xff1a; 检查相邻的两个数字是否均为9#include <bits/stdc.h> u…

从0到1搭建个人技术博客:用GitHub Pages+Hexo实现

一、为什么要搭建个人技术博客&#xff1f; 在技术圈&#xff0c;拥有个人博客的好处不言而喻&#xff1a; 简历加分项&#xff1a;面试官更青睐有技术沉淀的候选人知识系统化&#xff1a;输出倒逼输入&#xff0c;加深技术理解人脉拓展&#xff1a;吸引同行关注&#xff0c;…

Ubuntu22.04 设置显示存在双屏却无法双屏显示

文章目录一、背景描述二、解决方法一、背景描述 回到工位后&#xff0c;发现昨天离开时还可正常显示的双屏&#xff0c;今早ubuntu22.04 的设置界面显示有双屏&#xff0c;但外接的显示屏无法正常显示。 首先&#xff0c;查看当前图像处理显卡是否为N卡&#xff0c;没错&#…

高亚科技签约奕源金属,助力打造高效智能化采购管理体系

深圳市奕源金属制品有限公司近日&#xff0c;国内企业管理软件服务商高亚科技与深圳市奕源金属制品有限公司&#xff08;以下简称“奕源金属”&#xff09;正式签约&#xff0c;双方将基于高亚科技自主研发的8Manage SRM采购管理系统&#xff0c;共同推动奕源金属采购管理的数字…

数据结构之map

map的基本介绍我们常常把map称之为映射&#xff0c;就是将一个元素&#xff08;通常称之为key键&#xff09;与一个相对应的值&#xff08;通常称之为value&#xff09;关联起来&#xff0c;比如说一个学生的名字&#xff08;key&#xff09;有与之对应的成绩&#xff08;value…

vue3 canvas 选择器 Canvas 增加页面性能

文章目录Vue3 选择器 Canvas 增加页面性能基于Vue3 Composition API和Canvas实现的交互式选择器&#xff0c;支持PC端和移动端的拖动选择、多选取消选择功能vue3组件封装html代码Vue3 选择器 Canvas 增加页面性能 基于Vue3 Composition API和Canvas实现的交互式选择器&#xf…

Python 实战:打造多文件批量重命名工具

引言在实际运维、测试、数据分析、开发流程中&#xff0c;我们经常会处理成百上千条命令操作&#xff0c;例如&#xff1a;各种脚本任务&#xff08;启动、备份、重启、日志查看&#xff09;数据处理流程&#xff08;爬取 → 清洗 → 统计 → 可视化&#xff09;配置自动化&…

设计模式笔记_结构型_代理模式

1. 代理模式介绍代理模式是一种结构型设计模式&#xff0c;它允许你提供一个代理对象来控制对另一个对象的访问。代理对象通常在客户端和目标对象之间起到中介作用&#xff0c;能够在不改变目标对象的前提下增加额外的功能操作&#xff0c;比如延迟初始化、访问控制、日志记录等…

C语言<数据结构-单链表>(收尾)

上篇博客我将基础的尾插、尾删、头插、头删逐一讲解了&#xff0c;这篇博客将对上篇博客进行收尾&#xff0c;讲一下指定位置操作增删以及查找这几个函数&#xff0c;其实大同小异&#xff1a;一.查找函数&#xff1a;查找函数其实就是一个简单的循环遍历&#xff0c;所以不加以…

十年架构心路:从单机到云原生的分布式系统演进史

十年架构心路&#xff1a;从单机到云原生的分布式系统演进史 这里写目录标题十年架构心路&#xff1a;从单机到云原生的分布式系统演进史一、技术生涯的起点&#xff1a;单体架构的黄金时代1.1 典型技术栈1.2 记忆深刻的故障二、分布式架构转型期2.1 服务化拆分实践2.2 分布式事…

使用docker搭建nginx

安装docker 和 docker compose验证docker版本配置docker目录配置代理&#xff0c;使docker能访问外网能否ping通最后直接拉入镜像即可docker pull nginx

Intel新CPU助攻:微软Copilot+将登陆台式电脑

微软的Copilot PC计划已经推出一年多&#xff0c;但目前仅支持平板电脑和笔记本电脑&#xff0c;以及少数迷你电脑。 随着Intel下一代桌面处理器——代号为“Arrow Lake Refresh”的推出&#xff0c;Copilot PC功能有望扩展到桌面计算机。 要支持Copilot PC的所有功能&#xff…