مكرر البحث

يضع بحث الشبكة العصبية الاصطناعية (ANN Search) حدًا أقصى لعدد الكيانات التي يمكن استرجاعها في استعلام واحد، وقد لا يلبي استخدام بحث الشبكة العصبية الاصطناعية الأساسي متطلبات الاسترجاع على نطاق واسع. بالنسبة لطلبات البحث باستخدام الشبكة العصبية الاصطناعية (ANN) التي يتجاوز فيها عدد topK 16,384، يُنصح بالنظر في استخدام SearchIterator. سيقدم هذا القسم شرحًا لكيفية استخدام SearchIterator والاعتبارات ذات الصلة.

نظرة عامة

يعرض طلب البحث نتائج البحث، بينما يعرض SearchIterator متكررًا. يمكنك استدعاء الطريقة next() لهذا المتكرر للحصول على نتائج البحث.

على وجه التحديد، يمكنك استخدام SearchIterators على النحو التالي:

  1. قم بإنشاء SearchIterator وقم بتعيين عدد الكيانات المراد إرجاعها لكل طلب بحث والعدد الإجمالي للكيانات المراد إرجاعها.

  2. استدعاء الطريقة next() الخاصة بـ SearchIterator في حلقة للحصول على نتائج البحث مقسمة إلى صفحات.

  3. استدعاء الطريقة close() الخاصة بالمكرر لإنهاء الحلقة إذا عادت الطريقة next() بنتيجة فارغة.

إنشاء SearchIterator

يوضح مقتطف الشفرة التالي كيفية إنشاء SearchIterator.

from pymilvus import connections, Collection

connections.connect(
    uri="http://localhost:19530",
    token="root:Milvus"
)

# create iterator
query_vectors = [
    [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]]

collection = Collection("iterator_collection")

iterator = collection.search_iterator(
    data=query_vectors,
    anns_field="vector",
    param={"metric_type": "L2", "params": {"nprobe": 16}},
    batch_size=50,
    output_fields=["color"],
    limit=20000
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.orm.iterator.SearchIterator;
import io.milvus.v2.common.IndexParam.MetricType;
import io.milvus.v2.service.vector.request.data.FloatVec;

import java.util.*;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .token("root:Milvus")
        .build());

FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
SearchIterator searchIterator = client.searchIterator(SearchIteratorReq.builder()
        .collectionName("iterator_collection")
        .vectors(Collections.singletonList(queryVector))
        .vectorFieldName("vector")
        .batchSize(500L)
        .outputFields(Lists.newArrayList("color"))
        .topK(20000)
        .metricType(IndexParam.MetricType.COSINE)
        .build());
// go
import { MilvusClient } from '@zilliz/milvus2-sdk-node';

const milvusClient = new MilvusClient({
  address: 'http://localhost:19530',
  token: 'root:Milvus',
});

const queryVectors = [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
];
const collectionName = 'iterator_collection';

const iterator = milvusClient.searchIterator({
    collection_name: collectionName,
    vectors: queryVectors,
    anns_field: 'vector',
    params: { metric_type: 'L2', params: { nprobe: 16 } },
    batch_size: 50,
    output_fields: ['color'],
    limit: 20000,
});

export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"

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": "iterator_collection",
    "annsField": "vector",
    "data": [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]],
    "searchParams": {
        "metricType": "L2",
        "params": {
            "nprobe": 16
        }
    },
    "limit": 50,
    "offset": 0,
    "outputFields": ["color"]
}'
#include <iostream>
#include <vector>

#include "milvus/MilvusClientV2.h"

auto client = milvus::MilvusClientV2::Create();
auto status = client->Connect(milvus::ConnectParam("http://localhost:19530", "root:Milvus"));
if (!status.IsOk()) {
    std::cerr << "Failed to connect: " << status.Message() << std::endl;
    return;
}

// create iterator
std::vector<float> queryVector = {
    0.35803764F, -0.60234958F, 0.18414013F, -0.26286206F, 0.90294385F
};

milvus::SearchIteratorRequest request;
request.SetCollectionName("iterator_collection");
request.SetAnnsField("vector");
request.SetMetricType(milvus::MetricType::L2);
request.AddExtraParam("nprobe", "16");
request.SetBatchSize(50);
request.AddOutputField("color");
request.SetLimit(20000);
// SearchIterator only accepts one vector
request.AddFloatVector(queryVector);

milvus::SearchIteratorPtr iterator;
status = client->SearchIterator(request, iterator);
if (!status.IsOk()) {
    std::cerr << "Failed to create search iterator: " << status.Message() << std::endl;
    return;
}

في الأمثلة أعلاه، قمت بتعيين عدد الكيانات المراد إرجاعها لكل عملية بحث (batch_size/batchSize) إلى 50، وإجمالي عدد الكيانات المراد إرجاعها (topK) إلى 20,000.

استخدام SearchIterator

بمجرد أن يصبح SearchIterator جاهزًا، يمكنك استدعاء طريقة next() الخاصة به للحصول على نتائج البحث مقسمة إلى صفحات.

results = []

while True:
    result = iterator.next()
    if not result:
        iterator.close()
        break
    
    for hit in result:
        results.append(hit.to_dict())
import io.milvus.response.QueryResultsWrapper;

while (true) {
    List<QueryResultsWrapper.RowRecord> res = searchIterator.next();
    if (res.isEmpty()) {
        searchIterator.close();
        break;
    }

    for (QueryResultsWrapper.RowRecord record : res) {
        System.out.println(record);
    }
}
// go
for await (const result of iterator) {
    console.log(result);
}
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"

batch_size=50
limit=20000
offset=0

# Paginate with offset until an empty page is returned. Note that the sum of
# offset and limit in each request must not exceed the server-side result
# window (16,384 by default); SDK search iterators do not have this limit.
while [ "$offset" -lt "$limit" ]; do
    response=$(curl --silent --request POST \
        --url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
        --header "Authorization: Bearer ${TOKEN}" \
        --header "Content-Type: application/json" \
        --header "Request-Timeout: 10" \
        -d '{
            "collectionName": "iterator_collection",
            "annsField": "vector",
            "data": [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]],
            "searchParams": {
                "metricType": "L2",
                "params": {
                    "nprobe": 16
                }
            },
            "limit": '"$batch_size"',
            "offset": '"$offset"',
            "outputFields": ["color"]
        }')

    count=$(echo "$response" | jq -r '.data | length')
    if [ "$count" -eq 0 ]; then
        break
    fi

    echo "$response" | jq -r '.data[]'
    offset=$((offset + batch_size))
done
while (true) {
    milvus::SingleResult result;
    status = iterator->Next(result);
    if (!status.IsOk()) {
        std::cerr << "Iterator next failed: " << status.Message() << std::endl;
        break;
    }
    if (result.GetRowCount() == 0) {
        break;
    }

    milvus::EntityRows rows;
    status = result.OutputRows(rows);
    if (!status.IsOk()) {
        std::cerr << "Failed to get output rows: " << status.Message() << std::endl;
        break;
    }

    for (const auto& row : rows) {
        std::cout << row.dump() << std::endl;
    }
}

في أمثلة الكود أعلاه، قمت بإنشاء حلقة لا نهائية واستدعيت الطريقة next() داخل الحلقة لتخزين نتائج البحث في متغير، وأغلقت المكرر عندما لم تُرجع الطريقة next() أي نتيجة.

ترجمة بواسطةDeepL

جرب Managed Milvus مجاناً

Zilliz Cloud خالي من المتاعب، ويعمل بواسطة Milvus ويعمل بسرعة 10 أضعاف.

ابدأ
التعليقات

هل كانت هذه الصفحة مفيدة؟