基本的なベクトル検索
ベクトル埋め込みの並び順を記録したインデックスファイルに基づき、近似最近傍(ANN)検索は、受信した検索リクエストに含まれるクエリベクトルに基づいてベクトル埋め込みのサブセットを特定し、クエリベクトルをそのサブグループ内のベクトルと比較して、最も類似した結果を返します。ANN 検索により、Zilliz Cloud は効率的な検索エクスペリエンスを提供します。このページでは、基本的な ANN 検索を実行する方法について説明します。
コレクションの作成後に新しいフィールドを追加すると、これらのフィールドを含む検索では、値を明示的に設定していないエンティティに対して、定義済みのデフォルト値または NULL が返されます。詳細については、コレクションスキーマの変更 を参照してください。
概要
ANN 検索と k 近傍法(kNN)検索は、ベクトル類似検索で一般的な手法です。kNN 検索では、検索リクエストに含まれるクエリベクトルとベクトル空間内のすべてのベクトルを比較してから、最も類似したものを特定する必要があるため、時間とリソースを大量に消費します。
kNN 検索とは異なり、ANN 検索アルゴリズムでは、ベクトル埋め込みの並び順を記録した インデックスファイルが必要です。検索リクエストを受信すると、インデックスファイルを参照して、クエリベクトルに最も類似したベクトル埋め込みを含む可能性が高いサブグループを迅速に特定できます。次に、指定した メトリクスタイプを使用してクエリベクトルとサブグループ内のベクトルとの類似性を測定し、クエリベクトルとの類似性に基づいてグループメンバーを並べ替え、上位 K 件のグループメンバーを特定できます。
ANN 検索は事前に構築されたインデックスに依存しており、検索スループット、メモリ使用量、検索の正確性は、選択するインデックスタイプによって変わる場合があります。検索パフォーマンスと正確性のバランスを取る必要があります。
学習負担を軽減するため、Zilliz Cloud は AUTOINDEX を提供しています。AUTOINDEX を使用すると、Zilliz Cloud はインデックスの構築中にコレクション内のデータ分布を分析し、その分析に基づいて最適化されたインデックスパラメーターを設定し、検索パフォーマンスと正確性のバランスを取ることができます。
AUTOINDEX と適用可能なメトリクスタイプの詳細については、AUTOINDEX の説明 および メトリクスタイプ を参照してください。このセクションでは、以下のトピックについて詳しく説明します。
単一ベクトル検索
ANN 検索において、単一ベクトル検索とは、クエリベクトルを 1 つだけ使用する検索を指します。事前に構築されたインデックスと検索リクエストに含まれるメトリクスタイプに基づき、Zilliz Cloud はクエリベクトルに最も類似した上位 K 件のベクトルを検索します。
このセクションでは、単一ベクトル検索を実行する方法について説明します。検索リクエストには 1 つのクエリベクトルが含まれ、Zilliz Cloud は内積(IP)を使用してクエリベクトルとコレクション内のベクトルとの類似性を計算し、最も類似した 3 件を返します。
データプレーンの RESTful API エンドポイントを呼び出す際は、username:password のように、対象クラスターのユーザー名とパスワードをコロンで区切ったものを認証トークンとして使用してください。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
from pymilvus import MilvusClient
client = MilvusClient(
uri="YOUR_CLUSTER_ENDPOINT",
token="YOUR_CLUSTER_TOKEN"
)
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
anns_field="vector",
data=[query_vector],
limit=3
)
for hits in res:
for hit in hits:
print(hit)
# [
# [
# {
# "id": 551,
# "distance": 0.08821295201778412,
# "entity": {}
# },
# {
# "id": 296,
# "distance": 0.0800950899720192,
# "entity": {}
# },
# {
# "id": 43,
# "distance": 0.07794742286205292,
# "entity": {}
# }
# ]
# ]
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.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
import java.util.*;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.token("YOUR_CLUSTER_TOKEN")
.build());
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.data(Collections.singletonList(queryVector))
.annsField("vector")
.topK(3)
.build();
SearchResp searchResp = client.search(searchReq);
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);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={}, score=0.95944905, id=5)
// SearchResp.SearchResult(entity={}, score=0.8689616, id=1)
// SearchResp.SearchResult(entity={}, score=0.866088, id=7)
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
milvusAddr := "YOUR_CLUSTER_ENDPOINT"
token := "YOUR_CLUSTER_TOKEN"
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: milvusAddr,
APIKey: token,
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
defer client.Close(ctx)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("vector"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
}
use milvus::v2::prelude::*;
let config = ConnectConfig::new().uri("YOUR_CLUSTER_ENDPOINT").token("YOUR_CLUSTER_TOKEN");
let client = ClientV2::new(&config).await?;
// 4. Single vector search
let query_vector = vec![0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592];
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(vec![query_vector]))
.limit(3)
.build()?,
)
.await?;
for result in response.results() {
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
#include <iostream>
#include <vector>
#include "milvus/MilvusClientV2.h"
auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("YOUR_CLUSTER_ENDPOINT", "YOUR_CLUSTER_TOKEN"));
if (!status.IsOk()) {
std::cerr << "Failed to connect: " << status.Message() << std::endl;
return;
}
std::vector<float> queryVector = {
0.35803764F, -0.60234958F, 0.18414013F, -0.26286206F, 0.90294385F
};
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithAnnsField("vector")
.WithLimit(3)
.WithMetricType(milvus::MetricType::IP)
.AddFloatVector(queryVector);
milvus::SearchResponse searchResponse;
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;
}
}
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "YOUR_CLUSTER_ENDPOINT";
const token = "YOUR_CLUSTER_TOKEN";
const client = new MilvusClient({address, token});
// 4. Single vector search
var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
res = await client.search({
collection_name: "quick_setup",
data: query_vector,
limit: 3, // The number of results to return
})
console.log(res.results)
// [
// { score: 0.08821295201778412, id: '551' },
// { score: 0.0800950899720192, id: '296' },
// { score: 0.07794742286205292, id: '43' }
// ]
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"annsField": "vector",
"limit": 3
}'
# {
# "code": 0,
# "data": [
# {
# "distance": 0.08821295201778412,
# "id": 551
# },
# {
# "distance": 0.0800950899720192,
# "id": 296
# },
# {
# "distance": 0.07794742286205292,
# "id": 43
# }
# ]
# }
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"limit": 3
}' \
--output json
Milvus は、クエリベクトルに対する類似度スコアの降順で検索結果をランク付けします。類似度スコアはクエリベクトルまでの距離とも呼ばれ、その値の範囲は使用するメトリクスタイプによって異なります。
以下の表に、適用可能なメトリクスタイプと対応する距離範囲を示します。
| メトリクスタイプ | 特性 | 距離範囲 |
|---|---|---|
L2 | 値が小さいほど類似性が高くなります。 | [0, ∞) |
IP | 値が大きいほど類似性が高くなります。 | [-1, 1] |
COSINE | 値が大きいほど類似性が高くなります。 | [-1, 1] |
JACCARD | 値が小さいほど類似性が高くなります。 | [0, 1] |
HAMMING | 値が小さいほど類似性が高くなります。 | [0, dim(vector)] |
一括ベクトル検索
同様に、検索リクエストに複数のクエリベクトルを含めることもできます。Zilliz Cloud は各クエリベクトルに対して ANN 検索を並行して実行し、2 セットの結果を返します。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
# 7. Search with multiple vectors
# 7.1. Prepare query vectors
query_vectors = [
[0.041732933, 0.013779674, -0.027564144, -0.013061441, 0.009748648],
[0.0039737443, 0.003020432, -0.0006188639, 0.03913546, -0.00089768134]
]
# 7.2. Start search
res = client.search(
collection_name="quick_setup",
data=query_vectors,
limit=3,
)
for hits in res:
print("TopK results:")
for hit in hits:
print(hit)
# Output
#
# [
# [
# {
# "id": 551,
# "distance": 0.08821295201778412,
# "entity": {}
# },
# {
# "id": 296,
# "distance": 0.0800950899720192,
# "entity": {}
# },
# {
# "id": 43,
# "distance": 0.07794742286205292,
# "entity": {}
# }
# ],
# [
# {
# "id": 730,
# "distance": 0.04431751370429993,
# "entity": {}
# },
# {
# "id": 333,
# "distance": 0.04231833666563034,
# "entity": {}
# },
# {
# "id": 232,
# "distance": 0.04221535101532936,
# "entity": {}
# }
# ]
# ]
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.BaseVector;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
List<BaseVector> queryVectors = Arrays.asList(
new FloatVec(new float[]{0.041732933f, 0.013779674f, -0.027564144f, -0.013061441f, 0.009748648f}),
new FloatVec(new float[]{0.0039737443f, 0.003020432f, -0.0006188639f, 0.03913546f, -0.00089768134f})
);
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.data(queryVectors)
.topK(3)
.build();
SearchResp searchResp = client.search(searchReq);
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);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={}, score=0.49548206, id=1)
// SearchResp.SearchResult(entity={}, score=0.320147, id=3)
// SearchResp.SearchResult(entity={}, score=0.107413776, id=6)
// TopK results:
// SearchResp.SearchResult(entity={}, score=0.5678123, id=6)
// SearchResp.SearchResult(entity={}, score=0.32368967, id=2)
// SearchResp.SearchResult(entity={}, score=0.24108477, id=3)
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVectors := []entity.Vector{
entity.FloatVector([]float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}),
entity.FloatVector([]float32{0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104}),
}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
queryVectors,
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("vector"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
}
use milvus::v2::prelude::*;
// 7. Search with multiple vectors
// 7.1. Prepare query vectors
let query_vectors = vec![
vec![0.041732933, 0.013779674, -0.027564144, -0.013061441, 0.009748648],
vec![0.0039737443, 0.003020432, -0.0006188639, 0.03913546, -0.00089768134],
];
// 7.2. Start search
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(query_vectors))
.limit(3)
.build()?,
)
.await?;
for result in response.results() {
println!("TopK results:");
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
std::vector<std::vector<float>> queryVectors = {
{0.041732933F, 0.013779674F, -0.027564144F, -0.013061441F, 0.009748648F},
{0.0039737443F, 0.003020432F, -0.0006188639F, 0.03913546F, -0.00089768134F},
};
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithAnnsField("vector")
.WithLimit(3)
.WithFloatVectors(std::move(queryVectors));
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()) {
std::cout << "TopK results:" << std::endl;
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;
}
}
// 7. Search with multiple vectors
const query_vectors = [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]
]
res = await client.search({
collection_name: "quick_setup",
vectors: query_vectors,
limit: 3,
})
console.log(res.results)
// Output
//
// [
// [
// { score: 0.08821295201778412, id: '551' },
// { score: 0.0800950899720192, id: '296' },
// { score: 0.07794742286205292, id: '43' }
// ],
// [
// { score: 0.04431751370429993, id: '730' },
// { score: 0.04231833666563034, id: '333' },
// { score: 0.04221535101532936, id: '232' },
// ]
// ]
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]
],
"annsField": "vector",
"limit": 3
}'
# {
# "code": 0,
# "data": [
# [
# {
# "distance": 0.08821295201778412,
# "id": 551
# },
# {
# "distance": 0.0800950899720192,
# "id": 296
# },
# {
# "distance": 0.07794742286205292,
# "id": 43
# }
# ],
# [
# {
# "distance": 0.04431751370429993,
# "id": 730
# },
# {
# "distance": 0.04231833666563034,
# "id": 333
# },
# {
# "distance": 0.04221535101532936,
# "id": 232
# }
# ]
# ],
# "topks":[3]
# }
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.041732933,
0.013779674,
-0.027564144,
-0.013061441,
0.009748648
],
[
0.0039737443,
0.003020432,
-0.0006188639,
0.03913546,
-0.00089768134
]
],
"annsField": "vector",
"limit": 3
}' \
--output json
主キー検索
クエリベクトルを設定する代わりに、クエリベクトルが対象コレクションにすでに存在する場合は、主キーを使用できます。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
res = client.search(
collection_name="quick_setup",
anns_field="vector",
ids=[551, 296, 43],
limit=3
)
for hits in res:
for hit in hits:
print(hit)
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;
import java.util.Arrays;
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.annsField("vector")
.ids(Arrays.<Object>asList(551L, 296L, 43L))
.limit(3)
.metricType(IndexParam.MetricType.IP)
.build();
SearchResp searchResp = client.search(searchReq);
System.out.println(searchResp.getSearchResults());
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/column"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryIDs := column.NewColumnInt64("id", []int64{551, 296, 43})
resultSets, err := client.Search(ctx, milvusclient.NewSearchByIDsOption(
"quick_setup", // collectionName
3, // limit
queryIDs,
).WithANNSField("vector").
WithSearchParam("metric_type", "IP"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
}
use milvus::v2::prelude::*;
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.ids(Ids::Int64(vec![551, 296, 43]))
.limit(3)
.build()?,
)
.await?;
for result in response.results() {
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
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;
}
}
res = await client.search({
collection_name: "quick_setup",
anns_field: "vector",
ids: [551, 296, 43],
limit: 3,
metric_type: "IP",
})
console.log(res.results)
# 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": "quick_setup",
"annsField": "vector",
"ids": [551, 296, 43],
"limit": 3
}'
zilliz vector search \
--collection quick_setup \
--data '[]' \
--body '{
"ids": [
1,
2,
3
],
"annsField": "vector",
"limit": 3
}' \
--output json
パーティション内の ANN 検索
コレクション内に複数のパーティションを作成し、検索範囲を特定の数のパーティションに絞り込めるものとします。その場合は、検索リクエストに対象のパーティション名を含めることで、検索範囲を指定したパーティション内に制限できます。検索対象のパーティション数を減らすと、検索パフォーマンスが向上します。
以下のコードスニペットでは、コレクション内に PartitionA という名前のパーティションがあることを前提としています。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
partition_names=["partitionA"],
data=[query_vector],
limit=3,
)
for hits in res:
print("TopK results:")
for hit in hits:
print(hit)
# [
# [
# {
# "id": 551,
# "distance": 0.08821295201778412,
# "entity": {}
# },
# {
# "id": 296,
# "distance": 0.0800950899720192,
# "entity": {}
# },
# {
# "id": 43,
# "distance": 0.07794742286205292,
# "entity": {}
# }
# ]
# ]
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.partitionNames(Collections.singletonList("partitionA"))
.data(Collections.singletonList(queryVector))
.topK(3)
.build();
SearchResp searchResp = client.search(searchReq);
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);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={}, score=0.6395302, id=13)
// SearchResp.SearchResult(entity={}, score=0.5408028, id=12)
// SearchResp.SearchResult(entity={}, score=0.49696884, id=17)
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
WithPartitions("partitionA").
WithANNSField("vector"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
}
use milvus::v2::prelude::*;
// 4. Single vector search
let query_vector = vec![0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592];
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(vec![query_vector]))
.partition_names(["partitionA"])
.limit(3)
.build()?,
)
.await?;
for result in response.results() {
println!("TopK results:");
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithAnnsField("vector")
.AddPartitionName("partitionA")
.WithLimit(3)
.AddFloatVector(queryVector);
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. Single vector search
var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
res = await client.search({
collection_name: "quick_setup",
partition_names: ["partitionA"],
data: query_vector,
limit: 3, // The number of results to return
})
console.log(res.results)
// [
// { score: 0.08821295201778412, id: '551' },
// { score: 0.0800950899720192, id: '296' },
// { score: 0.07794742286205292, id: '43' }
// ]
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"partitionNames": ["partitionA"],
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"annsField": "vector",
"limit": 3
}'
# {
# "code": 0,
# "data": [
# {
# "distance": 0.08821295201778412,
# "id": 551
# },
# {
# "distance": 0.0800950899720192,
# "id": 296
# },
# {
# "distance": 0.07794742286205292,
# "id": 43
# }
# ],
# "topks":[3]
# }
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"partitionNames": [
"partitionA"
],
"limit": 3
}' \
--output json
出力フィールドを使用する
検索結果では、Zilliz Cloud はデフォルトで、上位 K 件のベクトル埋め込みを含むエンティティの主フィールド値と類似度の距離/scores を含めます。対象フィールドの名前(ベクトルフィールドとスカラーフィールドの両方)を出力フィールドとして検索リクエストに含めることで、検索結果にこれらのエンティティの他のフィールドの値を含めることができます。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=3, # The number of results to return
search_params={
"offset": 10 # The records to skip
}
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.data(Collections.singletonList(queryVector))
.topK(3)
.outputFields(Collections.singletonList("color"))
.build();
SearchResp searchResp = client.search(searchReq);
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);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={color=black_9955}, score=0.95944905, id=5)
// SearchResp.SearchResult(entity={color=red_7319}, score=0.8689616, id=1)
// SearchResp.SearchResult(entity={color=white_5015}, score=0.866088, id=7)
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("vector").
WithOutputFields("color"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("color: ", resultSet.GetColumn("color").FieldData().GetScalars())
}
use milvus::v2::prelude::*;
// 4. Single vector search
let query_vector = vec![0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592];
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(vec![query_vector]))
.output_fields(["color"])
.limit(3)
.build()?,
)
.await?;
for result in response.results() {
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithAnnsField("vector")
.WithLimit(3)
.WithMetricType(milvus::MetricType::IP)
.AddOutputField("color")
.AddFloatVector(queryVector);
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");
for (size_t i = 0; i < result.Scores().size(); ++i) {
std::cout << "id=" << ids[i] << ", score=" << result.Scores()[i]
<< ", color=" << colors->Data()[i] << std::endl;
}
}
// 4. Single vector search
var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
res = await client.search({
collection_name: "quick_setup",
data: query_vector,
limit: 3, // The number of results to return
output_fields: ["color"]
})
console.log(res.results)
// [
// { score: 0.08821295201778412, id: '551', entity: {"color": "orange_6781"}},
// { score: 0.0800950899720192, id: '296' entity: {"color": "red_4794"}},
// { score: 0.07794742286205292, id: '43' entity: {"color": "grey_8510"}}
// ]
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"annsField": "vector",
"limit": 3,
"outputFields": ["color"]
}'
# {
# "code": 0,
# "data": [
# {
# "distance": 0.08821295201778412,
# "id": 551,
# "color": "orange_6781"
# },
# {
# "distance": 0.0800950899720192,
# "id": 296,
# "color": "red_4794"
# },
# {
# "distance": 0.07794742286205292,
# "id": 43
# "color": "grey_8510"
# }
# ],
# "topks":[3]
# }
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"outputFields": [
"color"
],
"limit": 3
}' \
--output json
スカラーフィールドで検索結果を並べ替える | ONDEMAND
デフォルトでは、Zilliz Cloud はクエリベクトルに対する類似度スコアで検索結果を並べ替えます。返されるエンティティをスカラーフィールドの順序に従わせたい場合は、order_by_fields を検索リクエストに追加します。
order_by_fields の各項目では、スカラーフィールドと並べ替え方向を指定します。昇順には "asc"、降順には "desc" を使用します。order を省略した場合、Zilliz Cloud はそのフィールドを昇順で並べ替えます。
以下の例では、検索結果を price の低い順から高い順に並べ替えます。レスポンスでフィールド値を確認したい場合は、並べ替えフィールドを output_fields に含めてください。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
res = client.search(
collection_name="product_catalog",
data=query_vectors,
anns_field="embedding",
limit=20,
output_fields=["id", "price", "rating", "category"],
order_by_fields=[
{"field": "price", "order": "asc"}
],
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.aggregation.AggDirection;
import io.milvus.v2.service.vector.request.aggregation.OrderByField;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
import java.util.Arrays;
import java.util.Collections;
FloatVec queryVector = new FloatVec(new float[]{0.35803764f, -0.6023496f, 0.18414013f, -0.26286206f, 0.90294385f});
SearchReq searchReq = SearchReq.builder()
.collectionName("product_catalog")
.data(Collections.singletonList(queryVector))
.annsField("embedding")
.limit(20)
.outputFields(Arrays.asList("id", "price", "rating", "category"))
.orderByFields(Collections.singletonList(
OrderByField.builder()
.fieldName("price")
.direction(AggDirection.ASC)
.build()
))
.build();
SearchResp searchResp = client.search(searchReq);
System.out.println(searchResp.getSearchResults());
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.35803764, -0.6023496, 0.18414013, -0.26286206, 0.90294385}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"product_catalog", // collectionName
20, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("embedding").
WithOutputFields("id", "price", "rating", "category").
WithSearchParam("order_by_fields", "price:asc"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Prices: ", resultSet.GetColumn("price").FieldData().GetScalars())
}
use milvus::v2::prelude::*;
let query_vector = vec![0.35803764, -0.6023496, 0.18414013, -0.26286206, 0.90294385];
let response = client
.search(
SearchRequest::builder()
.collection_name("product_catalog")
.vector_field("embedding")
.vectors(SearchVectors::Float(vec![query_vector]))
.limit(20)
.output_fields(["id", "price", "rating", "category"])
.order_by_fields(vec![OrderByField::new().field_name("price").direction(AggDirection::Asc)])
.build()?,
)
.await?;
for result in response.results() {
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("product_catalog")
.WithAnnsField("embedding")
.WithLimit(20)
.WithOutputFields({"id", "price", "rating", "category"})
.AddOrderByField(milvus::OrderByField(
"price", milvus::AggregationDirection::ASC))
.AddFloatVector(queryVector);
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 prices = result.OutputField<milvus::Int64FieldData>("price");
for (size_t i = 0; i < result.GetRowCount(); ++i) {
std::cout << "id=" << ids[i] << ", price=" << prices->Data()[i] << std::endl;
}
}
res = await client.search({
collection_name: "product_catalog",
data: query_vector,
anns_field: "embedding",
limit: 20,
output_fields: ["id", "price", "rating", "category"],
order_by_fields: [
{ field: "price", order: "asc" }
],
})
console.log(res.results)
# restful
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"outputFields": [
"price"
],
"orderByFields": [
"price:asc"
],
"limit": 3
}' \
--output json
複数のスカラーフィールドで並べ替えることもできます。Zilliz Cloud は指定した順序でフィールドを適用します。以下の例では、Zilliz Cloud は結果を price の昇順で並べ替えます。price が同じエンティティについては、続いて rating の降順で並べ替え、Zilliz Cloud は該当する結果を返します。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
res = client.search(
collection_name="product_catalog",
data=query_vectors,
anns_field="embedding",
limit=20,
output_fields=["id", "price", "rating", "category"],
order_by_fields=[
{"field": "price", "order": "asc"},
{"field": "rating", "order": "desc"},
],
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.aggregation.AggDirection;
import io.milvus.v2.service.vector.request.aggregation.OrderByField;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
import java.util.Arrays;
import java.util.Collections;
FloatVec queryVector = new FloatVec(new float[]{0.35803764f, -0.6023496f, 0.18414013f, -0.26286206f, 0.90294385f});
SearchReq searchReq = SearchReq.builder()
.collectionName("product_catalog")
.data(Collections.singletonList(queryVector))
.annsField("embedding")
.limit(20)
.outputFields(Arrays.asList("id", "price", "rating", "category"))
.orderByFields(Arrays.asList(
OrderByField.builder()
.fieldName("price")
.direction(AggDirection.ASC)
.build(),
OrderByField.builder()
.fieldName("rating")
.direction(AggDirection.DESC)
.build()
))
.build();
SearchResp searchResp = client.search(searchReq);
System.out.println(searchResp.getSearchResults());
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.35803764, -0.6023496, 0.18414013, -0.26286206, 0.90294385}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"product_catalog", // collectionName
20, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("embedding").
WithOutputFields("id", "price", "rating", "category").
WithSearchParam("order_by_fields", "price:asc,rating:desc"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Prices: ", resultSet.GetColumn("price").FieldData().GetScalars())
fmt.Println("Ratings: ", resultSet.GetColumn("rating").FieldData().GetScalars())
}
use milvus::v2::prelude::*;
let query_vector = vec![0.35803764, -0.6023496, 0.18414013, -0.26286206, 0.90294385];
let response = client
.search(
SearchRequest::builder()
.collection_name("product_catalog")
.vector_field("embedding")
.vectors(SearchVectors::Float(vec![query_vector]))
.limit(20)
.output_fields(["id", "price", "rating", "category"])
.order_by_fields(vec![
OrderByField::new().field_name("price").direction(AggDirection::Asc),
OrderByField::new().field_name("rating").direction(AggDirection::Desc),
])
.build()?,
)
.await?;
for result in response.results() {
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("product_catalog")
.WithAnnsField("embedding")
.WithLimit(20)
.WithOutputFields({"id", "price", "rating", "category"})
.WithOrderByFields({
milvus::OrderByField("price", milvus::AggregationDirection::ASC),
milvus::OrderByField("rating", milvus::AggregationDirection::DESC),
})
.AddFloatVector(queryVector);
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 prices = result.OutputField<milvus::Int64FieldData>("price");
const auto ratings = result.OutputField<milvus::DoubleFieldData>("rating");
for (size_t i = 0; i < result.GetRowCount(); ++i) {
std::cout << "id=" << ids[i] << ", price=" << prices->Data()[i]
<< ", rating=" << ratings->Data()[i] << std::endl;
}
}
res = await client.search({
collection_name: "product_catalog",
data: query_vector,
anns_field: "embedding",
limit: 20,
output_fields: ["id", "price", "rating", "category"],
order_by_fields: [
{ field: "price", order: "asc" },
{ field: "rating", order: "desc" },
],
})
console.log(res.results)
# restful
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"outputFields": [
"price",
"rating"
],
"orderByFields": [
"price:asc",
"rating:desc"
],
"limit": 3
}' \
--output json
指定したすべての order-by フィールドで値が同じエンティティについては、Zilliz Cloud は元の類似度スコアの順序を維持します。
limit と offset を使用する
検索リクエストに含まれる limit パラメーターが、検索結果に含めるエンティティ数を決定することにお気づきかもしれません。このパラメーターは 1 回の検索で返すエンティティの最大数を指定し、通常 上位 K 件 と呼ばれます。
ページ分割されたクエリを実行したい場合は、ループを使用して複数の検索リクエストを送信し、各クエリリクエストに Limit パラメーターと Offset パラメーターを含めることができます。具体的には、Limit パラメーターを現在のクエリ結果に含めたいエンティティ数に設定し、Offset をすでに返されたエンティティの合計数に設定します。
以下の表は、一度に 100 件のエンティティを返す場合に、ページ分割されたクエリで Limit パラメーターと Offset パラメーターを設定する方法をまとめたものです。
| クエリ | クエリごとに返すエンティティ数 | すでに返されたエンティティの合計数 |
|---|---|---|
| 1 回目のクエリ | 100 | 0 |
| 2 回目のクエリ | 100 | 100 |
| 3 回目のクエリ | 100 | 200 |
| n 回目のクエリ | 100 | 100 x (n-1) |
単一の ANN 検索における limit と offset の合計は 16,384 未満にする必要があることに注意してください。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=3, # The number of results to return
search_params={
"offset": 10 # The records to skip
}
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.data(Collections.singletonList(queryVector))
.topK(3)
.offset(10)
.build();
SearchResp searchResp = client.search(searchReq);
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);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={}, score=0.24120237, id=16)
// SearchResp.SearchResult(entity={}, score=0.22559784, id=9)
// SearchResp.SearchResult(entity={}, score=-0.09906838, id=2)
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("vector").
WithOffset(10))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
}
use milvus::v2::prelude::*;
// 4. Single vector search
let query_vector = vec![0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592];
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(vec![query_vector]))
.limit(3)
.offset(10)
.build()?,
)
.await?;
for result in response.results() {
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithAnnsField("vector")
.WithLimit(3)
.WithOffset(10)
.AddFloatVector(queryVector);
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. Single vector search
var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
res = await client.search({
collection_name: "quick_setup",
data: query_vector,
limit: 3, // The number of results to return,
offset: 10 // The record to skip.
})
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"annsField": "vector",
"limit": 3,
"offset": 10
}'
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"limit": 3,
"offset": 3
}' \
--output json
level を使用する
ANN 検索を最適化するため、Zilliz Cloud は、簡素化された検索最適化によって検索精度を制御する level という名前のパラメーターを提供しています。
このパラメーターは 1 から 10 の範囲で、デフォルトは 1 です。値を大きくすると検索の再現率は向上しますが、検索パフォーマンスは低下します。一般的なケースでは、デフォルト値で最大 90% の再現率が得られます。必要に応じて値を大きくできます。
level パラメーターはまだ Public Preview です。5 より大きい値に設定できない場合、クラスターがこの機能を完全にはサポートしていない可能性があります。回避策として、代わりに 1 から 5 の範囲内の値を設定するか、Zilliz Cloud サポート にお問い合わせください。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=3, # The number of results to return
search_params={
"params": {
"level": 10 # The precision control
}
}
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
Map<String, Object> params = new HashMap<>();
params.put("level", 10);
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.data(Collections.singletonList(queryVector))
.topK(3)
.searchParams(params)
.build();
SearchResp searchResp = client.search(searchReq);
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);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={}, score=0.95944905, id=5)
// SearchResp.SearchResult(entity={}, score=0.8689616, id=1)
// SearchResp.SearchResult(entity={}, score=0.866088, id=7)
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("vector").
WithSearchParam("level", "10"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
}
use milvus::v2::prelude::*;
use std::collections::HashMap;
// 4. Single vector search
let query_vector = vec![0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592];
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(vec![query_vector]))
.limit(3)
.extra_params(HashMap::from([("level".into(), "10".into())]))
.build()?,
)
.await?;
for result in response.results() {
println!("TopK results:");
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
std::vector<float> query_vector = {0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592};
auto request = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithLimit(3)
.WithAnnsField("vector")
.AddFloatVector(query_vector)
.AddExtraParam("level", "10");
milvus::SearchResponse response;
auto status = client->Search(request, response);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
for (auto& result : response.Results().Results()) {
std::cout << "TopK results:" << std::endl;
milvus::EntityRows output_rows;
status = result.OutputRows(output_rows);
for (const auto& row : output_rows) {
std::cout << "\t" << row << std::endl;
}
}
// 4. Single vector search
var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
res = await client.search({
collection_name: "quick_setup",
data: query_vector,
limit: 3, // The number of results to return,
params: {
"level": 10 // The precision control
}
})
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]
],
"annsField": "vector",
"limit": 3,
"searchParams":{
"params":{
"level":10
}
}
}'
# {"code":0,"cost":0,"data":[{"distance":1,"id":0},{"distance":0.6290165,"id":1},{"distance":0.5975797,"id":4},{"distance":0.9999999,"id":1},{"distance":0.7408552,"id":7},{"distance":0.6290165,"id":0}],"topks":[3]}
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"searchParams": {
"level": 10
},
"limit": 3
}' \
--output json
再現率を取得する
level パラメーターを調整する際に enable_recall_calculation を true に設定すると、異なる level 値での検索の精度を評価できます。
enable_recall_calculation パラメーターはまだ Public Preview であり、互換性の問題により使用できない場合があります。サポートが必要な場合は、Zilliz Cloud サポート までお問い合わせください。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
# 4. Single vector search
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="quick_setup",
data=[query_vector],
limit=3, # The number of results to return
search_params={
"params": {
"level": 10, # The precision control
"enable_recall_calculation": True # Ask to return recall rate
}
}
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
Map<String, Object> params = new HashMap<>();
params.put("level", 10);
params.put("enable_recall_calculation", true);
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.data(Collections.singletonList(queryVector))
.topK(3)
.searchParams(params)
.build();
SearchResp searchResp = client.search(searchReq);
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);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={}, score=0.95944905, id=5)
// SearchResp.SearchResult(entity={}, score=0.8689616, id=1)
// SearchResp.SearchResult(entity={}, score=0.866088, id=7)
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("vector").
WithSearchParam("enable_recall_calculation", "true"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
}
use milvus::v2::prelude::*;
use std::collections::HashMap;
// 4. Single vector search
let query_vector = vec![0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592];
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(vec![query_vector]))
.limit(3)
.extra_params(HashMap::from([
("level".into(), "10".into()),
("enable_recall_calculation".into(), "true".into()),
]))
.build()?,
)
.await?;
for result in response.results() {
println!("TopK results:");
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
std::vector<float> query_vector = {0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592};
auto request = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithLimit(3)
.WithAnnsField("vector")
.AddFloatVector(query_vector)
.AddExtraParam("level", "10")
.AddExtraParam("enable_recall_calculation", "true");
milvus::SearchResponse response;
auto status = client->Search(request, response);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
for (auto& result : response.Results().Results()) {
std::cout << "TopK results:" << std::endl;
milvus::EntityRows output_rows;
status = result.OutputRows(output_rows);
for (const auto& row : output_rows) {
std::cout << "\t" << row << std::endl;
}
}
// 4. Single vector search
var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
res = await client.search({
collection_name: "quick_setup",
data: query_vector,
limit: 3, // The number of results to return,
params: {
"level": 10, // The precision control
"enable_recall_calculation": true // Ask to return recall rate
}
})
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]
],
"annsField": "vector",
"limit": 3,
"searchParams":{
"params":{
"level":10,
"enable_recall_calculation": true
}
}
}'
# {"code":0,"cost":0,"data":[{"distance":1,"id":0},{"distance":0.6290165,"id":1},{"distance":0.5975797,"id":4},{"distance":0.9999999,"id":1},{"distance":0.7408552,"id":7},{"distance":0.6290165,"id":0}],"topks":[3]}
# Zilliz CLI
# Recall-rate metadata is not currently exposed by the CLI.
検索のタイムゾーンを一時的に設定する
コレクションに TIMESTAMPTZ フィールドがある場合、検索呼び出しで timezone パラメーターを設定することで、単一の操作に対してデータベースまたはコレクションのデフォルトタイムゾーンを一時的に上書きできます。これにより、操作中の TIMESTAMPTZ 値の表示方法と比較方法が制御されます。
timezone の値は、たとえば Asia/Shanghai, America/Chicago, または UTC など、有効な IANA タイムゾーン識別子 である必要があります。TIMESTAMPTZ フィールドの使用方法の詳細については、TIMESTAMPTZ フィールド を参照してください。
以下の例は、検索操作のタイムゾーンを一時的に設定する方法を示しています。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- cURL
- Zilliz CLI
res = client.search(
collection_name="quick_setup",
anns_field="vector",
data=[query_vector],
limit=3,
timezone="America/Havana",
)
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
import java.util.Collections;
FloatVec queryVector = new FloatVec(new float[]{0.35803764f, -0.6023496f, 0.18414013f, -0.26286206f, 0.90294385f});
SearchReq searchReq = SearchReq.builder()
.collectionName("quick_setup")
.annsField("vector")
.data(Collections.singletonList(queryVector))
.limit(3)
.metricType(IndexParam.MetricType.IP)
.timezone("America/Havana")
.build();
SearchResp searchResp = client.search(searchReq);
System.out.println(searchResp.getSearchResults());
import (
"fmt"
"github.com/milvus-io/milvus/client/v3/entity"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
queryVector := []float32{0.35803764, -0.6023496, 0.18414013, -0.26286206, 0.90294385}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"quick_setup", // collectionName
3, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("vector").
WithSearchParam("metric_type", "IP").
WithOutputFields("event_time").
WithSearchParam("timezone", "America/Havana"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Event times: ", resultSet.GetColumn("event_time").FieldData().GetScalars())
}
use milvus::v2::prelude::*;
let query_vector = vec![0.35803764, -0.6023496, 0.18414013, -0.26286206, 0.90294385];
let response = client
.search(
SearchRequest::builder()
.collection_name("quick_setup")
.vector_field("vector")
.vectors(SearchVectors::Float(vec![query_vector]))
.limit(3)
.timezone("America/Havana")
.build()?,
)
.await?;
for result in response.results() {
for row in result.rows()? {
println!("{:?}", row.to_entity_row()?);
}
}
auto searchRequest = milvus::SearchRequest()
.WithCollectionName("quick_setup")
.WithAnnsField("vector")
.WithLimit(3)
.WithMetricType(milvus::MetricType::IP)
.AddOutputField("event_time")
.WithTimezone("America/Havana")
.AddFloatVector(queryVector);
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 eventTimes = result.OutputField<milvus::TimestamptzFieldData>("event_time");
for (size_t i = 0; i < result.GetRowCount(); ++i) {
std::cout << "id=" << ids[i] << ", event_time=" << eventTimes->Data()[i] << std::endl;
}
}
res = await client.search({
collection_name: "quick_setup",
anns_field: "vector",
data: query_vector,
limit: 3,
metric_type: "IP",
params: { timezone: "America/Havana" },
})
console.log(res.results)
# restful
export QUERY_VECTOR='[0.1, 0.2, 0.3, 0.4]'
curl -X POST "YOUR_CLUSTER_ENDPOINT/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Request-Timeout: 10" \
-d '{
"collectionName": "quick_setup",
"annsField": "vector",
"data": ['"$QUERY_VECTOR"'],
"limit": 3,
"searchParams": {
"timezone": "America/Havana"
}
}'
zilliz vector search \
--collection quick_setup \
--body '{
"data": [
[
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592
]
],
"annsField": "vector",
"outputFields": [
"event_time"
],
"timezone": "America/Havana",
"limit": 3
}' \
--output json
ANN 検索を強化する
AUTOINDEX は ANN 検索の学習曲線を大幅に緩やかにします。ただし、上位 K 件が増えるにつれて、検索結果が常に正確であるとは限りません。検索範囲の縮小、検索結果の関連性の向上、検索結果の多様化により、Zilliz Cloud は以下の検索拡張機能を実現します。
-
フィルター検索
検索リクエストにフィルター条件を含めることで、Zilliz Cloud は ANN 検索を実行する前にメタデータフィルタリングを実行し、検索範囲をコレクション全体から指定したフィルター条件に一致するエンティティのみに縮小できます。
メタデータフィルタリングとフィルター条件の詳細については、フィルター検索 および フィルタリングの説明 を参照してください。
-
範囲検索
返されるエンティティの距離またはスコアを特定の範囲内に制限することで、検索結果の関連性を向上できます。Zilliz Cloud では、範囲検索は、クエリベクトルに最も類似したベクトル埋め込みを中心とする 2 つの同心円を描くことを伴います。検索リクエストで両方の円の半径を指定すると、Zilliz Cloud は外側の円の内側かつ内側の円の外側にあるすべてのベクトル埋め込みを返します。
範囲検索の詳細については、範囲検索 を参照してください。
-
グループ化検索
返されるエンティティが特定のフィールドで同じ値を持つ場合、検索結果はベクトル空間内のすべてのベクトル埋め込みの分布を表していない可能性があります。検索結果を多様化するには、グループ化検索の使用を検討してください。
グループ化検索の詳細については、グループ化検索 を参照してください。
-
ハイブリッド検索
コレクションは複数のベクトルフィールドを含み、異なる埋め込みモデルを使用して生成されたベクトル埋め込みを保存できます。これにより、ハイブリッド検索を使用してこれらのベクトルフィールドからの検索結果を再ランク付けし、再現率を向上できます。
ハイブリッド検索の詳細については、ハイブリッド検索 を参照してください。
コレクションで許可されるベクトルフィールド数の制限の詳細については、Zilliz Cloud の制限 を参照してください。
-
検索イテレーター
1 回の ANN 検索では最大 16,384 件のエンティティが返されます。1 回の検索でより多くのエンティティを返す必要がある場合は、検索イテレーターの使用を検討してください。
検索イテレーターの詳細については、検索イテレーター を参照してください。
-
全文検索
全文検索は、テキストデータセット内で特定の用語やフレーズを含むドキュメントを取得し、関連性に基づいて結果をランク付けする機能です。この機能は、正確な用語を見落とす可能性があるセマンティック検索の制限を克服し、最も正確で文脈に関連した結果を受け取れるようにします。さらに、生のテキスト入力を受け付け、テキストデータを自動的にスパース埋め込みに変換するため、ベクトル埋め込みを手動で生成する必要がなく、ベクトル検索を簡素化します。
全文検索の詳細については、全文検索 を参照してください。
-
テキストマッチ
Zilliz Cloud のキーワードマッチにより、特定の用語に基づく正確なドキュメント取得が可能になります。この機能は主に、特定の条件を満たすためのフィルター検索に使用され、スカラーフィルタリングを組み込んでクエリ結果を絞り込み、スカラー条件を満たすベクトル内での類似検索を可能にします。
キーワードマッチの詳細については、キーワードマッチ を参照してください。
-
パーティションキーを使用する
メタデータフィルタリングに複数のスカラーフィールドを含めたり、かなり複雑なフィルター条件を使用したりすると、検索効率に影響する可能性があります。スカラーフィールドをパーティションキーとして設定し、パーティションキーを含むフィルター条件を検索リクエストで使用すると、検索範囲を指定したパーティションキー値に対応するパーティション内に制限するのに役立ちます。
パーティションキーの詳細については、パーティションキーを使用する を参照してください。
-
mmap を使用する
mmap 設定の詳細については、mmap を使用する を参照してください。