主キー検索
類似検索を実行する際は、対象コレクションにクエリベクトルがすでに存在している場合でも、常に 1 つ以上のクエリベクトルを指定する必要があります。検索前にベクトルを取得することを避けるには、代わりに主キーを使用できます。
概要
EC プラットフォームでは、ユーザーがキーワードを入力すると、それに一致する商品を取得できます。ユーザーが商品の詳細ページを表示すると、プラットフォームは、比較したいユーザー向けにページの下部に類似商品のリストも表示します。
レコメンデーションは、キーワードまたは現在の商品との類似度に基づいて並べ替えられます。これを実現するには、プラットフォームの開発者が、実際の類似検索の前にキーワードまたは現在の商品のベクトル表現を Milvus から取得する必要があります。そのため、プラットフォームと Milvus の間のラウンドトリップが増加し、多数の高次元浮動小数点数がネットワーク経由で送信されることになります。
アプリケーションと Milvus の間の連携ロジックを簡素化し、ラウンドトリップの回数を減らし、大量の高次元浮動小数点値をネットワーク経由で送信することを避けるには、主キー検索の使用を検討してください。
主キー検索では、クエリベクトルを指定する必要はありません。代わりに、クエリベクトルを含むエンティティの主キー(ids)を指定します。
制限事項
-
主キーを使用した検索は、BM25 関数のように VarChar フィールドから派生したスパースベクトルフィールドを除き、すべてのベクトルデータ型に適用されます。
-
フィルタ付き検索、範囲検索、グループ化検索では、クエリベクトルの代わりに主キーを使用できます。必要に応じてページネーションを有効にすることもできます。ただし、この機能はハイブリッド検索および検索イテレーターには適用されません。
-
embedding list を含む類似検索では、引き続きクエリベクトルを取得し、それらを embedding list に配置してから検索を実行する必要があります。
-
存在しない主キーや形式が正しくない主キーについては、Milvus がエラーを返します。
-
主キーとクエリベクトルは排他的です。両方を指定した場合もエラーになります。
例
以下の例では、指定したすべての Int64 ID が対象コレクションに存在することを前提としています。
主キーはフィルタリングには使用されず、ベクトルの取得にのみ使用されます。
例 1: 基本的な主キー検索
基本的な主キー検索を実行するには、クエリベクトルを主キーに置き換えるだけです。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
- Zilliz CLI
from pymilvus import MilvusClient
client = MilvusClient(
uri="YOUR_CLUSTER_ENDPOINT",
token="YOUR_CLUSTER_TOKEN"
)
res = client.search(
collection_name="my_collection",
anns_field="vector",
ids=[551, 296, 43], # a list of primary keys
limit=3
)
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
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.token("YOUR_CLUSTER_TOKEN")
.build());
List<Object> ids = Arrays.asList(551L, 296L, 43L);
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.annsField("vector")
.ids(ids)
.limit(3)
.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: "YOUR_CLUSTER_ENDPOINT",
token: "YOUR_CLUSTER_TOKEN",
});
const res = await client.search({
collection_name: "my_collection",
anns_field: "vector",
ids: [551, 296, 43], // a list of primary keys
limit: 3,
});
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: "YOUR_CLUSTER_ENDPOINT",
APIKey: "YOUR_CLUSTER_TOKEN",
})
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(
"my_collection", // collectionName
3, // limit
ids,
).WithANNSField("vector"))
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 "YOUR_CLUSTER_ENDPOINT/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
-H "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3
}'
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("my_collection")
.WithAnnsField("vector")
.WithIDs({551, 296, 43})
.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;
}
}
# Zilliz CLI
# Prerequisite: run zilliz login and select your cluster with zilliz context set.
zilliz vector search \
--collection my_collection \
--data "[]" \
--body '{
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3
}' \
--output json
例 2: 主キーを使用したフィルタ付き検索
以下の例では、color と likes が対象コレクションにスキーマ定義された 2 つのフィールドであることを前提としています。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
- Zilliz CLI
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 "YOUR_CLUSTER_ENDPOINT/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
-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;
}
}
# Zilliz CLI
# Prerequisite: run zilliz login and select your cluster with zilliz context set.
zilliz vector search \
--collection my_collection \
--data "[]" \
--body '{
"annsField": "vector",
"ids": [551, 296, 43],
"filter": "color like \\"red%\\" and likes > 50",
"outputFields": ["color", "likes"],
"limit": 3
}' \
--output json
例 3: 主キーを使用した範囲検索
- Python
- Java
- NodeJS
- Go
- cURL
- C++
- Zilliz CLI
res = client.search(
collection_name="my_collection",
ids=[551, 296, 43],
limit=3,
search_params={
"params": {
"radius": 0.4,
"range_filter": 0.6
}
}
)
ap<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 "YOUR_CLUSTER_ENDPOINT/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
-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;
}
}
# Zilliz CLI
# Prerequisite: run zilliz login and select your cluster with zilliz context set.
zilliz vector search \
--collection my_collection \
--data "[]" \
--body '{
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3,
"searchParams": {
"params": {
"radius": 0.4,
"range_filter": 0.6
}
}
}' \
--output json
例 4: 主キーを使用したグループ化検索
以下の例では、docId が対象コレクションにスキーマ定義されたフィールドであることを前提としています。
- Python
- Java
- NodeJS
- Go
- cURL
- C++
- Zilliz CLI
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 "YOUR_CLUSTER_ENDPOINT/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_CLUSTER_TOKEN" \
-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;
}
}
# Zilliz CLI
# Prerequisite: run zilliz login and select your cluster with zilliz context set.
zilliz vector search \
--collection my_collection \
--data "[]" \
--body '{
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3,
"groupingField": "docId",
"outputFields": ["docId"]
}' \
--output json