Milvus 核心向量检索执行引擎 Knowhere 设计深度解析:ANNS 索引统一抽象、核心接口与建索/检索流程

发布时间:2026/9/9 20:05:19

Milvus 核心向量检索执行引擎 Knowhere 设计深度解析:ANNS 索引统一抽象、核心接口与建索/检索流程 Milvus 核心向量检索执行引擎 Knowhere 设计深度解析ANNS 索引统一抽象、核心接口与建索/检索流程【免费下载链接】milvusMilvus is a high-performance, cloud-native vector database built for scalable vector ANN search项目地址: https://gitcode.com/GitHub_Trending/mi/milvus本篇以仓库设计文档 20211223-knowhere_design.md 为主体系统讲解 Milvus 向量检索引擎 Knowhere 的核心设计它如何用统一的 C 接口包装 Faiss、HNSWLib 等近似最近邻ANNS算法库如何组织向量数据内存格式以及索引构建、KNN 查询背后的调用时序。读完本文你将理解 Knowhere 在整个 Milvus 架构中的定位掌握BuildAll / Serialize / Load / Query等核心接口的语义并能在当前仓库的 C 与 Go 源码中循迹印证这套设计的落地形态与演进痕迹。Knowhere 设计文档的背景为什么需要统一的检索执行引擎Knowhere 设计文档诞生于 2021 年 12 月文件名为20211223-knowhere_design.md彼时 Milvus 正在向 2.x 云原生架构演进索引与检索逻辑高度耦合在核心中。要支撑丰富多样的索引类型与异构算力Milvus 需要一个检索执行引擎层的统一抽象这就是 Knowhere。要理解 Knowhere首先要理解它面对的两个基础概念向量索引Vector Index向量索引是在向量数据之上、通过某种数学模型构建起来的一种时间高效且空间高效的数据结构。借助向量索引可以快速查询出若干条与目标向量相似的数据。文档明确指出因为精确检索通常非常耗时Milvus 绝大多数向量索引类型都采用 ANNSApproximate Nearest Neighbors Search近似最近邻搜索。近似最近邻搜索ANNS与精确检索相比ANNS 的核心思想不再是必须返回最准确的结果而是只检索目标向量的邻居。它通过在可接受范围内牺牲精度来换取检索效率的大幅提升——这正是向量数据库在海量数据规模下能够做到毫秒级响应的重要前提。Knowhere 这一名字也取自 Milvus 中近似最近邻检索的迭代式权衡。Knowhere 是什么位置与能力边界设计文档对 Knowhere 的定位非常清晰Knowhere is the vector search execution engine of Milvus.即Knowhere 是 Milvus 的向量检索执行引擎。它承担两件关键事情封装多种主流向量索引算法库。原设计文档列举了 faiss、hnswlib、NGT、annoy 等流行库向 Milvus 上层提供一组统一接口使上层无需感知具体算法库的差异。支持异构计算。即同一套上层语义可以运行在不同硬件后端如 CPU 与 GPU之上。需要说明的是架构并非一成不变。从当前仓库源码看Knowhere 已经成为 Milvus 核心引入的独立 C 依赖核心目录 internal/core/src/index/VectorMemIndex.h 中直接#include knowhere/config.h、knowhere/index/index_node.h等头文件并使用knowhere::Indexknowhere::IndexNode、knowhere::Json、knowhere::expected等类型而设计文档 2021 年提到的 NGT、Annoy 库在当前仓库的 client/index 目录中已找不到对应实现文件可以推断它们在演进过程中被裁剪当前仓库仍保留的向量索引模块文件包括flat.go、ivf.go、hnsw.go、scann.go、disk_ann.go、gpu.go、auto.go、sparse.go等向量索引家族依然是 Knowhere 统一管理的一等公民。总体框架一层统一接口多条索引实现设计文档用一张框架图概括了 Knowhere 的整体结构。这张图位于仓库 docs/design-docs/assets/graphs/knowhere_framework.png。框架的核心思路是**接口与实现分离**上层Milvus 各模块建索引、加载、查询只面对 Knowhere 提供的统一 C 接口不直接依赖某个具体算法库中间层Knowhere 负责按索引类型如 FLAT、IVF、HNSW、SCANN、DISKANN 及 GPU 变体路由到对应实现屏蔽各算法库在 API、参数、序列化格式上的差异底层Faiss、HNSWLib 等算法库以插件式方式被调用异构计算能力GPU 索引等也在此层体现。设计文档原话提示For more index types and heterogeneous support, please refer to the vector index document.更多索引类型与异构支持的细节参见向量索引相关文档。换言之框架图的使命是说明统一的入口而索引类型的外延由独立文档维护——这与当前仓库将各类索引实现分散在 Knowhere 依赖中、由 Milvus 核心统一调度的结构一脉相承。统一抽象的核心接口Knowhere 的最小协议设计文档认为 Knowhere 为上层提供的最小必要接口集如下原文 C 代码完整保留/* * Serialize * return: serialization data */ BinarySet Serialize(); /* * Load from serialization data * param [in] dataset_ptr: serialization data */ void Load(const BinarySet); /* * Create index * param [in] dataset_ptr: index data (key of the Dataset is tensor, rows and dim) * parma [in] config: index param */ void BuildAll(const DatasetPtr dataset_ptr, const Config config); /* * KNN (K-Nearest Neighbors) Query * param [in] dataset_ptr: query data (key of the Dataset is tensor and rows) * parma [in] config: query param * parma [out] blacklist: mark for deletion * return: query result (key of the Dataset is ids and distance) */ DatasetPtr Query(const DatasetPtr dataset_ptr, const Config config, BitsetView blacklist); /* * Copy the index from GPU to CPU * return: CPU vector index * notes: Only valid of the GPU indexes */ VecIndexPtr CopyGpuToCpu(); /* * If the user IDs has been set, they will be returned in the Query interface; * else the range of the returned IDs is [0, row_num-1]. * parma [in] uids: user ids */ void SetUids(std::shared_ptrstd::vectorIDType uids); /* * Get the size of the index in memory. * return: index memory size */ int64_t Size();逐个接口的语义拆解接口方向语义说明Serialize()出把内存中的索引序列化成二进制数据BinarySet用于持久化到对象存储或传输Load(const BinarySet)入从序列化数据反序列化重建索引与Serialize成对出现BuildAll(dataset_ptr, config)建索引用训练数据构建索引dataset中需带tensor、rows、dim三个键config提供索引参数Query(dataset_ptr, config, blacklist)检索KNNK-近邻查询dataset提供tensor与rowsblacklist是 BitsetView用于标记待删除/过滤的向量返回结果dataset的键是ids与distanceCopyGpuToCpu()异构仅对 GPU 索引有效把 GPU 上的索引拷回 CPUSetUids(...)元数据设置用户自定义 ID设置后Query返回的是这些用户 ID否则返回[0, row_num-1]的内部编号Size()度量返回索引在内存中的字节大小注意Query中的blacklist参数设计上它不是一个随意的过滤条件而是基于位图BitsetView的删除标记视图配合增删改场景下的删除向量实现逻辑删除不重建索引的机制。这一设计在当前源码中依然延续Milvus 核心查询层多处使用common/BitsetView.h见 internal/core/src/common/BitsetView.h以及 internal/core/src/common/Types.h 中相关的类型定义。从统一接口到仓库落地三层的调用链印证设计文档描绘的是 Knowhere 自身的抽象而真正进入 Milvus 时这一组 C 接口还要经过Go 服务 → C ABI → 索引构建器 → Knowhere的层层封装。当前仓库可以清晰看到这套落地链路的每一环C 侧索引构建器internal/core/src/indexbuilder/VecIndexCreator.h 定义了Build、Serialize、Load、Query、Upload、CleanLocalData等高层方法其内部持有一个milvus::index::IndexBasePtr。而 internal/core/src/index/VectorMemIndex.h 中的Serialize / Load / BuildWithDataset / Query方法签名与设计文档一一对应并通过成员knowhere::Indexknowhere::IndexNode index_真正驱动 Knowhere 工作。C ABI 桥接层internal/core/src/indexbuilder/index_c.h 以extern C暴露CreateIndex / DeleteIndex / BuildFloatVecIndex / BuildBinaryVecIndex / BuildSparseFloatVecIndex / SerializeIndexToBinarySet / LoadIndexFromBinarySet等符号供 Go 通过 cgo 调用。这里可以看到设计文档数据类型在 Build 阶段区分的思路被拆成了按数据类型分发的构建函数族。Go 侧封装层internal/util/indexcgowrapper/index.go 定义了接口CodecIndexBuild / Serialize / GetIndexFileInfo / Load / Delete / CleanLocalData / UpLoad实现类CgoIndex把上述 C 函数翻译成 Go 方法。其中Build方法按schemapb.DataType分发FloatVector / Float16Vector / BFloat16Vector / BinaryVector / Int8Vector / SparseFloatVector 走各自向量索引构建路径标量类型则走BuildScalarIndex见 internal/util/indexcgowrapper/index.go。Serialize与Load则分别通过C.SerializeIndexToBinarySet与C.LoadIndexFromBinarySet完成 BinarySet 的写出与读入。因此如果沿代码追溯一次真实的建索任务链路大致为上层调度由索引协调与数据节点相关任务发起如 internal/datanode/index/task_index.go 所在的索引任务代码→indexcgowrapper.CgoIndex→index_c.h的 C 函数 →VecIndexCreator→VectorMemIndex→ Knowhere 具体索引实现。设计文档里的 7 个方法正是贯穿这条链路始终的语义锚点。向量数据的内存格式一维紧凑排列设计文档明确了 Knowhere 输入输出数据的统一内存格式这是理解各接口参数尤其是BuildAll、Query中Dataset的tensor字段的前提用于建索引与查询的向量数据以一维数组存放。数组前dim * sizeof(data_type)个字节是第一条向量其后依次排列剩余的row_num - 1条向量。即采用行主序row-major连续内存布局没有任何行间 padding。例如 float32 向量、维度dim128第一条向量占据数组头部128 * 4 512字节第二条紧随其后。这样的布局带来的好处是对 Faiss、HNSWLib 等底层算法库而言原始内存可直接零拷贝传入避免数据搬运开销数据集只需提供rows向量条数与dim维度即可推断出整块数据范围GPU 端批量拷贝时连续内存也更容易发挥带宽优势这也呼应了 Knowhere 的异构计算能力。这一内存格式约定在今天的 cgo 数据通道中依然成立Go 侧把向量以连续切片传递给 C 层时使用的正是裸指针加元素个数的形式。以 internal/util/indexcgowrapper/index.go 的cFloatPtr / cUint8Ptr / cInt8Ptr辅助函数为例它们取切片首元素地址转换为*C.float / *C.uint8_t / *C.int8_t交给 C 层本质上就是在传递这条一维连续向量数组。而rows、dim等元信息则由调用方在数据集的 dataset 中随行给出可参考 internal/util/indexcgowrapper/dataset.go 中数据集的装配逻辑。建索引的标准流程设计文档以时序图的形式给出了 Knowhere 建索引的标准流程图片来源仓库 docs/design-docs/assets/graphs/create_index.png。结合接口定义与仓库实现建索引阶段实际包含以下几个关键步骤准备数据以行主序一维数组形式组织待索引向量并在Dataset中声明tensor、rows、dim参数装配把索引类型、度量方式如 L2、IP、COSINE、nlist/M等索引参数组装进Config调用BuildAllKnowhere 依据Config中的索引类型路由到 Faiss/HNSWLib 等具体实现完成训练与建索可选持久化调用Serialize()将索引导出为BinarySet用于上传到对象存储Size()则用于估算索引资源占用、指导调度与放置。在当前仓库中步骤 3 到 4 的落地可追溯到 internal/util/indexcgowrapper/index.go 的Serialize()实现它把 C 层CBinarySet按 key 逐个读出并转成storage.Blob含文件名、内容与内存大小这些 Blob 随后会被上传到对象存储供后续查询节点加载使用。KNN 查询的标准流程与建索引对称设计文档用另一张时序图刻画查询阶段图片来源仓库 docs/design-docs/assets/graphs/knn_query.png。KNN 查询的典型过程如下准备查询向量组织批量查询数据Dataset中提供tensor与rows不要求提供dim建索时已固化维度携带过滤条件通过BitsetView blacklist标记需要屏蔽的向量典型场景是删除操作产生的失效向量检索结果不会包含这些位被置位的向量调用QueryKnowhere 将 topk、度量类型等查询参数解析进Config执行近似搜索返回结果结果以Dataset承载键为ids与distance若此前调用过SetUidsids对应的是用户自定义 ID否则是[0, row_num-1]范围内的内部编号。可以印证的是删除/过滤语义在当前实现中依然是查询的显式入参VectorMemIndex::Query的方法签名保留了const BitsetView bitset见 internal/core/src/index/VectorMemIndex.h标量条件的位图生成与向量删除的位图标记都会在进入 Knowhere 之前被归并成这份BitsetView。而用户 ID vs 内部编号的问题也有了更现代的承接VectorMemIndex通过GetIdMap / SetIdMapType暴露 knowhere 的IdMap见 internal/core/src/index/VectorMemIndex.h可以推断这正是在演进中把设计文档的SetUids升级为可插拔 ID 映射的实现方式。从 2021 设计到仓库现状Knowhere 的演进脉络设计文档是观察 Knowhere 设计意图的绝佳起点而当前仓库则提供了它后来长成什么样的实证。将两者对照可以总结出三条清晰的演进主线接口抽象保持稳定。设计文档确立的统一接口 算法库插件化哲学至今未变Serialize/Load、BuildAll/BuildWithDataset、Query、Size等方法仍以近乎一致的名字存在于 internal/core/src/indexbuilder/VecIndexCreator.h 与 internal/core/src/index/VectorMemIndex.h 中。上层无论面对内存索引还是磁盘索引面对的仍是同一套语义。代码组织走向分层与独立。当初文档描述的是Knowhere 封装各算法库今天的形态则是 Milvus 核心通过 cgo/C ABI 三层结构消费一个独立的 Knowhere 依赖knowhere::Index、knowhere::config.h等头文件均为外部依赖两层之间的边界由 internal/core/src/indexbuilder/index_c.h 和 internal/util/indexcgowrapper 明确划定这也让索引构建可以脱离主查询线程独立调度与资源计量。类型与能力持续扩充。从最初文档强调的浮点/二值向量与 GPU 异构演进到支持 float16、bfloat16、int8、稀疏浮点等多种向量类型且索引形态从纯内存如 IVF、HNSW、SCANN扩展出磁盘索引DISKANN等可见 internal/core/src/index/VectorMemIndex.cpp 与 internal/core/src/index/VectorDiskIndex.cpp 的并存印证了设计文档封装多种算法库、面向更多索引类型开放的初衷。如果你希望继续深入可以在仓库中按此路径展开阅读设计文档原文位于 docs/design-docs/design_docs/20211223-knowhere_design.md想看 C 层统一接口的实现进入 internal/core/src/indexbuilder 与 internal/core/src/index想看 Go 服务如何跨语言驱动 Knowhere阅读 internal/util/indexcgowrapper想验证上述接口行为的可执行样例可查看 internal/util/indexcgowrapper/index_test.go。在这条阅读路径上设计文档中的每一行接口声明都会在真实代码中找到自己的回声。【免费下载链接】milvusMilvus is a high-performance, cloud-native vector database built for scalable vector ANN search项目地址: https://gitcode.com/GitHub_Trending/mi/milvus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/9 20:05:19

AI协作调试:用结构化信息与四步法高效解决报错

先说我上周遇到的一件事。团队群里有人甩了一张报错截图,内容就一行字:“npm : 无法加载文件 d:\program files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。”然后底下附了一句“有人见过吗”。这种问题我见了太多次。报错本身很典型&#…

2026/9/9 20:00:19

SSM+Vue家居租赁系统毕业设计:从数据库到答辩全流程解析

每年大概三、四月份,就有不少同学开始为毕业设计失眠。如果你正盯着“基于SSM和Vue的家居租赁系统”这个题目发愁,既没有现成代码,也不知道论文从哪下笔,这篇文章可以帮你一条龙理顺思路。这类项目说到底就是一个电商系统的变体&a…

2026/9/9 23:40:53

乐鑫ESP32模组智能交互实战:选型、语音、GUI与量产避坑指南

1. 乐鑫模组为什么总能出现在智能交互的第一线 做智能硬件这几年,我发现一个很有意思的现象:不管是做智能音箱、中控屏、离线语音开关,还是做雷达人体存在传感器,大家聊着聊着总会提到乐鑫。早些年大家用ESP8266做联网&#xff0c…

2026/9/9 23:40:53

2007年数学建模B题公交车调度优化:从建模到代码实现

简介:2007年全国大学生数学建模B题通常涉及交通网络或公交路径优化,Dijkstra算法是求解最短路径的核心工具。该压缩包提供了当年参赛队伍的完整Java实现,包含7个Java源文件、11个编译后的class文件以及Eclipse工程配置文件,共21个…

2026/9/9 23:40:53

基于YOLOv8的多端车流检测系统:从训练到部署的完整实践

简介:基于YOLOv8的多端车流检测系统,适合计算机视觉方向的毕业设计或开源研究。资源包共396个文件,体积16.94MB,包含Python源码、预训练权重(.pt)、模型配置(.yaml)、GUI界面文件&am…

2026/9/9 23:40:53

用纯前端实现Markdown在线预览编辑器:从解析到安全渲染全解析

做前端项目的时候,总有那么几个工具类页面看着不起眼,真要动手却发现坑不少。Markdown在线预览编辑器就是典型的例子,看起来无非是左边写右边渲染,实际做下来涉及解析库选型、XSS过滤、代码高亮、同步滚动、性能防抖一堆问题。这篇…

2026/9/9 23:35:52

微信小程序源码学习指南:从支付v3到导航栏适配的实战拆解

简介:压缩包内汇集了近一百个微信小程序完整源码项目,覆盖电商、餐饮、生活服务、资讯阅读等常用行业,无论是课程设计还是工作参考,都适合移动端开发者、前端初学者以及想系统掌握小程序开发流程的学习者。资源共含7590个文件&…

2026/9/9 13:11:35

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/8 7:15:15

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/9 0:00:48

MHS模型硬件标准:让大模型像调用软件一样控制物理设备

让Claude真正看着显微镜说“这个细胞形态不太对”,或者让大模型自己调一版机械臂的运动轨迹,这事儿听上去已经很接近科幻片了。但你真上手试一次就会发现,模型不缺智商,缺的是一个能插进显微镜、机械臂、激光控制器里的“通用插座…

2026/9/9 0:00:48

AI五大核心方向详解:从机器学习到大模型,零基础转行选哪条?

会有人告诉我,他想转行学AI,但打开招聘网站一看直接傻眼:机器学习、深度学习、自然语言处理、计算机视觉、大模型应用……满屏都是这些词,好像每个都会一点,又好像每个都离自己很远。还有人上来就问“学Python还是学Ja…

2026/9/9 0:00:49

从50行最小循环到生产级AI引擎:工程化改造全解析

直接说干货。这一章我写的不是那种"hello world跑通某个模型"的教程,而是把AI引擎当做一个真正要上线、要被人调用、要扛流量的系统来聊。从最初只有50行的最小循环,到能够承载生产流量的AI引擎,中间差的不是代码量,而是…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/7 22:46:00

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/9 10:21:54

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码