أدوات التحليل متعددة اللغاتCompatible with Milvus 2.5.11+

عندما يقوم Milvus بتحليل النص، فإنه عادةً ما يطبق محللًا واحدًا على حقل النص بأكمله في المجموعة. وإذا كان هذا المحلل مُحسّنًا للغة الإنجليزية، فإنه يواجه صعوبة في التعامل مع قواعد التقطيع إلى رموز وقواعد اشتقاق الكلمات المختلفة تمامًا التي تتطلبها لغات أخرى، مثل الصينية أو الإسبانية أو الفرنسية، مما يؤدي إلى انخفاض معدل الاسترجاع. على سبيل المثال، قد يؤدي البحث عن الكلمة الإسبانية «teléfono» (التي تعني «هاتف») إلى تعثر المحلل المخصص للغة الإنجليزية: فقد يتجاهل علامة التشكيل ولا يطبق قواعد الاشتقاق الخاصة باللغة الإسبانية، مما يؤدي إلى تجاهل النتائج ذات الصلة.

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

القيود

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

  • يمكن لكل مستند في مجموعة واحدة استخدام محلل واحد فقط، يتم تحديده وفقًا لقيمة حقل معرف اللغة الخاص به.

  • قد يختلف الأداء اعتمادًا على مدى تعقيد أدوات التحليل وحجم بيانات النص.

نظرة عامة

يوضح الرسم البياني التالي سير العمل الخاص بتكوين واستخدام المحللات متعددة اللغات في Milvus:

Multi Language Analyzers Workflow سير عمل المحللات متعددة اللغات

  1. تكوين المحللات متعددة اللغات:

    • قم بإعداد محللات متعددة خاصة باللغات باستخدام التنسيق: <analyzer_name>: <analyzer_config> ، حيث يتبع كل محلل analyzer_config التكوين القياسي analyzer_params كما هو موضح في نظرة عامة على المحلل.

    • حدد حقل معرّف خاص سيحدد اختيار المحلل لكل مستند.

    • تكوين محلل default للتعامل مع اللغات غير المعروفة.

  2. إنشاء مجموعة:

    • تحديد المخطط مع الحقول الأساسية:

      • primary_key: معرّف فريد للمستند.

      • text_field: يخزن محتوى النص الأصلي.

      • identifier_field: يشير إلى المحلل الذي يجب استخدامه لكل مستند.

      • vector_field: يخزن التضمينات المتفرقة التي سيتم إنشاؤها بواسطة دالة BM25.

    • تكوين دالة BM25 ومعلمات الفهرسة.

  3. إدراج البيانات مع معرفات اللغة:

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

    • يختار Milvus المحلل المناسب بناءً على حقل المعرف، وتستخدم المستندات ذات المعرفات غير المعروفة محلل « default ».

  4. البحث باستخدام محللات خاصة باللغة:

    • أدخل نص الاستعلام مع تحديد اسم المحلل، ويقوم Milvus بمعالجة الاستعلام باستخدام المحلل المحدد.

    • يتم التقطيع وفقًا لقواعد خاصة باللغة، ويعرض البحث نتائج مناسبة للغة بناءً على التشابه.

الخطوة 1: تكوين multi_analyzer_params

يُعد « multi_analyzer_params » كائن JSON واحد يحدد كيفية اختيار Milvus للمحلل المناسب لكل كيان:

multi_analyzer_params = {
  # Define language-specific analyzers
  # Each analyzer follows this format: <analyzer_name>: <analyzer_params>
  "analyzers": {
    "english": {"type": "english"},          # English-optimized analyzer
    "chinese": {"type": "chinese"},          # Chinese-optimized analyzer
    "arabic": {"type": "arabic"},            # Arabic-optimized analyzer
    "thai": {"type": "thai"},                # Thai-optimized analyzer
    "default": {"tokenizer": "icu"}          # Required fallback analyzer
  },
  "by_field": "language",                    # Field determining analyzer selection
  "alias": {
    "ar": "arabic",                          # Use "ar" as shorthand for Arabic
    "cn": "chinese",                         # Use "cn" as shorthand for Chinese
    "en": "english",                         # Use "en" as shorthand for English
    "th": "thai"                             # Use "th" as shorthand for Thai
  }
}
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("analyzers", new HashMap<String, Object>() {{
    put("english", new HashMap<String, Object>() {{
        put("type", "english");
    }});
    put("chinese", new HashMap<String, Object>() {{
        put("type", "chinese");
    }});
    put("arabic", new HashMap<String, Object>() {{
        put("type", "arabic");
    }});
    put("thai", new HashMap<String, Object>() {{
        put("type", "thai");
    }});
    put("default", new HashMap<String, Object>() {{
        put("tokenizer", "icu");
    }});
}});
analyzerParams.put("by_field", "language");
analyzerParams.put("alias", new HashMap<String, Object>() {{
    put("ar", "arabic");
    put("cn", "chinese");
    put("en", "english");
    put("th", "thai");
}});
const multi_analyzer_params = {
  // Define language-specific analyzers
  // Each analyzer follows this format: <analyzer_name>: <analyzer_params>
  "analyzers": {
    "english": {"type": "english"},          # English-optimized analyzer
    "chinese": {"type": "chinese"},          # Chinese-optimized analyzer
    "arabic": {"type": "arabic"},            # Arabic-optimized analyzer
    "thai": {"type": "thai"},                # Thai-optimized analyzer
    "default": {"tokenizer": "icu"}          # Required fallback analyzer
  },
  "by_field": "language",                    # Field determining analyzer selection
  "alias": {
    "ar": "arabic",                          # Use "ar" as shorthand for Arabic
    "cn": "chinese",                         # Use "cn" as shorthand for Chinese
    "en": "english",                         # Use "en" as shorthand for English
    "th": "thai"                             # Use "th" as shorthand for Thai
  }
}
multiAnalyzerParams := map[string]any{
    "analyzers": map[string]any{
        "english": map[string]string{"type": "english"},
        "chinese": map[string]string{"type": "chinese"},
        "arabic": map[string]string{"type": "arabic"},
        "thai": map[string]string{"type": "thai"},
        "default": map[string]string{"tokenizer": "icu"},
    },
    "by_field": "language",
    "alias": map[string]string{
        "ar": "arabic",
        "cn": "chinese",
        "en": "english",
        "th": "thai",
    },
}
# restful
export multi_analyzer_params='{
  "analyzers": {
    "english": {
      "type": "english"
    },
    "chinese": {
      "type": "chinese"
    },
    "arabic": {
      "type": "arabic"
    },
    "thai": {
      "type": "thai"
    },
    "default": {
      "tokenizer": "icu"
    }
  },
  "by_field": "language",
  "alias": {
    "ar": "arabic",
    "cn": "chinese",
    "en": "english",
    "th": "thai"
  }
}'

المعلمة

مطلوب؟

الوصف

القواعد

analyzers

نعم

يسرد كل محلل خاص بلغة معينة يمكن لـ Milvus استخدامه لمعالجة النص. يتبع كل محلل في analyzers هذا التنسيق: <analyzer_name>: <analyzer_params>.

  • قم بتعريف كل محلل باستخدام صيغة analyzer_params القياسية (انظر نظرة عامة على المحلل).
  • أضف إدخالًا يكون مفتاحه default ؛ حيث يلجأ Milvus إلى هذا المحلل كلما لم تتطابق القيمة المخزنة في by_field مع اسم أي محلل آخر.

by_field

نعم

اسم الحقل الذي يخزن، لكل مستند، اللغة (أي اسم المحلل) التي يجب أن يطبقها Milvus.

  • يجب أن يكون حقلًا من نوع VARCHAR مُعرَّفًا في المجموعة.

  • يجب أن تتطابق القيمة في كل صف تمامًا مع أحد أسماء المحللات (أو الأسماء المستعارة) المدرجة في analyzers.

  • إذا كانت قيمة الصف مفقودة أو لم يتم العثور عليها، يطبق Milvus تلقائيًا محلل « default ».

alias

لا

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

يجب أن يرتبط كل اسم مستعار بمفتاح محلل موجود.

الخطوة 2: إنشاء مجموعة

يتطلب إنشاء مجموعة تدعم لغات متعددة تكوين حقول وفهارس محددة:

إضافة الحقول

في هذه الخطوة، حدد مخطط المجموعة بأربعة حقول أساسية:

  • حقل المفتاح الأساسي (id): معرّف فريد لكل كيان في المجموعة. يؤدي تعيين الخيار " auto_id=True " إلى تمكين Milvus من إنشاء هذه المعرّفات تلقائيًا.

  • حقل مؤشر اللغة (language): يتوافق حقل VARCHAR هذا مع المفتاح الأساسي ( by_field ) المحدد في ملف تعريف المجموعة ( multi_analyzer_params). ويخزن معرف اللغة لكل كيان، والذي يحدد لـ Milvus المحلل الذي يجب استخدامه.

  • حقل محتوى النص (text): يخزن حقل VARCHAR هذا البيانات النصية الفعلية التي تريد تحليلها والبحث فيها. يعد تعيين enable_analyzer=True أمرًا بالغ الأهمية لأنه ينشط قدرات تحليل النص لهذا الحقل. ترتبط تهيئة multi_analyzer_params مباشرةً بهذا الحقل، مما يؤسس للارتباط بين بياناتك النصية وأدوات التحليل الخاصة باللغة.

  • حقل المتجهات (sparse): سيخزن هذا الحقل المتجهات المتفرقة التي تولدها دالة BM25. تمثل هذه المتجهات الشكل القابل للتحليل لبياناتك النصية، وهي ما يبحث عنه Milvus فعليًّا.

# Import required modules
from pymilvus import MilvusClient, DataType, Function, FunctionType

# Initialize client
client = MilvusClient(
    uri="http://localhost:19530",
)

# Initialize a new schema
schema = client.create_schema()

# Step 2.1: Add a primary key field for unique document identification
schema.add_field(
    field_name="id",                  # Field name
    datatype=DataType.INT64,          # Integer data type
    is_primary=True,                  # Designate as primary key
    auto_id=True                      # Auto-generate IDs (recommended)
)

# Step 2.2: Add language identifier field
# This MUST match the "by_field" value in language_analyzer_config
schema.add_field(
    field_name="language",       # Field name
    datatype=DataType.VARCHAR,   # String data type
    max_length=255               # Maximum length (adjust as needed)
)

# Step 2.3: Add text content field with multi-language analysis capability
schema.add_field(
    field_name="text",                           # Field name
    datatype=DataType.VARCHAR,                   # String data type
    max_length=8192,                             # Maximum length (adjust based on expected text size)
    enable_analyzer=True,                        # Enable text analysis
    multi_analyzer_params=multi_analyzer_params  # Connect with our language analyzers
)

# Step 2.4: Add sparse vector field to store the BM25 output
schema.add_field(
    field_name="sparse",                   # Field name
    datatype=DataType.SPARSE_FLOAT_VECTOR  # Sparse vector data type
)
import com.google.gson.JsonObject;
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.collection.request.DropCollectionReq;
import io.milvus.v2.service.utility.request.FlushReq;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.EmbeddedText;
import io.milvus.v2.service.vector.response.SearchResp;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq.CollectionSchema collectionSchema = CreateCollectionReq.CollectionSchema.builder()
        .build();
        
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("id")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .autoID(true)
        .build());
        
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("language")
        .dataType(DataType.VarChar)
        .maxLength(255)
        .build());

collectionSchema.addField(AddFieldReq.builder()
        .fieldName("text")
        .dataType(DataType.VarChar)
        .maxLength(8192)
        .enableAnalyzer(true)
        .multiAnalyzerParams(analyzerParams)
        .build());
        
collectionSchema.addField(AddFieldReq.builder()
        .fieldName("sparse")
        .dataType(DataType.SparseFloatVector)
        .build());
import { MilvusClient, DataType, FunctionType } from "@zilliz/milvus2-sdk-node";

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

// Initialize schema array
const schema = [
  {
    name: "id",
    data_type: DataType.Int64,
    is_primary_key: true,
    auto_id: true,
  },
  {
    name: "language",
    data_type: DataType.VarChar,
    max_length: 255,
  },
  {
    name: "text",
    data_type: DataType.VarChar,
    max_length: 8192,
    enable_analyzer: true,
    analyzer_params: multi_analyzer_params,
  },
  {
    name: "sparse",
    data_type: DataType.SparseFloatVector,
  },
];

import (
    "context"
    "fmt"

    "github.com/milvus-io/milvus/client/v2/column"
    "github.com/milvus-io/milvus/client/v2/entity"
    "github.com/milvus-io/milvus/client/v2/index"
    "github.com/milvus-io/milvus/client/v2/milvusclient"
)

client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
    Address: "localhost:19530",
    APIKey:  "root:Milvus",
})
if err != nil {
    fmt.Println(err.Error())
    // handle error
}

schema := entity.NewSchema()

schema.WithField(entity.NewField().
    WithName("id").
    WithDataType(entity.FieldTypeInt64).
    WithIsPrimaryKey(true).
    WithIsAutoID(true),
).WithField(entity.NewField().
    WithName("language").
    WithDataType(entity.FieldTypeVarChar).
    WithMaxLength(255),
).WithField(entity.NewField().
    WithName("text").
    WithDataType(entity.FieldTypeVarChar).
    WithMaxLength(8192).
    WithEnableAnalyzer(true).
    WithMultiAnalyzerParams(multiAnalyzerParams),
).WithField(entity.NewField().
    WithName("sparse").
    WithDataType(entity.FieldTypeSparseVector),
)
# restful
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"

export idField='{
  "fieldName": "id",
  "dataType": "Int64",
  "isPrimary": true,
  "autoID": true
}'

export languageField='{
  "fieldName": "language",
  "dataType": "VarChar",
  "elementTypeParams": {
    "max_length": 255
  }
}'

export textField='{
  "fieldName": "text",
  "dataType": "VarChar",
  "elementTypeParams": {
    "max_length": 8192,
    "enable_analyzer": true,
    "multiAnalyzerParam": '"$multi_analyzer_params"'
  },
}'

export sparseField='{
  "fieldName": "sparse",
  "dataType": "SparseFloatVector"
}'

تحديد دالة BM25

قم بتعريف دالة BM25 لإنشاء تمثيلات متجهات متفرقة من بيانات النص الأولية الخاصة بك:

# Create the BM25 function
bm25_function = Function(
    name="text_to_vector",            # Descriptive function name
    function_type=FunctionType.BM25,  # Use BM25 algorithm
    input_field_names=["text"],       # Process text from this field
    output_field_names=["sparse"]     # Store vectors in this field
)

# Add the function to our schema
schema.add_function(bm25_function)
CreateCollectionReq.Function function = CreateCollectionReq.Function.builder()
        .functionType(FunctionType.BM25)
        .name("text_to_vector")
        .inputFieldNames(Collections.singletonList("text"))
        .outputFieldNames(Collections.singletonList("sparse"))
        .build();
collectionSchema.addFunction(function);
const functions = [
  {
    name: "text_bm25_emb",
    description: "bm25 function",
    type: FunctionType.BM25,
    input_field_names: ["text"],
    output_field_names: ["sparse"],
    params: {},
  },
];
function := entity.NewFunction()
schema.WithFunction(function.WithName("text_to_vector").
    WithType(entity.FunctionTypeBM25).
    WithInputFields("text").
    WithOutputFields("sparse"))
# restful
export function='{
  "name": "text_to_vector",
  "type": "BM25",
  "inputFieldNames": ["text"],
  "outputFieldNames": ["sparse"]
}'

export schema="{
  \"autoID\": true,
  \"fields\": [
    $idField,
    $languageField,
    $textField,
    $sparseField
  ],
  \"functions\": [
    $function
  ]
}"

تقوم هذه الدالة تلقائيًا بتطبيق المحلل المناسب على كل إدخال نصي بناءً على معرّف لغته. لمزيد من المعلومات حول استرجاع النصوص القائم على BM25، راجع البحث عن النص الكامل.

تكوين معلمات الفهرس

للسماح بالبحث الفعال، قم بإنشاء فهرس لحقل المتجهات المتفرقة:

# Configure index parameters
index_params = client.prepare_index_params()

# Add index for sparse vector field
index_params.add_index(
    field_name="sparse",        # Field to index (our vector field)
    index_type="AUTOINDEX",     # Let Milvus choose optimal index type
    metric_type="BM25"          # Must be BM25 for this feature
)
List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
        .fieldName("sparse")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.BM25)
        .build());
const index_params = [{
    field_name: "sparse",
    index_type: "AUTOINDEX",
    metric_type: "BM25"
}];
idx := index.NewAutoIndex(index.MetricType(entity.BM25))
indexOption := milvusclient.NewCreateIndexOption("multilingual_documents", "sparse", idx)
# restful
export IndexParams='[
  {
    "fieldName": "sparse",
    "indexType": "AUTOINDEX",
    "metricType": "BM25",
    "params": {}
  }
]'

يعمل الفهرس على تحسين أداء البحث من خلال تنظيم المتجهات المتفرقة لإجراء حسابات تشابه BM25 بكفاءة.

إنشاء المجموعة

تجمع هذه الخطوة النهائية من عملية الإنشاء جميع التكوينات السابقة:

  • collection_name="multilang_demo" قم بتسمية مجموعتك للرجوع إليها مستقبلاً.

  • schema=schema تطبق بنية الحقول والوظائف التي حددتها.

  • index_params=index_params تنفيذ استراتيجية الفهرسة لإجراء عمليات بحث فعالة.

# Create collection
COLLECTION_NAME = "multilingual_documents"

# Check if collection already exists
if client.has_collection(COLLECTION_NAME):
    client.drop_collection(COLLECTION_NAME)  # Remove it for this example
    print(f"Dropped existing collection: {COLLECTION_NAME}")

# Create the collection
client.create_collection(
    collection_name=COLLECTION_NAME,       # Collection name
    schema=schema,                         # Our multilingual schema
    index_params=index_params              # Our search index configuration
)
client.dropCollection(DropCollectionReq.builder()
        .collectionName("multilingual_documents")
        .build());
        
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("multilingual_documents")
        .collectionSchema(collectionSchema)
        .indexParams(indexes)
        .build();
client.createCollection(requestCreate);
const COLLECTION_NAME = "multilingual_documents";

// Create the collection
await client.createCollection({
  collection_name: COLLECTION_NAME,
  schema: schema,
  index_params: index_params,
  functions: functions
});

err = client.CreateCollection(ctx,
    milvusclient.NewCreateCollectionOption("multilingual_documents", schema).
        WithIndexOptions(indexOption))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
--data "{
  \"collectionName\": \"multilingual_documents\",
  \"schema\": $schema,
  \"indexParams\": $IndexParams
}"

في هذه المرحلة، يقوم Milvus بإنشاء مجموعة فارغة تدعم محلل اللغات المتعددة، وجاهزة لاستقبال البيانات.

الخطوة 3: إدراج بيانات نموذجية

عند إضافة مستندات إلى مجموعتك متعددة اللغات، يجب أن يتضمن كل منها محتوى نصيًّا ومعرّف لغة:

# Prepare multilingual documents
documents = [
    # English documents
    {
        "text": "Artificial intelligence is transforming technology",
        "language": "english",  # Using full language name
    },
    {
        "text": "Machine learning models require large datasets",
        "language": "en",  # Using our defined alias
    },
    # Chinese documents
    {
        "text": "人工智能正在改变技术领域",
        "language": "chinese",  # Using full language name
    },
    {
        "text": "机器学习模型需要大型数据集",
        "language": "cn",  # Using our defined alias
    },
]

# Insert the documents
result = client.insert(COLLECTION_NAME, documents)

# Print results
inserted = result["insert_count"]            
print(f"Successfully inserted {inserted} documents")
print("Documents by language: 2 English, 2 Chinese")

# Expected output:
# Successfully inserted 4 documents
# Documents by language: 2 English, 2 Chinese
List<String> texts = Arrays.asList(
        "Artificial intelligence is transforming technology",
        "Machine learning models require large datasets",
        "人工智能正在改变技术领域",
        "机器学习模型需要大型数据集"
);
List<String> languages = Arrays.asList(
        "english", "en", "chinese", "cn"
);

List<JsonObject> rows = new ArrayList<>();
for (int i = 0; i < texts.size(); i++) {
    JsonObject row = new JsonObject();
    row.addProperty("text", texts.get(i));
    row.addProperty("language", languages.get(i));
    rows.add(row);
}
client.insert(InsertReq.builder()
        .collectionName("multilingual_documents")
        .data(rows)
        .build());
// Prepare multilingual documents
const documents = [
  // English documents
  {
    text: "Artificial intelligence is transforming technology",
    language: "english",
  },
  {
    text: "Machine learning models require large datasets",
    language: "en",
  },
  // Chinese documents
  {
    text: "人工智能正在改变技术领域",
    language: "chinese",
  },
  {
    text: "机器学习模型需要大型数据集",
    language: "cn",
  },
];

// Insert the documents
const result = await client.insert({
  collection_name: COLLECTION_NAME,
  data: documents,
});

// Print results
const inserted = result.insert_count;
console.log(`Successfully inserted ${inserted} documents`);
console.log("Documents by language: 2 English, 2 Chinese");

// Expected output:
// Successfully inserted 4 documents
// Documents by language: 2 English, 2 Chinese

column1 := column.NewColumnVarChar("text",
    []string{
        "Artificial intelligence is transforming technology",
        "Machine learning models require large datasets",
        "人工智能正在改变技术领域",
        "机器学习模型需要大型数据集",
    })
column2 := column.NewColumnVarChar("language",
    []string{"english", "en", "chinese", "cn"})

_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("multilingual_documents").
    WithColumns(column1, column2),
)
if err != nil {
    fmt.Println(err.Error())
    // handle err
}
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
--data '{
  "collectionName": "multilingual_documents",
  "data": [
    {
      "text": "Artificial intelligence is transforming technology",
      "language": "english"
    },
    {
      "text": "Machine learning models require large datasets",
      "language": "en"
    },
    {
      "text": "人工智能正在改变技术领域",
      "language": "chinese"
    },
    {
      "text": "机器学习模型需要大型数据集",
      "language": "cn"
    }
  ]
}'

أثناء الإدراج، يقوم Milvus بما يلي:

  1. يقرأ حقل " language " في كل مستند

  2. يطبق المحلل المقابل على حقل text

  3. يُنشئ تمثيلًا متجهًا متفرقًا عبر دالة BM25

  4. يخزن النص الأصلي والمتجه المتفرق الذي تم إنشاؤه

لا تحتاج إلى توفير المتجه المتفرق مباشرةً؛ حيث تقوم دالة BM25 بإنشائه تلقائيًا استنادًا إلى النص والمحلل المحدد.

الخطوة 4: تنفيذ عمليات البحث

استخدم محلل اللغة الإنجليزية

عند البحث باستخدام محللات متعددة اللغات، يحتوي ملف " search_params " على إعدادات مهمة:

  • metric_type="BM25" يجب أن تتطابق مع إعدادات الفهرس.

  • analyzer_name="english" يحدد المحلل الذي سيتم تطبيقه على نص الاستعلام الخاص بك. وهذا مستقل عن المحللات المستخدمة في المستندات المخزنة.

  • params={"drop_ratio_search": "0"} يتحكم في السلوك الخاص بـ BM25؛ وهنا، يحتفظ بجميع المصطلحات في البحث. لمزيد من المعلومات، راجع «المتجه المتفرق» ( Sparse Vector).

search_params = {
    "metric_type": "BM25",            # Must match index configuration
    "analyzer_name": "english",  # Analyzer that matches the query language
    "drop_ratio_search": "0",     # Keep all terms in search (tweak as needed)
}

# Execute the search
english_results = client.search(
    collection_name=COLLECTION_NAME,  # Collection to search
    data=["artificial intelligence"],                # Query text
    anns_field="sparse",              # Field to search against
    search_params=search_params,      # Search configuration
    limit=3,                      # Max results to return
    output_fields=["text", "language"],  # Fields to include in the output
    consistency_level="Bounded",       # Data‑consistency guarantee
)

# Display English search results
print("\n=== English Search Results ===")
for i, hit in enumerate(english_results[0]):
    print(f"{i+1}. [{hit.score:.4f}] {hit.entity.get('text')} "
          f"(Language: {hit.entity.get('language')})")

# Expected output:
# === English Search Results ===
# 1. [2.7881] Artificial intelligence is transforming technology (Language: english)
Map<String,Object> searchParams = new HashMap<>();
searchParams.put("metric_type", "BM25");
searchParams.put("analyzer_name", "english");
searchParams.put("drop_ratio_search", 0);
SearchResp searchResp = client.search(SearchReq.builder()
        .collectionName("multilingual_documents")
        .data(Collections.singletonList(new EmbeddedText("artificial intelligence")))
        .annsField("sparse")
        .topK(3)
        .searchParams(searchParams)
        .outputFields(Arrays.asList("text", "language"))
        .build());

System.out.println("\n=== English Search Results ===");
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
    for (SearchResp.SearchResult result : results) {
        System.out.printf("Score: %f, %s\n", result.getScore(), result.getEntity().toString());
    }
}
// Execute the search
const english_results = await client.search({
  collection_name: COLLECTION_NAME,
  data: ["artificial intelligence"],
  anns_field: "sparse",
  params: {
    metric_type: "BM25",
    analyzer_name: "english",
    drop_ratio_search: "0",
  },
  limit: 3,
  output_fields: ["text", "language"],
  consistency_level: "Bounded",
});

// Display English search results
console.log("\n=== English Search Results ===");
english_results.results.forEach((hit, i) => {
  console.log(
    `${i + 1}. [${hit.score.toFixed(4)}] ${hit.entity.text} ` +
      `(Language: ${hit.entity.language})`
  );
});

annSearchParams := index.NewCustomAnnParam()
annSearchParams.WithExtraParam("metric_type", "BM25")
annSearchParams.WithExtraParam("analyzer_name", "english")
annSearchParams.WithExtraParam("drop_ratio_search", 0)

resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "multilingual_documents", // collectionName
    3,                        // limit
    []entity.Vector{entity.Text("artificial intelligence")},
).WithANNSField("sparse").
    WithAnnParam(annSearchParams).
    WithOutputFields("text", "language"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}

for _, resultSet := range resultSets {
    for i := 0; i < len(resultSet.Scores); i++ {
        text, _ := resultSet.GetColumn("text").GetAsString(i)
        lang, _ := resultSet.GetColumn("language").GetAsString(i)
        fmt.Println("Score: ", resultSet.Scores[i], "Text: ", text, "Language:", lang)
    }
}
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
--data '{
  "collectionName": "multilingual_documents",
  "data": ["artificial intelligence"],
  "annsField": "sparse",
  "limit": 3,
  "searchParams": {
    "metric_type": "BM25",
    "analyzer_name": "english",
    "drop_ratio_search": "0"  
  },
  "outputFields": ["text", "language"],
  "consistencyLevel": "Bounded"
}'

استخدام محلل اللغة الصينية

يوضح هذا المثال التبديل إلى محلل اللغة الصينية (باستخدام الاسم المستعار "cn") لنص استعلام مختلف. تظل جميع المعلمات الأخرى كما هي، ولكن يتم الآن معالجة نص الاستعلام باستخدام قواعد التقطيع الخاصة باللغة الصينية.

search_params["analyzer_name"] = "cn"

chinese_results = client.search(
    collection_name=COLLECTION_NAME,  # Collection to search
    data=["人工智能"],                # Query text
    anns_field="sparse",              # Field to search against
    search_params=search_params,      # Search configuration
    limit=3,                      # Max results to return
    output_fields=["text", "language"],  # Fields to include in the output
    consistency_level="Bounded",       # Data‑consistency guarantee
)

# Display Chinese search results
print("\n=== Chinese Search Results ===")
for i, hit in enumerate(chinese_results[0]):
    print(f"{i+1}. [{hit.score:.4f}] {hit.entity.get('text')} "
          f"(Language: {hit.entity.get('language')})")

# Expected output:
# === Chinese Search Results ===
# 1. [3.3814] 人工智能正在改变技术领域 (Language: chinese)
searchParams.put("analyzer_name", "cn");
searchResp = client.search(SearchReq.builder()
        .collectionName("multilingual_documents")
        .data(Collections.singletonList(new EmbeddedText("人工智能")))
        .annsField("sparse")
        .topK(3)
        .searchParams(searchParams)
        .outputFields(Arrays.asList("text", "language"))
        .build());

System.out.println("\n=== Chinese Search Results ===");
searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
    for (SearchResp.SearchResult result : results) {
        System.out.printf("Score: %f, %s\n", result.getScore(), result.getEntity().toString());
    }
}
// Execute the search
const cn_results = await client.search({
  collection_name: COLLECTION_NAME,
  data: ["人工智能"],
  anns_field: "sparse",
  params: {
    metric_type: "BM25",
    analyzer_name: "cn",
    drop_ratio_search: "0",
  },
  limit: 3,
  output_fields: ["text", "language"],
  consistency_level: "Bounded",
});

// Display Chinese search results
console.log("\n=== Chinese Search Results ===");
cn_results.results.forEach((hit, i) => {
  console.log(
    `${i + 1}. [${hit.score.toFixed(4)}] ${hit.entity.text} ` +
      `(Language: ${hit.entity.language})`
  );
});

annSearchParams.WithExtraParam("analyzer_name", "cn")

resultSets, err = client.Search(ctx, milvusclient.NewSearchOption(
    "multilingual_documents", // collectionName
    3,                        // limit
    []entity.Vector{entity.Text("人工智能")},
).WithANNSField("sparse").
    WithAnnParam(annSearchParams).
    WithOutputFields("text", "language"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}

for _, resultSet := range resultSets {
    for i := 0; i < len(resultSet.Scores); i++ {
        text, _ := resultSet.GetColumn("text").GetAsString(i)
        lang, _ := resultSet.GetColumn("language").GetAsString(i)
        fmt.Println("Score: ", resultSet.Scores[i], "Text: ", text, "Language:", lang)
    }
}

# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
--data '{
  "collectionName": "multilingual_documents",
  "data": ["人工智能"],
  "annsField": "sparse",
  "limit": 3,
  "searchParams": {
    "analyzer_name": "cn"
  },
  "outputFields": ["text", "language"],
  "consistencyLevel": "Bounded"
}'