البحث باستخدام المفتاح الأساسيCompatible with Milvus 2.6.9+

عند إجراء عمليات البحث عن التشابه، يُطلب منك دائمًا تقديم متجه استعلام واحد أو أكثر، حتى لو كانت متجهات الاستعلام موجودة بالفعل في المجموعة المستهدفة. لتجنب استرجاع المتجهات قبل البحث، يمكنك استخدام المفاتيح الأساسية بدلاً من ذلك.

نظرة عامة

في منصات التجارة الإلكترونية، يمكن للمستخدمين إدخال كلمة رئيسية لاسترداد المنتجات التي تتطابق معها. بمجرد أن يعرض المستخدم صفحة تفاصيل المنتج، ستعرض المنصة أيضًا قائمة بالمنتجات المشابهة في أسفل الصفحة للمستخدمين الذين يرغبون في مقارنتها.

يتم فرز التوصيات حسب مدى تشابهها مع الكلمة المفتاحية أو المنتج الحالي. ولتحقيق ذلك، يحتاج مطورو المنصات إلى استرداد التمثيل المتجهي للكلمة المفتاحية أو المنتج الحالي من Milvus قبل إجراء البحث الفعلي عن التشابه، مما يزيد من عدد رحلات الذهاب والإياب بين المنصة وMilvus ويؤدي إلى إرسال عدد كبير من القيم العائمة عالية الأبعاد عبر الشبكة.

لتبسيط منطق التفاعل بين تطبيقاتك وMilvus، وتقليل عدد عمليات الذهاب والإياب، وتجنب إرسال كميات كبيرة من قيم العدد العائم عالية الأبعاد عبر الشبكة، فكر في استخدام عمليات البحث بالمفتاح الأساسي.

في عملية البحث باستخدام المفتاح الأساسي، لا تحتاج إلى تقديم أي متجهات استعلام. بدلاً من ذلك، يُطلب منك تقديم المفاتيح الأساسية (ids) للكيانات التي تحتوي على متجهات الاستعلام.

الحدود والقيود

  • تنطبق عمليات البحث باستخدام المفاتيح الأساسية على جميع أنواع بيانات المتجهات، باستثناء حقول المتجهات المتفرقة المشتقة من حقول VarChar، كما هو الحال في دوال BM25.

  • يمكنك استخدام المفاتيح الأساسية بدلاً من متجهات الاستعلام في عمليات البحث المُصفاة، وعمليات البحث حسب النطاق، وعمليات البحث حسب التجميع، مع تمكين ترقيم الصفحات اختياريًا. ومع ذلك، لا تنطبق هذه الميزة على عمليات البحث المختلطة ومكررات البحث.

  • بالنسبة لعمليات البحث عن التشابه التي تتضمن قوائم التضمين، لا تزال بحاجة إلى استرداد متجهات الاستعلام وترتيبها في قوائم التضمين وتشغيل عمليات البحث.

  • لا يمكنك استخدام المفاتيح الأساسية بدلاً من متجهات الاستعلام في واجهات برمجة التطبيقات (API) RESTful.

  • بالنسبة لأي مفاتيح أساسية غير موجودة أو تلك ذات التنسيق غير الصحيح، سيُظهر Milvus رسائل خطأ.

  • المفاتيح الأساسية ومتجهات الاستعلام متنافية. ويؤدي توفير كليهما أيضًا إلى حدوث أخطاء.

أمثلة

تفترض الأمثلة التالية أن جميع معرّفات Int64 المقدمة متوفرة في المجموعة المستهدفة.

لا تُستخدم المفاتيح الأساسية للتصفية؛ بل تُستخدم فقط لاسترجاع المتجهات.

لإجراء بحث أساسي باستخدام المفتاح الأساسي، ما عليك سوى استبدال متجهات الاستعلام بالمفاتيح الأساسية.

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