主鍵搜尋Compatible with Milvus 2.6.9+
進行相似度搜尋時,系統總是會要求您提供一個或多個查詢向量,即使這些查詢向量已經存在於目標集合中也是如此。為了避免在搜尋前先檢索向量,您可以改用主鍵來替代。
概述
在電子商務平台上,使用者可輸入關鍵字來檢索相符的商品。當使用者瀏覽商品詳情頁時,平台也會在頁面底部顯示一份相似商品清單,供使用者進行比較。
這些推薦商品會根據其與關鍵字或當前商品的相似度進行排序。為實現此功能,平台開發人員需要在實際進行相似度搜尋之前,先從 Milvus 擷取關鍵字或當前商品的向量表示,這會增加平台與 Milvus 之間的往返次數,並導致大量高維度浮點數值透過網路傳輸。
為簡化您的應用程式與 Milvus 之間的互動邏輯、減少往返次數,並避免透過網路傳輸大量高維度浮點數值,建議考慮使用主鍵搜尋。
在主鍵搜尋中,您無需提供任何查詢向量。取而代之的是,系統會要求您提供包含查詢向量的實體之主鍵(ids )。
限制與規範
使用主鍵進行的搜尋適用於所有向量資料類型,惟源自 VarChar 欄位的稀疏向量欄位除外(例如 BM25 函式中的情況)。
您可以在過濾、範圍和分組搜尋中使用主鍵代替查詢向量,並可選擇啟用分頁功能。然而,此功能不適用於混合搜尋和搜尋迭代器。
對於涉及嵌入清單的相似度搜尋,您仍需檢索查詢向量、將其排列成嵌入清單,並執行搜尋。
在 RESTful API 中,您無法使用主鍵代替查詢向量。
對於任何不存在的主鍵或格式不正確的主鍵,Milvus 會提示錯誤。
主鍵與查詢向量互斥。若同時提供兩者,亦會導致錯誤。
範例
以下範例假設所有提供的 Int64 ID 均存在於目標集合中。
主鍵不會用於篩選;它們僅用於向量檢索。
範例 1:基本主鍵搜尋
要進行基本的主鍵搜尋,只需將查詢向量替換為主鍵即可。
from pymilvus import MilvusClient
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
res = client.search(
collection_name="quick_setup",
anns_field="vector",
ids=[551, 296, 43], # a list of primary keys
limit=3,
search_params={"metric_type": "IP"}
)
for hits in res:
for hit in hits:
print(hit)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;
import io.milvus.v2.common.IndexParam;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.token("root:Milvus")
.build());
List<Object> ids = Arrays.asList(551L, 296L, 43L);
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("quick_setup")
.annsField("vector")
.ids(ids)
.limit(3)
.metricType(IndexParam.MetricType.IP)
.build());
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
System.out.println("TopK results:");
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({
address: "http://localhost:19530",
token: "root:Milvus",
});
const res = await client.search({
collection_name: "quick_setup",
anns_field: "vector",
ids: [551, 296, 43], // a list of primary keys
limit: 3,
metric_type: "IP",
});
console.log(res.results);
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v3/column"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "localhost:19530",
APIKey: "root:Milvus",
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
defer client.Close(ctx)
ids := column.NewColumnInt64("id", []int64{551, 296, 43}) // a list of primary keys
resultSets, err := client.Search(ctx, milvusclient.NewSearchByIDsOption(
"quick_setup", // collectionName
3, // limit
ids,
).WithANNSField("vector").
WithSearchParam("metric_type", "IP"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs)
fmt.Println("Scores: ", resultSet.Scores)
}
# restful
curl -X POST "http://localhost:19530/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer root:Milvus" \
-H "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3
}'
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithAnnsField("vector")
.WithIDs({551, 296, 43})
.WithLimit(3)
.WithMetricType(milvus::MetricType::IP);
milvus::SearchResponse searchResponse;
auto status = client->Search(searchRequest, searchResponse);
if (!status.IsOk()) {
std::cerr << "Search failed: " << status.Message() << std::endl;
return;
}
for (const auto& result : searchResponse.Results().Results()) {
const auto ids = result.Ids().IntIDArray();
for (size_t i = 0; i < result.Scores().size(); ++i) {
std::cout << "id=" << ids[i] << ", score=" << result.Scores()[i] << std::endl;
}
}
範例 2:使用主鍵進行篩選搜尋
以下範例假設「color」和「likes」是目標集合中兩個由模式定義的欄位。
res = client.search(
collection_name="my_collection",
ids=[551, 296, 43], #
filter='color like "red%" and likes > 50',
output_fields=["color", "likes"],
limit=3,
)
List<Object> ids = Arrays.asList(551L, 296L, 43L);
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.ids(ids)
.filter("color like \"red%\" and likes > 50")
.limit(3)
.outputFields(Arrays.asList("color", "likes"))
.build());
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
System.out.println("TopK results:");
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
const res = await client.search({
collection_name: "my_collection",
ids: [551, 296, 43],
filter: 'color like "red%" and likes > 50',
output_fields: ["id", "color", "likes"],
limit: 3,
});
console.log(res.results);
ids := column.NewColumnInt64("id", []int64{551, 296, 43})
resultSets, err := client.Search(ctx, milvusclient.NewSearchByIDsOption(
"my_collection", // collectionName
3, // limit
ids,
).WithFilter(`color like "red%" and likes > 50`).
WithOutputFields("color", "likes"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs)
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("color: ", resultSet.GetColumn("color"))
fmt.Println("likes: ", resultSet.GetColumn("likes"))
}
# restful
curl -X POST "http://localhost:19530/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer root:Milvus" \
-H "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"annsField": "vector",
"ids": [551, 296, 43],
"filter": "color like \\"red%\\" and likes > 50",
"outputFields": ["color", "likes"],
"limit": 3
}'
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("my_collection")
.WithIDs({551, 296, 43})
.WithFilter(R"(color like "red%" and likes > 50)")
.WithOutputFields({"color", "likes"})
.WithLimit(3);
milvus::SearchResponse searchResponse;
auto status = client->Search(searchRequest, searchResponse);
if (!status.IsOk()) {
std::cerr << "Search failed: " << status.Message() << std::endl;
return;
}
for (const auto& result : searchResponse.Results().Results()) {
const auto ids = result.Ids().IntIDArray();
const auto colors = result.OutputField<milvus::VarCharFieldData>("color");
const auto likes = result.OutputField<milvus::Int64FieldData>("likes");
for (size_t i = 0; i < result.Scores().size(); ++i) {
std::cout << "id=" << ids[i]
<< ", score=" << result.Scores()[i]
<< ", color=" << colors->Data()[i]
<< ", likes=" << likes->Data()[i] << std::endl;
}
}
範例 3:使用主鍵進行範圍搜尋
res = client.search(
collection_name="my_collection",
ids=[551, 296, 43],
limit=3,
search_params={
"params": {
"radius": 0.4,
"range_filter": 0.6
}
}
)
Map<String, Object> params = new HashMap<>();
params.put("radius", "0.4");
params.put("range_filter", "0.6");
List<Object> ids = Arrays.asList(551L, 296L, 43L);
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.ids(ids)
.limit(3)
.searchParams(params)
.build());
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
System.out.println("TopK results:");
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
const res = await client.search({
collection_name: "my_collection",
ids: [551, 296, 43],
limit: 3,
params: {
radius: 0.4,
range_filter: 0.6,
},
});
console.log(res.results);
annParam := index.NewCustomAnnParam()
annParam.WithRadius(0.4)
annParam.WithRangeFilter(0.6)
ids := column.NewColumnInt64("id", []int64{551, 296, 43})
resultSets, err := client.Search(ctx, milvusclient.NewSearchByIDsOption(
"my_collection", // collectionName
3, // limit
ids,
).WithANNSField("vector").
WithAnnParam(annParam))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs)
fmt.Println("Scores: ", resultSet.Scores)
}
# restful
curl -X POST "http://localhost:19530/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer root:Milvus" \
-H "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3,
"searchParams": {
"params": {
"radius": 0.4,
"range_filter": 0.6
}
}
}'
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("my_collection")
.WithAnnsField("vector")
.WithIDs({551, 296, 43})
.WithRadius(0.4)
.WithRangeFilter(0.6)
.WithLimit(3);
milvus::SearchResponse searchResponse;
auto status = client->Search(searchRequest, searchResponse);
if (!status.IsOk()) {
std::cerr << "Search failed: " << status.Message() << std::endl;
return;
}
for (const auto& result : searchResponse.Results().Results()) {
const auto ids = result.Ids().IntIDArray();
for (size_t i = 0; i < result.Scores().size(); ++i) {
std::cout << "id=" << ids[i] << ", score=" << result.Scores()[i] << std::endl;
}
}
範例 4:使用主鍵進行分組搜尋
以下範例假設「docId 」是目標集合中由模式定義的欄位。
res = client.search(
collection_name="my_collection",
ids=[551, 296, 43],
limit=3,
group_by_field="docId",
output_fields=["docId"]
)
List<Object> ids = Arrays.asList(551L, 296L, 43L);
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.ids(ids)
.limit(3)
.groupByFieldName("docId")
.outputFields(Collections.singletonList("docId"))
.build());
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
System.out.println("TopK results:");
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
const res = await client.search({
collection_name: "my_collection",
ids: [551, 296, 43],
limit: 3,
group_by_field: "docId",
output_fields: ["id", "docId"],
});
console.log(res.results);
ids := column.NewColumnInt64("id", []int64{551, 296, 43})
resultSets, err := client.Search(ctx, milvusclient.NewSearchByIDsOption(
"my_collection", // collectionName
3, // limit
ids,
).WithGroupByField("docId").
WithOutputFields("docId"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs)
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("docId: ", resultSet.GetColumn("docId"))
}
# restful
curl -X POST "http://localhost:19530/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer root:Milvus" \
-H "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3,
"groupingField": "docId",
"outputFields": ["docId"]
}'
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("my_collection")
.WithAnnsField("vector")
.WithIDs({551, 296, 43})
.WithGroupByField("docId")
.WithOutputFields({"docId"})
.WithLimit(3);
milvus::SearchResponse searchResponse;
auto status = client->Search(searchRequest, searchResponse);
if (!status.IsOk()) {
std::cerr << "Search failed: " << status.Message() << std::endl;
return;
}
for (const auto& result : searchResponse.Results().Results()) {
const auto ids = result.Ids().IntIDArray();
const auto docIds = result.OutputField<milvus::Int64FieldData>("docId");
for (size_t i = 0; i < result.Scores().size(); ++i) {
std::cout << "id=" << ids[i]
<< ", score=" << result.Scores()[i]
<< ", docId=" << docIds->Data()[i] << std::endl;
}
}