المتجهات المتفرقة

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

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

في هذا البرنامج التعليمي، سوف تتعلم كيفية:

  • إعداد تضمينات المتجهات المتفرقة;
  • إنشاء مجموعة مع حقل متجه متناثر;
  • إدراج الكيانات ذات التضمينات المتجهة المتفرقة;
  • فهرسة المجموعة وإجراء بحث ANN على المتجهات المتفرقة.

لمشاهدة المتجهات المتفرقة أثناء العمل، راجع hello_sparse.py.

ملاحظات

حاليًا، دعم المتجهات المتفرقة هو ميزة تجريبية في الإصدار 2.4.0، مع وجود خطط لجعلها متاحة بشكل عام في الإصدار 3.0.0.

إعداد تضمينات المتجهات المتفرقة

لاستخدام المتجهات المتفرقة في ميلفوس، قم بإعداد تضمينات المتجهات بأحد التنسيقات المدعومة:

  • المصفوفات المتفرقة: استخدم عائلة فئة scipy.sparse لتمثيل التضمينات المتفرقة الخاصة بك. هذه الطريقة فعالة للتعامل مع البيانات واسعة النطاق وعالية الأبعاد.

  • قائمة القواميس: تمثيل كل تضمين متناثر كقاموس، منظم على شكل {dimension_index: value, ...} ، حيث يمثل كل زوج من المفاتيح والقيمة فهرس البعد وقيمته المقابلة.

    مثال:

    {2: 0.33, 98: 0.72, ...}
    
  • قائمة قواميس التضمين المتكرر: مشابه لقائمة القواميس، ولكن استخدم قائمة من القواميس، [(dimension_index, value)] ، لتحديد الأبعاد غير الصفرية وقيمها فقط.

    مثال:

    [(2, 0.33), (98, 0.72), ...]
    

يقوم المثال التالي بإعداد التضمينات المتفرقة عن طريق توليد مصفوفة متناثرة عشوائية لـ 10000 كيان، لكل منها 10000 بُعد وكثافة تناثرية تبلغ 0.005.

# Prepare entities with sparse vector representation
import numpy as np
import random

rng = np.random.default_rng()

num_entities, dim = 10000, 10000

# Generate random sparse rows with an average of 25 non-zero elements per row
entities = [
    {
        "scalar_field": rng.random(),
        # To represent a single sparse vector row, you can use:
        # - Any of the scipy.sparse sparse matrices class family with shape[0] == 1
        # - Dict[int, float]
        # - Iterable[Tuple[int, float]]
        "sparse_vector": {
            d: rng.random() for d in random.sample(range(dim), random.randint(20, 30))
        },
    }
    for _ in range(num_entities)
]

# print the first entity to check the representation
print(entities[0])

# Output:
# {
#     'scalar_field': 0.520821523849214,
#     'sparse_vector': {
#         5263: 0.2639375518635271,
#         3573: 0.34701499565746674,
#         9637: 0.30856525997853057,
#         4399: 0.19771651149001523,
#         6959: 0.31025067641541815,
#         1729: 0.8265339135915016,
#         1220: 0.15303302147479103,
#         7335: 0.9436728846033107,
#         6167: 0.19929870545596562,
#         5891: 0.8214617920371853,
#         2245: 0.7852255053773395,
#         2886: 0.8787982039149889,
#         8966: 0.9000606703940665,
#         4910: 0.3001170013981104,
#         17: 0.00875671667413136,
#         3279: 0.7003425473001098,
#         2622: 0.7571360018373428,
#         4962: 0.3901879090102064,
#         4698: 0.22589525720196246,
#         3290: 0.5510228492587324,
#         6185: 0.4508413201390492
#     }
# }

ملاحظات

يجب أن تكون أبعاد المتجهات من نوع Python int أو numpy.integer ، ويجب أن تكون القيم من نوع Python float أو numpy.floating.

لتوليد التضمينات، يمكنك أيضًا استخدام الحزمة model المضمنة في مكتبة PyMilvus، والتي تقدم مجموعة من وظائف التضمين. لمزيد من التفاصيل، راجع التضمينات.

إنشاء مجموعة ذات حقل متجه متناثر

لإنشاء مجموعة مع حقل متجه متناثر، قم بتعيين نوع بيانات حقل المتجه المتناثر إلى DataType.SPARSE_FLOAT_VECTOR. على عكس المتجهات الكثيفة، ليست هناك حاجة لتحديد بُعد للمتجهات المتفرقة.

from pymilvus import MilvusClient, DataType

# Create a MilvusClient instance
client = MilvusClient(uri="http://localhost:19530")

# Create a collection with a sparse vector field
schema = client.create_schema(
    auto_id=True,
    enable_dynamic_fields=True,
)

schema.add_field(field_name="pk", datatype=DataType.VARCHAR, is_primary=True, max_length=100)
schema.add_field(field_name="scalar_field", datatype=DataType.DOUBLE)
# For sparse vector, no need to specify dimension
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR) # set `datatype` to `SPARSE_FLOAT_VECTOR`

client.create_collection(collection_name="test_sparse_vector", schema=schema)

للحصول على تفاصيل حول معلمات المجموعة الشائعة، راجع create_collection().

إدراج الكيانات ذات التضمينات المتجهة المتفرقة

لإدراج الكيانات ذات التضمينات المتجهة المتناثرة، ما عليك سوى تمرير قائمة الكيانات إلى insert() الطريقة.

# Insert entities
client.insert(collection_name="test_sparse_vector", data=entities)

فهرسة المجموعة

قبل إجراء عمليات البحث عن التشابه، قم بإنشاء فهرس للمجموعة. لمزيد من المعلومات حول أنواع الفهرس والمعلمات راجع إضافة_فهرس() وإنشاء_فهرس().

# Index the collection

# Prepare index params
index_params = client.prepare_index_params()

index_params.add_index(
    field_name="sparse_vector",
    index_name="sparse_inverted_index",
    index_type="SPARSE_INVERTED_INDEX", # the type of index to be created. set to `SPARSE_INVERTED_INDEX` or `SPARSE_WAND`.
    metric_type="IP", # the metric type to be used for the index. Currently, only `IP` (Inner Product) is supported.
    params={"drop_ratio_build": 0.2}, # the ratio of small vector values to be dropped during indexing.
)

# Create index
client.create_index(collection_name="test_sparse_vector", index_params=index_params)

لبناء فهرس على المتجهات المتناثرة، لاحظ ما يلي:

  • index_type: نوع الفهرس المراد إنشاؤه. الخيارات الممكنة للمتجهات المتفرقة:

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

    • SPARSE_WAND: يستخدم خوارزمية (WAND) الضعيفة لتجاوز المرشحين غير المحتملين بسرعة، مع تركيز التقييم على أولئك الذين لديهم إمكانات ترتيب أعلى. يعامل الأبعاد على أنها مصطلحات ومتجهات كمستندات، مما يسرّع من عمليات البحث في مجموعات البيانات الكبيرة والمتناثرة.

  • metric_type: يتم دعم مقياس المسافة IP (المنتج الداخلي) فقط للمتجهات المتفرقة.

  • params.drop_ratio_build: معلمة الفهرس المستخدمة خصيصًا للمتجهات المتفرقة. تتحكم في نسبة قيم المتجهات الصغيرة التي يتم استبعادها أثناء عملية الفهرسة. تتيح هذه المعلمة ضبط المفاضلة بين الكفاءة والدقة من خلال تجاهل القيم الصغيرة عند إنشاء الفهرس. على سبيل المثال، إذا كان drop_ratio_build = 0.3 ، أثناء إنشاء الفهرس، يتم تجميع جميع القيم من جميع المتجهات المتفرقة وفرزها. لا يتم تضمين أصغر 30% من هذه القيم في الفهرس، مما يقلل من عبء العمل الحسابي أثناء البحث.

لمزيد من المعلومات، راجع الفهرس داخل الذاكرة.

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

# Load the collection into memory
client.load_collection(collection_name="test_sparse_vector")

# Perform ANN search on sparse vectors

# for demo purpose we search for the last inserted vector
query_vector = entities[-1]["sparse_vector"]

search_params = {
    "metric_type": "IP",
    "params": {"drop_ratio_search": 0.2}, # the ratio of small vector values to be dropped during search.
}

search_res = client.search(
    collection_name="test_sparse_vector",
    data=[query_vector],
    limit=3,
    output_fields=["pk", "scalar_field"],
    search_params=search_params,
)

for hits in search_res:
    for hit in hits:
        print(f"hit: {hit}")
        
# Output:
# hit: {'id': '448458373272710786', 'distance': 7.220192909240723, 'entity': {'pk': '448458373272710786', 'scalar_field': 0.46767865218233806}}
# hit: {'id': '448458373272708317', 'distance': 1.2287548780441284, 'entity': {'pk': '448458373272708317', 'scalar_field': 0.7315987515699472}}
# hit: {'id': '448458373272702005', 'distance': 0.9848432540893555, 'entity': {'pk': '448458373272702005', 'scalar_field': 0.9871869181562156}}

عند تكوين معلمات البحث، لاحظ ما يلي:

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

إجراء استعلامات قياسية

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

تصفية الكيانات ذات الحقل_المتجه القياسي الأكبر من 3:

# Perform a query by specifying filter expr
filter_query_res = client.query(
    collection_name="test_sparse_vector",
    filter="scalar_field > 0.999",
)

print(filter_query_res[:2])

# Output:
# [{'pk': '448458373272701862', 'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}}, {'pk': '448458373272702421', 'scalar_field': 0.9990218525410719, 'sparse_vector': {448: 0.587817907333374, 1866: 0.0994109958410263, 2438: 0.8672442436218262, 2533: 0.8063794374465942, 2595: 0.02122959867119789, 2828: 0.33827054500579834, 2871: 0.1984412521123886, 2938: 0.09674275666475296, 3154: 0.21552987396717072, 3662: 0.5236313343048096, 3711: 0.6463911533355713, 4029: 0.4041993021965027, 7143: 0.7370485663414001, 7589: 0.37588241696357727, 7776: 0.436136394739151, 7962: 0.06377989053726196, 8385: 0.5808192491531372, 8592: 0.8865005970001221, 8648: 0.05727503448724747, 9071: 0.9450633525848389, 9161: 0.146037295460701, 9358: 0.1903032660484314, 9679: 0.3146636486053467, 9974: 0.8561339378356934, 9991: 0.15841573476791382}}]

تصفية الكيانات حسب المفتاح الأساسي:

# primary keys of entities that satisfy the filter
pks = [ret["pk"] for ret in filter_query_res]

# Perform a query by primary key
pk_query_res = client.query(
    collection_name="test_sparse_vector", filter=f"pk == '{pks[0]}'"
)

print(pk_query_res)

# Output:
# [{'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}, 'pk': '448458373272701862'}]

الحدود

عند استخدام المتجهات المتفرقة في ميلفوس، ضع في اعتبارك الحدود التالية:

  • حاليًا، يتم دعم مقياس مسافة IP فقط للمتجهات المتفرقة.

  • بالنسبة لحقول المتجهات المتفرقة، يتم دعم أنواع الفهرس SPARSE_INVERTED_INDEX و SPARSE_WAND فقط.

  • في الوقت الحالي، لا يتم دعم البحث في النطاق والبحث التجميعي ومكرر البحث للمتجهات المتفرقة.

الأسئلة الشائعة

  • ما هو مقياس المسافة المدعوم للمتجهات المتفرقة؟

    لا تدعم المتجهات المتفرقة سوى مقياس المسافة الضرب الداخلي (IP) بسبب الأبعاد العالية للمتجهات المتفرقة، مما يجعل المسافة L2 ومسافة جيب التمام غير عمليتين.

  • هل يمكنك شرح الفرق بين SPARSE_INVERTED_INDEX و SPARSE_WAND، وكيف يمكنني الاختيار بينهما؟

    SPARSE_INVERTED_INDEX هو فهرس مقلوب تقليدي، بينما يستخدم SPARSE_WAND خوارزمية SPARSE_WAND خوارزمية ضعيفة لتقليل عدد تقييمات مسافة IP الكاملة أثناء البحث. عادةً ما تكون SPARSE_WAND أسرع، لكن أداءها يمكن أن ينخفض مع زيادة كثافة المتجهات. للاختيار بينها، قم بإجراء التجارب والمعايير بناءً على مجموعة البيانات وحالة الاستخدام الخاصة بك.

  • كيف يمكنني اختيار معلمات drop_ratio_build و drop_ratio_search؟

    يعتمد اختيار دروب_راتيو_بيلد ودروب_راتيو_بحث على خصائص بياناتك ومتطلباتك من حيث زمن انتقال/إنتاجية البحث والدقة.

  • ما أنواع البيانات المدعومة للتضمينات المتفرقة؟

    يجب أن يكون جزء البُعد عددًا صحيحًا غير موزع 32 بت، ويمكن أن يكون جزء القيمة رقمًا عائمًا غير سالب 32 بت.

  • هل يمكن أن يكون بُعد التضمين المتناثر أي قيمة منفصلة ضمن فضاء uint32؟

    نعم، مع استثناء واحد. يمكن أن يكون بُعد التضمين المتناثر أي قيمة في نطاق [0, maximum of uint32). هذا يعني أنه لا يمكنك استخدام القيمة القصوى لـ uint32.

  • هل تجرى عمليات البحث على المقاطع المتزايدة من خلال فهرس أم بالقوة الغاشمة؟

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

  • هل من الممكن وجود متجهات متناثرة وكثيفة في مجموعة واحدة؟

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

  • ما هي متطلبات التضمينات المتفرقة لإدراجها أو البحث عنها؟

    يجب أن تحتوي التضمينات المتفرقة على قيمة واحدة غير صفرية على الأقل، ويجب أن تكون مؤشرات المتجهات غير سالبة.