🚀 جرب Zilliz Cloud، الـ Milvus المدارة بالكامل، مجاناً — تجربة أداء أسرع بـ 10 أضعاف! جرب الآن>>

milvus-logo
LFAI
الصفحة الرئيسية
  • دليل المستخدم
  • Home
  • Docs
  • دليل المستخدم

  • البحث وإعادة التصنيف

  • تجميع البحث عن المجموعات

تجميع البحث

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

نظرة عامة

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

افترض أن مجموعة تخزن مستندات متعددة (يُشار إليها بـ docId). للاحتفاظ بأكبر قدر ممكن من المعلومات الدلالية عند تحويل المستندات إلى متجهات، يتم تقسيم كل مستند إلى فقرات (أو أجزاء) أصغر يمكن التحكم فيها وتخزينها ككيانات منفصلة. على الرغم من تقسيم المستند إلى أقسام أصغر، إلا أن المستخدمين غالبًا ما يظلون مهتمين بتحديد المستندات الأكثر صلة باحتياجاتهم.

ANN Search البحث في الشبكة النانوية

عند إجراء بحث الجار الأقرب التقريبي (ANN) على مثل هذه المجموعة، قد تتضمن نتائج البحث عدة فقرات من نفس المستند، مما قد يؤدي إلى تجاهل مستندات أخرى، وهو ما قد لا يتماشى مع حالة الاستخدام المقصودة.

Grouping Search تجميع البحث

لتحسين تنوّع نتائج البحث، يمكنك إضافة المعلمة group_by_field في طلب البحث لتمكين تجميع البحث. كما هو موضح في الرسم التخطيطي، يمكنك تعيين group_by_field إلى docId. عند تلقي هذا الطلب، سيقوم ميلفوس بـ

  • إجراء بحث ANN استنادًا إلى متجه الاستعلام المقدم للعثور على جميع الكيانات الأكثر تشابهًا مع الاستعلام.

  • تجميع نتائج البحث حسب group_by_field المحدد، مثل docId.

  • إرجاع أفضل النتائج لكل مجموعة، كما هو محدد بواسطة المعلمة limit ، مع الكيان الأكثر تشابهًا من كل مجموعة.

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

يوفر هذا القسم مثالاً على التعليمات البرمجية لتوضيح استخدام البحث عن التجميع. يفترض المثال التالي أن المجموعة تتضمن حقول id و vector و chunk و docId.

[
        {"id": 0, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "chunk": "pink_8682", "docId": 1},
        {"id": 1, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "chunk": "red_7025", "docId": 5},
        {"id": 2, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "chunk": "orange_6781", "docId": 2},
        {"id": 3, "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], "chunk": "pink_9298", "docId": 3},
        {"id": 4, "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], "chunk": "red_4794", "docId": 3},
        {"id": 5, "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], "chunk": "yellow_4222", "docId": 4},
        {"id": 6, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], "chunk": "red_9392", "docId": 1},
        {"id": 7, "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], "chunk": "grey_8510", "docId": 2},
        {"id": 8, "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], "chunk": "white_9381", "docId": 5},
        {"id": 9, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], "chunk": "purple_4976", "docId": 3},
]


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

from pymilvus import MilvusClient

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)

query_vectors = [
    [0.14529211512077012, 0.9147257273453546, 0.7965055218724449, 0.7009258593102812, 0.5605206522382088]]

# Group search results
res = client.search(
    collection_name="group_search_collection",
    data=query_vectors,
    limit=3,
    group_by_field="docId",
    output_fields=["docId"]
)

# Retrieve the values in the `docId` column
doc_ids = [result['entity']['docId'] for result in res[0]]

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

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

FloatVec queryVector = new FloatVec(new float[]{0.14529211512077012f, 0.9147257273453546f, 0.7965055218724449f, 0.7009258593102812f, 0.5605206522382088f});
SearchReq searchReq = SearchReq.builder()
        .collectionName("group_search_collection")
        .data(Collections.singletonList(queryVector))
        .topK(3)
        .groupByFieldName("docId")
        .outputFields(Collections.singletonList("docId"))
        .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={docId=5}, score=0.74767184, id=1)
// SearchResp.SearchResult(entity={docId=2}, score=0.6254269, id=7)
// SearchResp.SearchResult(entity={docId=3}, score=0.3611898, id=3)

// nolint
func ExampleClient_Search_grouping() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    milvusAddr := "127.0.0.1:19530"
    token := "root:Milvus"

    cli, err := client.New(ctx, &client.ClientConfig{
        Address: milvusAddr,
        APIKey:  token,
    })
    if err != nil {
        log.Fatal("failed to connect to milvus server: ", err.Error())
    }

    defer cli.Close(ctx)

    queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}

    resultSets, err := cli.Search(ctx, client.NewSearchOption(
        "my_collection", // collectionName
        3,               // limit
        []entity.Vector{entity.FloatVector(queryVector)},
    ).WithGroupByField("docId"))
    if err != nil {
        log.Fatal("failed to perform basic ANN search collection: ", err.Error())
    }

    for _, resultSet := range resultSets {
        log.Println("IDs: ", resultSet.IDs)
        log.Println("Scores: ", resultSet.Scores)
    }
    // Output:
    // IDs:
    // Scores:
}

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

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

var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = await client.search({
    collection_name: "my_collection",
    data: [query_vector],
    limit: 3,
    // highlight-start
    group_by_field: "docId"
    // highlight-end
})

// Retrieve the values in the `docId` column
var docIds = res.results.map(result => result.entity.docId)

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" \
-d '{
    "collectionName": "group_search_collection",
    "data": [
        [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
    ],
    "annsField": "vector",
    "limit": 3,
    "groupingField": "docId",
    "outputFields": ["docId"]
}'

في الطلب أعلاه، limit=3 يشير إلى أن النظام سيعيد نتائج البحث من ثلاث مجموعات، بحيث تحتوي كل مجموعة على الكيان الأكثر تشابهًا مع متجه الاستعلام.

تكوين حجم المجموعة

بشكل افتراضي، يُرجع البحث عن المجموعات كيان واحد فقط لكل مجموعة. إذا كنت تريد نتائج متعددة لكل مجموعة، اضبط المعلمات group_size و strict_group_size.

# Group search results

res = client.search(
    collection_name="group_search_collection", 
    data=query_vectors, # Query vector
    limit=5, # Top K results to return
    group_by_field="docId", # Group by docId
    group_size=2, # Return 2 entities per group
    strict_group_size=True, # Ensure each group has 2 entities
    output_fields=["docId"]
)

FloatVec queryVector = new FloatVec(new float[]{0.14529211512077012f, 0.9147257273453546f, 0.7965055218724449f, 0.7009258593102812f, 0.5605206522382088f});
SearchReq searchReq = SearchReq.builder()
        .collectionName("group_search_collection")
        .data(Collections.singletonList(queryVector))
        .topK(5)
        .groupByFieldName("docId")
        .groupSize(2)
        .strictGroupSize(true)
        .outputFields(Collections.singletonList("docId"))
        .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={docId=5}, score=0.74767184, id=1)
// SearchResp.SearchResult(entity={docId=5}, score=-0.49148706, id=8)
// SearchResp.SearchResult(entity={docId=2}, score=0.6254269, id=7)
// SearchResp.SearchResult(entity={docId=2}, score=0.38515577, id=2)
// SearchResp.SearchResult(entity={docId=3}, score=0.3611898, id=3)
// SearchResp.SearchResult(entity={docId=3}, score=0.19556211, id=4)

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

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

var query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]

res = await client.search({
    collection_name: "my_collection",
    data: [query_vector],
    limit: 3,
    group_by_field: "docId",
    // highlight-start
    group_size: 2,
    strict_group_size: true
    // highlight-end
})

// Retrieve the values in the `docId` column
var docIds = res.results.map(result => result.entity.docId)

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "group_search_collection",
    "data": [
        [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
    ],
    "annsField": "vector",
    "limit": 5,
    "groupingField": "docId",
    "groupSize":2,
    "strictGroupSize":true,
    "outputFields": ["docId"]
}'

في المثال أعلاه

  • group_size: يحدد عدد الكيانات المطلوب إرجاعها لكل مجموعة. على سبيل المثال، تعيين group_size=2 يعني أن كل مجموعة (أو كل docId) يجب أن تُرجع بشكل مثالي فقرتين من أكثر الفقرات (أو القطع) تشابهًا. إذا لم يتم تعيين group_size ، يقوم النظام افتراضيًا بإرجاع نتيجة واحدة لكل مجموعة.

  • strict_group_size: تتحكم هذه المعلمة المنطقية فيما إذا كان يجب على النظام فرض العدد الذي تم تعيينه بواسطة group_size. عند strict_group_size=True ، سيحاول النظام تضمين العدد الدقيق للكيانات المحددة بواسطة group_size في كل مجموعة (على سبيل المثال، فقرتان)، ما لم تكن هناك بيانات كافية في تلك المجموعة. بشكل افتراضي (strict_group_size=False)، يعطي النظام الأولوية لتلبية عدد المجموعات المحددة بواسطة المعلمة limit ، بدلاً من ضمان احتواء كل مجموعة على group_size كيانات. هذا النهج أكثر كفاءة بشكل عام في الحالات التي يكون فيها توزيع البيانات غير متساوٍ.

للحصول على تفاصيل المعلمة الإضافية، راجع البحث ().

الاعتبارات

  • عدد المجموعات: تتحكم المعلمة limit في عدد المجموعات التي يتم إرجاع نتائج البحث منها، بدلاً من العدد المحدد للكيانات داخل كل مجموعة. يساعد تعيين limit المناسب في التحكم في تنوع البحث وأداء الاستعلام. يمكن أن يؤدي تقليل limit إلى تقليل تكاليف الحوسبة إذا كانت البيانات موزعة بكثافة أو إذا كان الأداء مصدر قلق.

  • الكيانات لكل مجموعة: تتحكم المعلمة group_size في عدد الكيانات التي يتم إرجاعها لكل مجموعة. يمكن أن يؤدي ضبط group_size بناءً على حالة الاستخدام إلى زيادة ثراء نتائج البحث. ومع ذلك، إذا كانت البيانات موزعة بشكل غير متساوٍ، فقد تقوم بعض المجموعات بإرجاع عدد كيانات أقل من المحدد بواسطة group_size ، خاصة في سيناريوهات البيانات المحدودة.

  • حجم المجموعة الصارم: عند strict_group_size=True ، سيحاول النظام إرجاع العدد المحدد من الكيانات (group_size) لكل مجموعة، ما لم تكن هناك بيانات كافية في تلك المجموعة. يضمن هذا الإعداد عدد كيانات متناسق لكل مجموعة ولكنه قد يؤدي إلى تدهور الأداء مع التوزيع غير المتكافئ للبيانات أو الموارد المحدودة. إذا لم يكن عدد الكيانات الصارم مطلوبًا، يمكن أن يؤدي الإعداد strict_group_size=False إلى تحسين سرعة الاستعلام.

جرب Managed Milvus مجاناً

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

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

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