CreateIndex API执行流程_milvus源码解析

简介: CreateIndex API执行流程_milvus源码解析

CreateIndex API执行流程源码解析

milvus版本:v2.3.2

整体架构:

architecture.png

CreateIndex 的数据流向:

create_index数据流向.jpg

1.客户端sdk发出CreateIndex API请求。

import numpy as np
from pymilvus import (
    connections,
    FieldSchema, CollectionSchema, DataType,
    Collection,
)

num_entities, dim = 2000, 8


print("start connecting to Milvus")
connections.connect("default", host="192.168.230.71", port="19530")


fields = [
    FieldSchema(name="pk", dtype=DataType.VARCHAR, is_primary=True, auto_id=False, max_length=100),
    FieldSchema(name="random", dtype=DataType.DOUBLE),
    FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=dim)
]

schema = CollectionSchema(fields, "hello_milvus is the simplest demo to introduce the APIs")

print("Create collection `hello_milvus`")
hello_milvus = Collection("hello_milvus", schema, consistency_level="Strong")


print("Start inserting entities")
rng = np.random.default_rng(seed=19530)
entities = [
    # provide the pk field because `auto_id` is set to False
    [str(i) for i in range(num_entities)],
    rng.random(num_entities).tolist(),  # field random, only supports list
    rng.random((num_entities, dim)),    # field embeddings, supports numpy.ndarray and list
]

insert_result = hello_milvus.insert(entities)

hello_milvus.flush()

print("Start Creating index IVF_FLAT")
index = {
   
   
    "index_type": "IVF_FLAT",
    "metric_type": "L2",
    "params": {
   
   "nlist": 8},
}

hello_milvus.create_index("embeddings", index,index_name="idx_embeddings")

客户端SDK向proxy发送一个CreateIndex API请求,在embeddings列上创建一个名为idx_embeddings的索引。

2.客户端接受API请求,将request封装为createIndexTask,并压入ddQueue队列。

代码路径:internal\proxy\impl.go

// CreateIndex create index for collection.
func (node *Proxy) CreateIndex(ctx context.Context, request *milvuspb.CreateIndexRequest) (*commonpb.Status, error) {
   
   
    ......

    // request封装为task
    cit := &createIndexTask{
   
   
        ctx:                ctx,
        Condition:          NewTaskCondition(ctx),
        req:                request,
        rootCoord:          node.rootCoord,
        datacoord:          node.dataCoord,
        replicateMsgStream: node.replicateMsgStream,
    }

    ......
    // 将task压入ddQueue队列

    if err := node.sched.ddQueue.Enqueue(cit); err != nil {
   
   
        ......
    }

    ......
    // 等待cct执行完
    if err := cit.WaitToFinish(); err != nil {
   
   
        ......
    }

    ......
}

3.执行createIndexTask的3个方法PreExecute、Execute、PostExecute。

PreExecute()一般为参数校验等工作。

Execute()一般为真正执行逻辑。

代码路径:internal\proxy\task_index.go

func (cit *createIndexTask) Execute(ctx context.Context) error {
   
   
    ......
    req := &indexpb.CreateIndexRequest{
   
   
        CollectionID:    cit.collectionID,
        FieldID:         cit.fieldSchema.GetFieldID(),
        IndexName:       cit.req.GetIndexName(),
        TypeParams:      cit.newTypeParams,
        IndexParams:     cit.newIndexParams,
        IsAutoIndex:     cit.isAutoIndex,
        UserIndexParams: cit.newExtraParams,
        Timestamp:       cit.BeginTs(),
    }
    cit.result, err = cit.datacoord.CreateIndex(ctx, req)
    ......
    SendReplicateMessagePack(ctx, cit.replicateMsgStream, cit.req)
    return nil
}

从代码可以看出调用了datacoord的CreateIndex接口。

4.进入datacoord的CreateIndex接口。

代码路径:internal\datacoord\index_service.go

// CreateIndex create an index on collection.
// Index building is asynchronous, so when an index building request comes, an IndexID is assigned to the task and
// will get all flushed segments from DataCoord and record tasks with these segments. The background process
// indexBuilder will find this task and assign it to IndexNode for execution.
func (s *Server) CreateIndex(ctx context.Context, req *indexpb.CreateIndexRequest) (*commonpb.Status, error) {
   
   
    ......
    // 分配indexID,indexID=0
    indexID, err := s.meta.CanCreateIndex(req)
    ......

    if indexID == 0 {
   
   
        // 分配indexID
        indexID, err = s.allocator.allocID(ctx)
        ......
    }

    index := &model.Index{
   
   
        CollectionID:    req.GetCollectionID(),
        FieldID:         req.GetFieldID(),
        IndexID:         indexID,
        IndexName:       req.GetIndexName(),
        TypeParams:      req.GetTypeParams(),
        IndexParams:     req.GetIndexParams(),
        CreateTime:      req.GetTimestamp(),
        IsAutoIndex:     req.GetIsAutoIndex(),
        UserIndexParams: req.GetUserIndexParams(),
    }

    // Get flushed segments and create index

    err = s.meta.CreateIndex(index)
    ......

    // 将collectionID发送到channel,其它的goroutine进行消费。
    select {
   
   
    case s.notifyIndexChan <- req.GetCollectionID():
    default:
    }

    ......
}

变量index:

index_model.jpg

5.进入s.meta.CreateIndex()

代码路径:internal\datacoord\index_meta.go

func (m *meta) CreateIndex(index *model.Index) error {
   
   
    ......
    // 写入etcd元数据
    if err := m.catalog.CreateIndex(m.ctx, index); err != nil {
   
   
        ......
    }

    m.updateCollectionIndex(index)
    ......
}

在这里重点研究m.catalog.CreateIndex()这个方法做了什么事情。

func (kc *Catalog) CreateIndex(ctx context.Context, index *model.Index) error {
   
   
    key := BuildIndexKey(index.CollectionID, index.IndexID)

    value, err := proto.Marshal(model.MarshalIndexModel(index))
    if err != nil {
   
   
        return err
    }

    err = kc.MetaKv.Save(key, string(value))
    if err != nil {
   
   
        return err
    }
    return nil
}

在etcd会产生1个key。

==field-index/445834678636119060/445834678636519085==

value的值的结构为indexpb.FieldIndex,然后进行protobuf序列化后存入etcd。

因此etcd存储的是二进制数据。

&indexpb.FieldIndex{
   
   
    IndexInfo: &indexpb.IndexInfo{
   
   
        CollectionID:    index.CollectionID,
        FieldID:         index.FieldID,
        IndexName:       index.IndexName,
        IndexID:         index.IndexID,
        TypeParams:      index.TypeParams,
        IndexParams:     index.IndexParams,
        IsAutoIndex:     index.IsAutoIndex,
        UserIndexParams: index.UserIndexParams,
    },
    Deleted:    index.IsDeleted,
    CreateTime: index.CreateTime,
}

fieldindex.jpg

跟踪BuildIndexKey()函数,即可以得到key的规则。整理如下:

key规则:

  • 前缀/field-index/{collectionID}/{IndexID}

可以反映index属于哪个collection。Index的value可以反映属于哪个field。

不能反映属于哪个partition、哪个segment。

总结:

  • CreateIndex由proxy传递给协调器dataCoord操作etcd。
  • CreateIndex最终会在etcd上写入1种类型的key(其实还有一种,在另一篇中进行介绍)。
目录
相关文章
|
12月前
|
存储 缓存 算法
淘宝买家秀 API 深度开发:多模态内容解析与合规推荐技术拆解
本文详解淘宝买家秀接口(taobao.reviews.get)的合规调用、数据标准化与智能推荐全链路方案。涵盖权限申请、多模态数据清洗、情感分析、混合推荐模型及缓存优化,助力开发者提升审核效率60%、商品转化率增长28%,实现UGC数据高效变现。
|
12月前
|
XML 数据采集 API
用Lxml高效解析XML格式数据:以天气API为例
免费Python教程:实战解析中国天气网XML数据,详解Lxml库高效解析技巧、XPath用法、流式处理大文件及IP封禁应对策略,助你构建稳定数据采集系统。
517 0
|
API 开发者 数据采集
高效获取淘宝商品详情:API 开发实现链接解析的完整技术方案
2025反向海淘新机遇:依托代购系统,聚焦小众垂直品类,结合Pandabay数据选品,降本增效。系统实现智能翻译、支付风控、物流优化,助力中式养生茶等品类利润翻倍,新手也能快速入局全球市场。
高效获取淘宝商品详情:API 开发实现链接解析的完整技术方案
|
数据采集 存储 供应链
第三方电商数据 API 数据来源深度解析:合规与稳定背后的核心逻辑
本文揭秘第三方电商数据API的底层逻辑:通过官方授权、生态共享与合规采集三重来源,结合严格清洗校验,确保数据稳定、合规、高质。企业选型应关注来源合法性与场景匹配度,避开数据陷阱,实现真正数据驱动增长
|
JSON API 数据安全/隐私保护
Python采集淘宝拍立淘按图搜索API接口及JSON数据返回全流程指南
通过以上流程,可实现淘宝拍立淘按图搜索的完整调用链路,并获取结构化的JSON商品数据,支撑电商比价、智能推荐等业务场景。
|
存储 监控 安全
132_API部署:FastAPI与现代安全架构深度解析与LLM服务化最佳实践
在大语言模型(LLM)部署的最后一公里,API接口的设计与安全性直接决定了模型服务的可用性、稳定性与用户信任度。随着2025年LLM应用的爆炸式增长,如何构建高性能、高安全性的REST API成为开发者面临的核心挑战。FastAPI作为Python生态中最受青睐的Web框架之一,凭借其卓越的性能、强大的类型安全支持和完善的文档生成能力,已成为LLM服务化部署的首选方案。
1536 3
|
安全 NoSQL API
拼多多:通过微信支付API实现社交裂变付款的技术解析
基于微信JSAPI构建社交裂变支付系统,用户发起拼单后生成预订单与分享链接,好友代付后通过回调更新订单并触发奖励。集成微信支付、异步处理、签名验签与Redis关系绑定,提升支付成功率与裂变系数,实现高效安全的闭环支付。
1200 0
|
存储 算法 API
唯品会智能分仓API技术解析:基于收货地址自动匹配最近仓库
唯品会智能分仓API通过地理编码与Haversine距离算法,自动将订单匹配至最近仓库,提升配送效率、降低成本。本文详解其技术原理、实现步骤与应用优势,助力开发者构建高效物流系统。(239字)
|
人工智能 供应链 API
淘宝API商品详情接口全解析:从基础数据到深度挖掘
淘宝API商品详情接口不仅提供基础数据,更通过深度挖掘实现从数据到洞察的跨越。开发者需结合业务场景选择合适分析方法,利用AI标签、区块链溯源等新技术,最终实现数据驱动的电商业务创新。

推荐镜像

更多
  • DNS