تصميم نموذج البيانات للبحث

تُعد أنظمة استرجاع المعلومات، والمعروفة أيضًا باسم محركات البحث، ضرورية لتطبيقات الذكاء الاصطناعي المختلفة مثل التوليد المعزز للاسترجاع (RAG) والبحث المرئي والتوصية بالمنتجات. يوجد في صميم هذه الأنظمة نموذج بيانات مصمم بعناية لتنظيم المعلومات وفهرستها واسترجاعها.

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

Data Model Anatomy تشريح نموذج البيانات

نموذج البيانات

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

تحليل احتياجات العمل

تبدأ المعالجة الفعالة لاحتياجات العمل بتحليل أنواع الاستعلامات التي سيقوم بها المستخدمون وتحديد طرق البحث الأنسب.

  • استعلامات المستخدم: تحديد أنواع الاستعلامات المتوقع أن يقوم بها المستخدمون. يساعد ذلك على ضمان دعم مخططك لحالات الاستخدام في العالم الحقيقي وتحسين أداء البحث. قد تتضمن هذه الاستعلامات:

    • استرجاع المستندات التي تطابق استعلام لغة طبيعية

    • العثور على صور مشابهة لصورة مرجعية أو مطابقة وصف نصي

    • البحث عن المنتجات حسب السمات مثل الاسم أو الفئة أو العلامة التجارية

    • تصفية العناصر بناءً على البيانات الوصفية المنظمة (على سبيل المثال، تاريخ النشر والعلامات والتقييمات)

    • الجمع بين معايير متعددة في الاستعلامات المختلطة (على سبيل المثال، في البحث المرئي، مع مراعاة التشابه الدلالي لكل من الصور وتعليقاتها)

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

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

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

    • تصفية البيانات الوصفية: علاوة على البحث المتجه، تطبيق قيود مثل نطاقات التاريخ أو الفئات أو العلامات.

ترجمة متطلبات العمل إلى نموذج بيانات البحث

الخطوة التالية هي ترجمة متطلبات عملك إلى نموذج بيانات ملموس، من خلال تحديد المكونات الأساسية لمعلوماتك وطرق البحث الخاصة بها:

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

  • تحديد أنواع البيانات والتنسيقات المناسبة لكل عنصر. على سبيل المثال:

    • أوصاف نصية → سلسلة

    • تضمينات الصور أو المستندات → متجهات كثيفة أو متفرقة

    • الفئات أو الوسوم أو العلامات أو الأعلام → سلسلة أو مصفوفة أو صفيف أو صوري

    • السمات العددية مثل السعر أو التصنيف → عدد صحيح أو عائم

    • المعلومات المهيكلة مثل تفاصيل المؤلف -> json

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

تصميم المخطط

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

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

الحقل المتجه

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

يدعم ميلفوس أنواع بيانات المتجهات: FLOAT_VECTOR للمتجهات الكثيفة، SPARSE_FLOAT_VECTOR للمتجهات المتفرقة و BINARY_VECTOR للمتجهات الثنائية

الحقول العددية

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

يدعم ميلفوس أنواعًا قياسية مثل BOOL و INT8/16/32/64 و و FLOAT و DOUBLE و VARCHAR و JSON و ARRAY لتخزين وتصفية البيانات غير المتجهة. تعزز هذه الأنواع دقة عمليات البحث وتخصيصها.

الاستفادة من الميزات المتقدمة في تصميم المخطط

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

المفتاح الأساسي

يعد حقل المفتاح الأساسي مكونًا أساسيًا في المخطط، حيث إنه يحدد بشكل فريد كل كيان داخل المجموعة. تعريف المفتاح الأساسي إلزامي. يجب أن يكون حقلًا قياسيًا من النوع الصحيح أو السلسلة ويتم تمييزه على أنه is_primary=True. اختياريًا، يمكنك تمكين auto_id للمفتاح الأساسي، والذي يتم تعيينه تلقائيًا بأرقام صحيحة تنمو بشكل متجانس كلما تم إدخال المزيد من البيانات في المجموعة.

لمزيد من التفاصيل، راجع الحقل الأساسي والمعرف التلقائي.

التقسيم

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

لمزيد من التفاصيل، راجع استخدام مفتاح التقسيم.

المحلل

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

لمزيد من التفاصيل، راجع نظرة عامة على المحلِّل.

الوظيفة

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

لمزيد من التفاصيل، راجع البحث عن النص الكامل.

مثال من العالم الحقيقي

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

الحقل

مصدر البيانات

المستخدمة من قبل طرق البحث

المفتاح الأساسي

مفتاح التقسيم

المحلل

مدخلات/مخرجات الوظيفة

article_id (INT64)

تم إنشاؤه تلقائيًا مع تمكين auto_id

استعلام باستخدام Get

Y

N

N

N

العنوان (VARCHAR)

عنوان المقالة

تطابق النص

N

N

Y

N

الطابع الزمني (INT32)

تاريخ النشر

تصفية حسب مفتاح التقسيم

N

Y

N

N

النص (VARCHAR)

النص الخام للمقال

البحث الهجين متعدد النواقل

N

N

Y

المدخلات

text_dense_vector (FLOAT_VECTOR)

متجه كثيف تم إنشاؤه بواسطة نموذج تضمين النص

بحث المتجه الأساسي

N

N

N

N

text_sparse_vector (SPARSE_FLOAT_VECTOR)

متجه متناثر يتم إنشاؤه تلقائيًا بواسطة دالة BM25 المدمجة

بحث النص الكامل

N

N

N

الإخراج

لمزيد من المعلومات حول المخططات وإرشادات مفصلة حول إضافة أنواع مختلفة من الحقول، يرجى الرجوع إلى شرح المخطط.

تهيئة المخطط

للبدء، نحتاج إلى إنشاء مخطط فارغ. تؤسس هذه الخطوة بنية أساسية لتحديد نموذج البيانات.

from pymilvus import MilvusClient

schema = MilvusClient.create_schema()
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.CreateCollectionReq;

// 1. Connect to Milvus server
ConnectConfig connectConfig = ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build();

MilvusClientV2 client = new MilvusClientV2(connectConfig);

// 2. Create an empty schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

//Skip this step using JavaScript
import "github.com/milvus-io/milvus/client/v2/entity"

schema := entity.NewSchema()
# Skip this step using cURL

إضافة حقول

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

from pymilvus import DataType

schema.add_field(field_name="article_id", datatype=DataType.INT64, is_primary=True, auto_id=True, description="article id")
schema.add_field(field_name="title", datatype=DataType.VARCHAR, enable_analyzer=True, enable_match=True, max_length=200, description="article title")
schema.add_field(field_name="timestamp", datatype=DataType.INT32, description="publish date")
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=2000, enable_analyzer=True, description="article text content")
schema.add_field(field_name="text_dense_vector", datatype=DataType.FLOAT_VECTOR, dim=768, description="text dense vector")
schema.add_field(field_name="text_sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR, description="text sparse vector")
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;

schema.addField(AddFieldReq.builder()
        .fieldName("article_id")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .autoID(true)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("title")
        .dataType(DataType.VarChar)
        .maxLength(200)
        .enableAnalyzer(true)
        .enableMatch(true)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("timestamp")
        .dataType(DataType.Int32)
        .build())
schema.addField(AddFieldReq.builder()
        .fieldName("text")
        .dataType(DataType.VarChar)
        .maxLength(2000)
        .enableAnalyzer(true)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("text_dense_vector")
        .dataType(DataType.FloatVector)
        .dimension(768)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("text_sparse_vector")
        .dataType(DataType.SparseFloatVector)
        .build());
const fields = [
    {
        name: "article_id",
        data_type: DataType.Int64,
        is_primary_key: true,
        auto_id: true
    },
    {
        name: "title",
        data_type: DataType.VarChar,
        max_length: 200,
        enable_analyzer: true,
        enable_match: true
    },
    {
        name: "timestamp",
        data_type: DataType.Int32
    },
    {
        name: "text",
        data_type: DataType.VarChar,
        max_length: 2000,
        enable_analyzer: true
    },
    {
        name: "text_dense_vector",
        data_type: DataType.FloatVector,
        dim: 768
    },
    {
        name: "text_sparse_vector",
        data_type: DataType.SparseFloatVector
    }
]
schema.WithField(entity.NewField().
    WithName("article_id").
    WithDataType(entity.FieldTypeInt64).
    WithIsPrimaryKey(true).
    WithIsAutoID(true).
    WithDescription("article id"),
).WithField(entity.NewField().
    WithName("title").
    WithDataType(entity.FieldTypeVarChar).
    WithMaxLength(200).
    WithEnableAnalyzer(true).
    WithEnableMatch(true).
    WithDescription("article title"),
).WithField(entity.NewField().
    WithName("timestamp").
    WithDataType(entity.FieldTypeInt32).
    WithDescription("publish date"),
).WithField(entity.NewField().
    WithName("text").
    WithDataType(entity.FieldTypeVarChar).
    WithMaxLength(2000).
    WithEnableAnalyzer(true).
    WithDescription("article text content"),
).WithField(entity.NewField().
    WithName("text_dense_vector").
    WithDataType(entity.FieldTypeFloatVector).
    WithDim(768).
    WithDescription("text dense vector"),
).WithField(entity.NewField().
    WithName("text_sparse_vector").
    WithDataType(entity.FieldTypeSparseVector).
    WithDescription("text sparse vector"),
)
export fields='[
    {
        "fieldName": "article_id",
        "dataType": "Int64",
        "isPrimary": true
    },
    {
        "fieldName": "title",
        "dataType": "VarChar",
        "elementTypeParams": {
            "max_length": 200,
            "enable_analyzer": true,
            "enable_match": true
        }
    },
    {
        "fieldName": "timestamp",
        "dataType": "Int32"
    },
    {
       "fieldName": "text",
       "dataType": "VarChar",
       "elementTypeParams": {
            "max_length": 2000,
            "enable_analyzer": true
        }
    },
    {
       "fieldName": "text_dense_vector",
       "dataType": "FloatVector",
       "elementTypeParams": {
            "dim": 768
        }
    },
    {
       "fieldName": "text_sparse_vector",
       "dataType": "SparseFloatVector",
    }
]'

export schema="{
    \"autoID\": true,
    \"fields\": $fields
}"

في هذا المثال، تم تحديد السمات التالية للحقول:

  • المفتاح الأساسي: يتم استخدام article_id كمفتاح أساسي يتيح تخصيص المفاتيح الأساسية تلقائيًا للكيانات الواردة.

  • مفتاح التقسيم: يتم تعيين timestamp كمفتاح تقسيم يسمح بالتصفية حسب الأقسام. قد يكون هذا

  • محلل النص: يتم تطبيق محلل النص على حقلي السلسلة title و text لدعم مطابقة النص والبحث عن النص الكامل على التوالي.

(اختياري) إضافة دوال

لتعزيز قدرات الاستعلام عن البيانات، يمكن دمج الدوال في المخطط. على سبيل المثال، يمكن إنشاء دالة لمعالجة متعلقة بحقول محددة.

from pymilvus import Function, FunctionType

bm25_function = Function(
    name="text_bm25",
    input_field_names=["text"],
    output_field_names=["text_sparse_vector"],
    function_type=FunctionType.BM25,
)

schema.add_function(bm25_function)
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.service.collection.request.CreateCollectionReq.Function;

import java.util.*;

schema.addFunction(Function.builder()
        .functionType(FunctionType.BM25)
        .name("text_bm25")
        .inputFieldNames(Collections.singletonList("text"))
        .outputFieldNames(Collections.singletonList("text_sparse_vector"))
        .build());
import FunctionType from "@zilliz/milvus2-sdk-node";

const functions = [
    {
      name: 'text_bm25',
      description: 'bm25 function',
      type: FunctionType.BM25,
      input_field_names: ['text'],
      output_field_names: ['text_sparse_vector'],
      params: {},
    },
];
function := entity.NewFunction().
    WithName("text_bm25").
    WithInputFields("text").
    WithOutputFields("text_sparse_vector").
    WithType(entity.FunctionTypeBM25)
schema.WithFunction(function)
export myFunctions='[
    {
        "name": "text_bm25",
        "type": "BM25",
        "inputFieldNames": ["text"],
        "outputFieldNames": ["text_sparse_vector"],
        "params": {}
    }
]'

export schema="{
    \"autoID\": true,
    \"fields\": $fields
    \"functions\": $myFunctions
}"

يضيف هذا المثال دالة BM25 مدمجة في المخطط، باستخدام الحقل text كمدخلات وتخزين المتجهات المتفرقة الناتجة في الحقل text_sparse_vector.

الخطوات التالية