milvus2.4多向量搜索源码分析

milvus2.4多向量搜索源码分析

api入口

HybridSearch是多向量搜索的API。

func (node *Proxy) HybridSearch(ctx context.Context, request *milvuspb.HybridSearchRequest) (*milvuspb.SearchResults, error) {var err errorrsp := &milvuspb.SearchResults{Status: merr.Success(),}err2 := retry.Handle(ctx, func() (bool, error) {rsp, err = node.hybridSearch(ctx, request)if errors.Is(merr.Error(rsp.GetStatus()), merr.ErrInconsistentRequery) {return true, merr.Error(rsp.GetStatus())}return false, nil})if err2 != nil {rsp.Status = merr.Status(err2)}return rsp, err
}func (node *Proxy) hybridSearch(ctx context.Context, request *milvuspb.HybridSearchRequest) (*milvuspb.SearchResults, error) {......// 转换为milvuspb.SearchRequestnewSearchReq := convertHybridSearchToSearch(request)qt := &searchTask{ctx:       ctx,Condition: NewTaskCondition(ctx),SearchRequest: &internalpb.SearchRequest{Base: commonpbutil.NewMsgBase(commonpbutil.WithMsgType(commonpb.MsgType_Search),commonpbutil.WithSourceID(paramtable.GetNodeID()),),ReqID: paramtable.GetNodeID(),},request:             newSearchReq,tr:                  timerecord.NewTimeRecorder(method),qc:                  node.queryCoord,node:                node,lb:                  node.lbPolicy,mustUsePartitionKey: Params.ProxyCfg.MustUsePartitionKey.GetAsBool(),}guaranteeTs := request.GuaranteeTimestamplog := log.Ctx(ctx).With(zap.String("role", typeutil.ProxyRole),zap.String("db", request.DbName),zap.String("collection", request.CollectionName),zap.Any("partitions", request.PartitionNames),zap.Any("OutputFields", request.OutputFields),zap.Uint64("guarantee_timestamp", guaranteeTs),)defer func() {span := tr.ElapseSpan()if span >= paramtable.Get().ProxyCfg.SlowQuerySpanInSeconds.GetAsDuration(time.Second) {log.Info(rpcSlow(method), zap.Duration("duration", span))metrics.ProxySlowQueryCount.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10),metrics.HybridSearchLabel,).Inc()}}()log.Debug(rpcReceived(method))if err := node.sched.dqQueue.Enqueue(qt); err != nil {......}......
}

从代码中可以看出HybridSearch最终调用的和Search() API是同一个task。

milvuspb.HybridSearchRequest有一个[]*SearchRequest变量,这个存储了多个查询结构体,如果是普通的Search(),传参直接就是SearchRequest结构体,如果是HybridSearch(),就是多个查询结构体,下一步做转换。

convertHybridSearchToSearch

进入convertHybridSearchToSearch()看看是如何转换的。

func convertHybridSearchToSearch(req *milvuspb.HybridSearchRequest) *milvuspb.SearchRequest {ret := &milvuspb.SearchRequest{Base:                  req.GetBase(),DbName:                req.GetDbName(),CollectionName:        req.GetCollectionName(),PartitionNames:        req.GetPartitionNames(),OutputFields:          req.GetOutputFields(),SearchParams:          req.GetRankParams(),TravelTimestamp:       req.GetTravelTimestamp(),GuaranteeTimestamp:    req.GetGuaranteeTimestamp(),Nq:                    0,NotReturnAllMeta:      req.GetNotReturnAllMeta(),ConsistencyLevel:      req.GetConsistencyLevel(),UseDefaultConsistency: req.GetUseDefaultConsistency(),SearchByPrimaryKeys:   false,SubReqs:               nil,}for _, sub := range req.GetRequests() {subReq := &milvuspb.SubSearchRequest{Dsl:              sub.GetDsl(),PlaceholderGroup: sub.GetPlaceholderGroup(),DslType:          sub.GetDslType(),SearchParams:     sub.GetSearchParams(),Nq:               sub.GetNq(),}ret.SubReqs = append(ret.SubReqs, subReq)}return ret
}

milvuspb.SearchRequest结构体增加了一个SubReqs变量,类型是[]*SubSearchRequest。

type SubSearchRequest struct {Dsl                  stringPlaceholderGroup     []byteDslType              commonpb.DslTypeSearchParams         []*commonpb.KeyValuePairNq                   int64XXX_NoUnkeyedLiteral struct{}XXX_unrecognized     []byteXXX_sizecache        int32
}

searchTask

PreExecute()

t.SearchRequest.IsAdvanced = len(t.request.GetSubReqs()) > 0

Search()和HybridSearch()最终都是走的searchTask,如果是HybridSearch,IsAdvanced会置为true,如果是Search,IsAdvanced会置为false。

func (t *searchTask) PreExecute(ctx context.Context) error {......t.SearchRequest.IsAdvanced = len(t.request.GetSubReqs()) > 0......if t.SearchRequest.GetIsAdvanced() {if len(t.request.GetSubReqs()) > defaultMaxSearchRequest {return errors.New(fmt.Sprintf("maximum of ann search requests is %d", defaultMaxSearchRequest))}}if t.SearchRequest.GetIsAdvanced() {t.rankParams, err = parseRankParams(t.request.GetSearchParams())if err != nil {return err}}......if t.SearchRequest.GetIsAdvanced() {t.requery = len(t.request.OutputFields) > 0err = t.initAdvancedSearchRequest(ctx)} else {t.requery = len(vectorOutputFields) > 0err = t.initSearchRequest(ctx)}......
}

在initAdvancedSearchRequest填充SubReqs

Search

最终会转换为多次search。

// Search preforms search operation on shard.
func (sd *shardDelegator) Search(ctx context.Context, req *querypb.SearchRequest) ([]*internalpb.SearchResults, error) {......if req.GetReq().GetIsAdvanced() {futures := make([]*conc.Future[*internalpb.SearchResults], len(req.GetReq().GetSubReqs()))// 多次调用searchfor index, subReq := range req.GetReq().GetSubReqs() {newRequest := &internalpb.SearchRequest{Base:               req.GetReq().GetBase(),ReqID:              req.GetReq().GetReqID(),DbID:               req.GetReq().GetDbID(),CollectionID:       req.GetReq().GetCollectionID(),PartitionIDs:       subReq.GetPartitionIDs(),Dsl:                subReq.GetDsl(),PlaceholderGroup:   subReq.GetPlaceholderGroup(),DslType:            subReq.GetDslType(),SerializedExprPlan: subReq.GetSerializedExprPlan(),OutputFieldsId:     req.GetReq().GetOutputFieldsId(),MvccTimestamp:      req.GetReq().GetMvccTimestamp(),GuaranteeTimestamp: req.GetReq().GetGuaranteeTimestamp(),TimeoutTimestamp:   req.GetReq().GetTimeoutTimestamp(),Nq:                 subReq.GetNq(),Topk:               subReq.GetTopk(),MetricType:         subReq.GetMetricType(),IgnoreGrowing:      req.GetReq().GetIgnoreGrowing(),Username:           req.GetReq().GetUsername(),IsAdvanced:         false,}future := conc.Go(func() (*internalpb.SearchResults, error) {searchReq := &querypb.SearchRequest{Req:             newRequest,DmlChannels:     req.GetDmlChannels(),TotalChannelNum: req.GetTotalChannelNum(),}searchReq.Req.GuaranteeTimestamp = req.GetReq().GetGuaranteeTimestamp()searchReq.Req.TimeoutTimestamp = req.GetReq().GetTimeoutTimestamp()if searchReq.GetReq().GetMvccTimestamp() == 0 {searchReq.GetReq().MvccTimestamp = tSafe}// 执行搜索results, err := sd.search(ctx, searchReq, sealed, growing)if err != nil {return nil, err}return segments.ReduceSearchResults(ctx,results,searchReq.Req.GetNq(),searchReq.Req.GetTopk(),searchReq.Req.GetMetricType())})futures[index] = future}// 等待所有任务执行完成err = conc.AwaitAll(futures...)if err != nil {return nil, err}results := make([]*internalpb.SearchResults, len(futures))for i, future := range futures {result := future.Value()if result.GetStatus().GetErrorCode() != commonpb.ErrorCode_Success {log.Debug("delegator hybrid search failed",zap.String("reason", result.GetStatus().GetReason()))return nil, merr.Error(result.GetStatus())}results[i] = result}var ret *internalpb.SearchResultsret, err = segments.MergeToAdvancedResults(ctx, results)if err != nil {return nil, err}// 走这里return []*internalpb.SearchResults{ret}, nil}return sd.search(ctx, req, sealed, growing)
}

总结

HybridSearch会转换为多个Search搜索。

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

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

相关文章

【前端】-【前端文件操作与文件上传】-【前端接受后端传输文件指南】

目录 前端文件操作与文件上传前端接受后端传输文件指南 前端文件操作与文件上传 一、前端文件上传有两种思路: 二进制blob传输:典型案例是formData传输,相当于用formData搭载二进制的blob传给后端base64传输:转为base64传输&…

基于StatefulSet控制器在Kubernetes上部署MySQL一主多从

一、前提--StatefuSet特性 1.1 有状态的节点控制器 -- StatefulSet 及其网络状态 容器的解决方案是针对无状态应用场景的最佳实践,但对于有状态应用来说,就并非如此了。Kubernetes 用 StatefulSet 解决了有状态应用编排的问题,本文我们就来…

短视频账号没流量怎么办?三个方法提高播放量!沈阳短视频剪辑线下培训

做短视频的最怕什么? 最怕没流量啊,一旦没有流量,就吸引不到粉丝,更别提变现了! 但是,不同的短视频账号遇到没流量的情况是不同的。有的是新账号,始终没有流量;而有的是做了很久的账…

旧衣回收小程序开发:线上回收模式成为行业发展趋势

当下人们生活水平在不断提高,对衣服的要求也在增加,更新速度越来越快,闲置下来的旧衣服也在增加,为了减少浪费,旧衣回收行业受到了大众的关注。旧衣回收对我国资源回收、环境保护具有非常大的意义。 在互联网时代下&a…

第9篇:创建Nios II工程之读取Switch的值<二>

Q:上一期我们完成了Quartus硬件工程部分,本期我们创建Nios II软件工程这部分。 A:创建完BSP和Nios II Application之后,在source文件main.c中添加代码:system.h头文件中新增了Switch PIO IP的硬件信息,包括…

Windows cmd bat之特殊符号及变量

cmd 常用变量 bat批处理常用命令 %1~%9表示拖入文件(%0以外的输入文件),%0表示批处理文件本身 %0~%1字母意思基本相同,不区分大小写 ::打印当前窗口地址 echo “%cd%” %0 获取当前文件路径 %~d0 …

最新AI实景自动无人直播软件:智能讲解、一键开播,享受24小时自动专业直播体验

在现今数字化时代(ai无人直播下载:hzzxar)直播行业越来越受到人们的关注和喜爱。随着人工智能的不断发展,AI实景自动无人直播软件应运而生,为商家提供了更便捷、高效的直播方式。本文将介绍如何利用这一创新技术&#…

融知财经:期货交易原理是怎样的?期货交易有哪些特征?

期货的原理是基于对某期货品种未来走势的判断而形成对其合约的买卖交易,因此期货可以解释为买涨或买跌。买涨,即看多交易,预期某期货品种未来价格上涨而进行的买入开仓交易;买跌,即看空交易,预期某期货品种…

简站WordPress主题

简站WordPress主题是一种专为建立网站而设计的WordPress模板,它旨在简化网站建设过程,使得用户能够更容易地创建和管理自己的网站。简站WordPress主题具有以下特点: 易用性:简站WordPress主题被设计为简单易用,适合各…

redisson 使用脚本实现将一个队列的元素弹出并推入另一个队列的原子操作

脚本逻辑: 从队列1弹出元素如果存在值则推入队列2否则返回null RScript script redissonClient.getScript(); final String scriptText """local value redis.call(lpop, KEYS[1]);if value thenredis.call(rpush, KEYS[2], value);return valu…

Android广播机制简介

文章目录 Android广播机制简介广播的基本概念广播的类型广播的使用场景Android广播的优缺点优点缺点 使用Android广播的一些最佳实践: Android广播机制简介 Android广播是一种轻量级的消息传递机制,用于应用程序之间或系统与应用程序之间进行通信。它类似于订阅-发…

java多线程,synchronized

Java多线程——synchronized使用详解_synchronized用法-CSDN博客

squeeze的用法

squeeze是压缩张量的命令 import torch a torch.randn(1,3) print(a) print(a.shape) 比如说squeeze(?)括号里是啥 就是在哪个维度上删除维度为1 之后的结果 比如上上面那个里子 a是([[]]) 但是在下面那个例子中d…

【智能安防监控补光灯调光芯片方案】单节锂电降压恒流驱动芯片FP8013 最大输出3A体积小/静态功耗低/效率高/支持无频闪调光

文章目录 文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 前言 随着智能安防监控技术的不断发展,补光灯的关键性能也日益受到重视。为了提供更好的夜间监控效果,我们需要一种高效、稳定的调光芯片来驱动补光灯的亮…

《米小圈动画古诗》—“诗情画意”也不是很难嘛!

创新是一个民族的灵魂和希望,是一个国家兴旺发达的不竭动力,而学习古诗词就是丰富孩子想象力、培养学生创新精神最有效的方法。因为,诗的韵律,情绪跌宕,可以让孩子在大脑中形成一幅完整的图画。 诗歌带给人最美妙的体…

python selenium 滑动后获取动态追加的元素

在使用Python的Selenium库进行网页自动化时,如果需要滑动页面并获取动态追加的元素,可以使用以下步骤: 使用Selenium定位到滑动条元素。 执行滑动操作,可以调用execute_script方法来模拟滑动。 使用WebDriverWait和expected_co…

java垃圾收集器详解

垃圾收集器 Serial Serial收集器是Java虚拟机中最基本的垃圾回收(GC)收集器之一,主要特点是单线程的垃圾回收。虽然它只使用一个线程进行垃圾回收,但Serial收集器在单CPU环境或者小内存资源的情况下表现得相当高效。由于其单线程…

PMP考试没过怎么办?如何补考?(附复核流程)

最近刷小红书,看很多人都在晒PMP通过的成绩截图,一方面为大家开心,终于拿到了期盼已久的PMP,但同时也有宝子发挥失常没通过考试,所以这期针对没考过的宝子们,出一期复盘文章,无论结果如何&#…

今天重新使用natapp发现连不上了

我配置了natapp.ini以后还是这种情况 然后发现使用命令是可以的 直接在natapp页面中使用cmd 直接用命令 natapp -authtoken9ab6b9040a629626

智能可编程脉冲电源:为电源行业带来前所未有的创新

智能可编程脉冲电源是一种具有高精度、高可靠性、节能降耗和可编程性强等特点的电源设备。它主要由脉冲发生器、功率调节电路和控制电路等组成。脉冲发生器产生的脉冲信号可以驱动功率调节电路,实现对电源输出的电压和电流的精确控制。通过控制电路对脉冲信号进行调…