Pencarian Kunci UtamaCompatible with Milvus 2.6.9+

Saat melakukan pencarian kesamaan, Anda selalu diminta untuk menyediakan satu atau lebih vektor kueri, meskipun vektor-vektor kueri tersebut sudah ada di dalam koleksi target. Untuk menghindari pengambilan vektor sebelum pencarian, Anda dapat menggunakan kunci utama sebagai gantinya.

Gambaran Umum

Di platform e-commerce, pengguna dapat memasukkan kata kunci untuk mengambil produk yang cocok dengannya. Setelah pengguna melihat halaman detail produk, platform juga akan menampilkan daftar produk serupa di bagian bawah halaman bagi pengguna yang ingin membandingkannya.

Rekomendasi tersebut diurutkan berdasarkan kemiripannya dengan kata kunci atau produk yang sedang dilihat. Untuk mencapai hal ini, pengembang platform perlu mengambil representasi vektor dari kata kunci atau produk yang sedang dilihat dari Milvus sebelum pencarian kemiripan sebenarnya dilakukan, yang meningkatkan jumlah round-trip antara platform dan Milvus serta mengakibatkan transmisi sejumlah besar nilai floating-point berdimensi tinggi melalui jaringan.

Untuk menyederhanakan logika interaksi antara aplikasi Anda dan Milvus, mengurangi jumlah perjalanan bolak-balik, dan menghindari pengiriman sejumlah besar nilai floating-point berdimensi tinggi melalui jaringan, pertimbangkan untuk menggunakan pencarian berdasarkan kunci utama.

Dalam pencarian kunci utama, Anda tidak perlu menyediakan vektor kueri apa pun. Sebagai gantinya, Anda diminta untuk menyediakan kunci utama (ids) dari entitas yang berisi vektor kueri tersebut.

Batasan & pembatasan

  • Pencarian menggunakan kunci utama berlaku untuk semua tipe data vektor, kecuali bidang vektor langka yang diturunkan dari bidang VarChar, seperti dalam fungsi BM25.

  • Anda dapat menggunakan kunci utama sebagai pengganti vektor kueri dalam pencarian yang difilter, rentang, dan pengelompokan, dengan opsi paginasi diaktifkan. Namun, fitur ini tidak berlaku untuk pencarian hibrida dan iterator pencarian.

  • Untuk pencarian kesamaan yang melibatkan daftar embedding, Anda tetap perlu mengambil vektor kueri, menyusunnya menjadi daftar embedding, dan menjalankan pencarian.

  • Anda tidak dapat menggunakan kunci utama sebagai pengganti vektor kueri dalam API RESTful.

  • Untuk kunci utama yang tidak ada atau yang formatnya salah, Milvus akan menampilkan pesan kesalahan.

  • Kunci utama dan vektor kueri saling eksklusif. Menyertakan keduanya juga akan mengakibatkan kesalahan.

Contoh

Contoh-contoh berikut mengasumsikan bahwa semua ID Int64 yang disediakan tersedia di koleksi tujuan.

Kunci utama tidak digunakan untuk penyaringan; kunci tersebut hanya digunakan untuk pengambilan vektor.

Untuk melakukan pencarian kunci utama dasar, cukup ganti vektor kueri dengan kunci utama.

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;
    }
}

Contoh 2: Pencarian dengan penyaringan menggunakan kunci utama

Contoh berikut mengasumsikan bahwa color dan likes adalah dua kolom yang didefinisikan dalam skema pada koleksi target.

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;
    }
}

Contoh 3: Pencarian rentang menggunakan kunci utama

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;
    }
}

Contoh 4: Pencarian pengelompokan menggunakan kunci utama

Contoh berikut mengasumsikan bahwa ` docId ` adalah bidang yang didefinisikan dalam skema pada koleksi target.

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;
    }
}