// Licensed to the LF AI & Data foundation under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package querynode /* #cgo pkg-config: milvus_segcore #include "segcore/plan_c.h" #include "segcore/reduce_c.h" */ import "C" import ( "fmt" ) type sliceInfo struct { sliceNQs []int64 sliceTopKs []int64 } // SearchResult contains a pointer to the search result in C++ memory type SearchResult struct { cSearchResult C.CSearchResult } // searchResultDataBlobs is the CSearchResultsDataBlobs in C++ type searchResultDataBlobs = C.CSearchResultDataBlobs // RetrieveResult contains a pointer to the retrieve result in C++ memory type RetrieveResult struct { cRetrieveResult C.CRetrieveResult } func parseSliceInfo(originNQs []int64, originTopKs []int64, nqPerSlice int64) *sliceInfo { sInfo := &sliceInfo{ sliceNQs: make([]int64, 0), sliceTopKs: make([]int64, 0), } if nqPerSlice == 0 { return sInfo } for i := 0; i < len(originNQs); i++ { for j := 0; j < int(originNQs[i]/nqPerSlice); j++ { sInfo.sliceNQs = append(sInfo.sliceNQs, nqPerSlice) sInfo.sliceTopKs = append(sInfo.sliceTopKs, originTopKs[i]) } if tailSliceSize := originNQs[i] % nqPerSlice; tailSliceSize > 0 { sInfo.sliceNQs = append(sInfo.sliceNQs, tailSliceSize) sInfo.sliceTopKs = append(sInfo.sliceTopKs, originTopKs[i]) } } return sInfo } func reduceSearchResultsAndFillData(plan *SearchPlan, searchResults []*SearchResult, numSegments int64, sliceNQs []int64, sliceTopKs []int64) (searchResultDataBlobs, error) { if plan.cSearchPlan == nil { return nil, fmt.Errorf("nil search plan") } if len(sliceNQs) == 0 { return nil, fmt.Errorf("empty slice nqs is not allowed") } if len(sliceNQs) != len(sliceTopKs) { return nil, fmt.Errorf("unaligned sliceNQs(len=%d) and sliceTopKs(len=%d)", len(sliceNQs), len(sliceTopKs)) } cSearchResults := make([]C.CSearchResult, 0) for _, res := range searchResults { if res == nil { return nil, fmt.Errorf("nil searchResult detected when reduceSearchResultsAndFillData") } cSearchResults = append(cSearchResults, res.cSearchResult) } cSearchResultPtr := (*C.CSearchResult)(&cSearchResults[0]) cNumSegments := C.int64_t(numSegments) var cSliceNQSPtr = (*C.int64_t)(&sliceNQs[0]) var cSliceTopKSPtr = (*C.int64_t)(&sliceTopKs[0]) var cNumSlices = C.int64_t(len(sliceNQs)) var cSearchResultDataBlobs searchResultDataBlobs status := C.ReduceSearchResultsAndFillData(&cSearchResultDataBlobs, plan.cSearchPlan, cSearchResultPtr, cNumSegments, cSliceNQSPtr, cSliceTopKSPtr, cNumSlices) if err := HandleCStatus(&status, "ReduceSearchResultsAndFillData failed"); err != nil { return nil, err } return cSearchResultDataBlobs, nil } func getReqSlices(nqOfReqs []int64, nqPerSlice int64) ([]int32, error) { if nqPerSlice == 0 { return nil, fmt.Errorf("zero nqPerSlice is not allowed") } slices := make([]int32, 0) for i := 0; i < len(nqOfReqs); i++ { for j := 0; j < int(nqOfReqs[i]/nqPerSlice); j++ { slices = append(slices, int32(nqPerSlice)) } if tailSliceSize := nqOfReqs[i] % nqPerSlice; tailSliceSize > 0 { slices = append(slices, int32(tailSliceSize)) } } return slices, nil } func getSearchResultDataBlob(cSearchResultDataBlobs searchResultDataBlobs, blobIndex int) ([]byte, error) { var blob C.CProto status := C.GetSearchResultDataBlob(&blob, cSearchResultDataBlobs, C.int32_t(blobIndex)) if err := HandleCStatus(&status, "marshal failed"); err != nil { return nil, err } return GetCProtoBlob(&blob), nil } func deleteSearchResultDataBlobs(cSearchResultDataBlobs searchResultDataBlobs) { C.DeleteSearchResultDataBlobs(cSearchResultDataBlobs) } func deleteSearchResults(results []*SearchResult) { if len(results) == 0 { return } for _, result := range results { if result != nil { C.DeleteSearchResult(result.cSearchResult) } } }