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

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

  • المخطط وحقول البيانات

  • متجه متناثر

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

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

نظرة عامة

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

  • تحليل النصوص: تمثيل المستندات على هيئة متجهات كيس من الكلمات، حيث يتوافق كل بُعد مع كلمة، والكلمات التي تظهر في المستند فقط هي التي لها قيم غير صفرية.

  • أنظمة التوصيات: مصفوفات التفاعل بين المستخدم والعنصر، حيث يمثل كل بُعد تقييم المستخدم لعنصر معين، حيث يتفاعل معظم المستخدمين مع عدد قليل من العناصر فقط.

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

كما هو موضح في الرسم البياني أدناه، عادةً ما يتم تمثيل المتجهات الكثيفة كمصفوفات مستمرة حيث يكون لكل موضع قيمة (على سبيل المثال، [0.3, 0.8, 0.2, 0.3, 0.1]). في المقابل، تخزّن المتجهات المتفرقة العناصر غير الصفرية ومؤشراتها فقط، وغالبًا ما يتم تمثيلها كأزواج قيمة مفتاح-قيمة (على سبيل المثال، [{2: 0.2}, ..., {9997: 0.5}, {9999: 0.7}]). يقلل هذا التمثيل بشكل كبير من مساحة التخزين ويزيد من الكفاءة الحسابية، خاصة عند التعامل مع بيانات عالية الأبعاد للغاية (على سبيل المثال، 10000 بُعد).

Spare vector representation تمثيل المتجهات المتفرقة

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

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

بعد التحويل إلى متجهات، يمكن تخزين البيانات في ميلفوس لإدارتها واسترجاع المتجهات. يوضح الرسم البياني أدناه العملية الأساسية.

Use sparse vector in Milvus استخدام المتجهات المتفرقة في ملفوس

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

استخدام المتجهات المتفرقة في ميلفوس

يدعم Milvus تمثيل المتجهات المتفرقة بأي من التنسيقات التالية.

  • مصفوفة متفرقة (باستخدام فئة scipy.sparse )

    from scipy.sparse import csr_matrix
    
    # Create a sparse matrix
    row = [0, 0, 1, 2, 2, 2]
    col = [0, 2, 2, 0, 1, 2]
    data = [1, 2, 3, 4, 5, 6]
    sparse_matrix = csr_matrix((data, (row, col)), shape=(3, 3))
    
    # Represent sparse vector using the sparse matrix
    sparse_vector = sparse_matrix.getrow(0)
    
    
  • قائمة القواميس (بتنسيق {dimension_index: value, ...})

    # Represent sparse vector using a dictionary
    sparse_vector = [{1: 0.5, 100: 0.3, 500: 0.8, 1024: 0.2, 5000: 0.6}]
    
    
    SortedMap<Long, Float> sparseVector = new TreeMap<>();
    sparseVector.put(1L, 0.5f);
    sparseVector.put(100L, 0.3f);
    sparseVector.put(500L, 0.8f);
    sparseVector.put(1024L, 0.2f);
    sparseVector.put(5000L, 0.6f);
    
    
  • قائمة القواميس التكرارية (منسقة على [(dimension_index, value)])

    # Represent sparse vector using a list of tuples
    sparse_vector = [[(1, 0.5), (100, 0.3), (500, 0.8), (1024, 0.2), (5000, 0.6)]]
    
    

إضافة حقل متجه

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

  1. تعيين datatype إلى نوع بيانات المتجهات المتفرقة المدعومة، SPARSE_FLOAT_VECTOR.

  2. لا حاجة لتحديد البُعد.

from pymilvus import MilvusClient, DataType

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

client.drop_collection(collection_name="my_sparse_collection")

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="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;

import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);
schema.addField(AddFieldReq.builder()
        .fieldName("pk")
        .dataType(DataType.VarChar)
        .isPrimaryKey(true)
        .autoID(true)
        .maxLength(100)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("sparse_vector")
        .dataType(DataType.SparseFloatVector)
        .build());

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

const schema = [
  {
    name: "metadata",
    data_type: DataType.JSON,
  },
  {
    name: "pk",
    data_type: DataType.Int64,
    is_primary_key: true,
  },
  {
    name: "sparse_vector",
    data_type: DataType.SparseFloatVector,
  }
];


export primaryField='{
    "fieldName": "pk",
    "dataType": "VarChar",
    "isPrimary": true,
    "elementTypeParams": {
        "max_length": 100
    }
}'

export vectorField='{
    "fieldName": "sparse_vector",
    "dataType": "SparseFloatVector"
}'

export schema="{
    \"autoID\": true,
    \"fields\": [
        $primaryField,
        $vectorField
    ]
}"

في هذا المثال، تمت إضافة حقل متجه باسم sparse_vector لتخزين المتجهات المتفرقة. نوع بيانات هذا الحقل هو SPARSE_FLOAT_VECTOR.

تعيين بارامترات الفهرس للحقل المتجه

تشبه عملية إنشاء فهرس للمتجهات المتفرقة عملية إنشاء فهرس للمتجهات الكثيفة، ولكن مع وجود اختلافات في نوع الفهرس المحدد (index_type)، ومقياس المسافة (metric_type)، ومعلمات الفهرس (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",
    metric_type="IP",
    params={"inverted_index_algo": "DAAT_MAXSCORE"},
)

import io.milvus.v2.common.IndexParam;
import java.util.*;

List<IndexParam> indexes = new ArrayList<>();
Map<String,Object> extraParams = new HashMap<>();
extraParams.put("inverted_index_algo": "DAAT_MAXSCORE");
indexes.add(IndexParam.builder()
        .fieldName("sparse_vector")
        .indexName("sparse_inverted_index")
        .indexType(IndexParam.IndexType.SPARSE_INVERTED_INDEX)
        .metricType(IndexParam.MetricType.IP)
        .extraParams(extraParams)
        .build());

const indexParams = await client.createIndex({
    index_name: 'sparse_inverted_index',
    field_name: 'sparse_vector',
    metric_type: MetricType.IP,
    index_type: IndexType.SPARSE_INVERTED_INDEX,
    params: {
      inverted_index_algo: 'DAAT_MAXSCORE',
    },
});

export indexParams='[
        {
            "fieldName": "sparse_vector",
            "metricType": "IP",
            "indexName": "sparse_inverted_index",
            "indexType": "SPARSE_INVERTED_INDEX",
            "params":{"inverted_index_algo": "DAAT_MAXSCORE"}
        }
    ]'

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

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

    • SPARSE_INVERTED_INDEX: فهرس مقلوب للأغراض العامة للمتجهات المتفرقة.

    بدءًا من الإصدار 2.5.4 فصاعدًا، يتم إهمال SPARSE_WAND. بدلاً من ذلك، يوصى باستخدام "inverted_index_algo": "DAAT_WAND" للمعادلة مع الحفاظ على التوافق.

  • metric_type: المقياس المستخدم لحساب التشابه بين المتجهات المتفرقة. قيم صالحة:

    • IP (الضرب الداخلي): يقيس التشابه باستخدام الضرب النقطي.

    • BM25: يستخدم عادةً للبحث في النص الكامل، مع التركيز على التشابه النصي.

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

  • params.inverted_index_algo: الخوارزمية المستخدمة لبناء الفهرس والاستعلام عنه. قيم صالحة:

    • "DAAT_MAXSCORE" (افتراضي): معالجة استعلام المستند في الوقت المحسن (DAAT) باستخدام خوارزمية MaxScore. يوفر MaxScore أداءً أفضل لقيم k العالية أو الاستعلامات التي تحتوي على العديد من المصطلحات عن طريق تخطي المصطلحات والمستندات التي من المحتمل أن يكون لها تأثير ضئيل. وهي تحقق ذلك من خلال تقسيم المصطلحات إلى مجموعات أساسية وغير أساسية بناءً على درجات التأثير القصوى، مع التركيز على المصطلحات التي يمكن أن تساهم في أعلى k من النتائج.

    • "DAAT_WAND": معالجة استعلام DAAT المحسّنة باستخدام خوارزمية WAND. تقوم WAND بتقييم عدد أقل من المستندات التي تم الوصول إليها من خلال الاستفادة من درجات التأثير القصوى لتخطي المستندات غير المنافسة، ولكن لديها نفقات أعلى لكل ضربة. وهذا يجعل WAND أكثر كفاءة للاستعلامات ذات القيم k الصغيرة أو الاستعلامات القصيرة، حيث يكون التخطي أكثر جدوى.

    • "TAAT_NAIVE": معالجة استعلام المصطلح الأساسي في الوقت (TAAT). على الرغم من أنها أبطأ مقارنةً بـ DAAT_MAXSCORE و DAAT_WAND ، إلا أن TAAT_NAIVE تقدم ميزة فريدة. على عكس خوارزميات DAAT، التي تستخدم درجات التأثير القصوى المخزنة مؤقتًا والتي تظل ثابتة بغض النظر عن التغييرات التي تطرأ على معلمة المجموعة العالمية (avgdl)، يتكيف TAAT_NAIVE ديناميكيًا مع هذه التغييرات.

إنشاء مجموعة

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

client.create_collection(
    collection_name="my_sparse_collection",
    schema=schema,
    index_params=index_params
)

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_sparse_collection")
        .collectionSchema(schema)
        .indexParams(indexes)
        .build();
client.createCollection(requestCreate);

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

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

await client.createCollection({
    collection_name: 'my_sparse_collection',
    schema: schema,
    index_params: indexParams
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
    \"collectionName\": \"my_sparse_collection\",
    \"schema\": $schema,
    \"indexParams\": $indexParams
}"

إدراج البيانات

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

sparse_vectors = [
    {"sparse_vector": {1: 0.5, 100: 0.3, 500: 0.8}},
    {"sparse_vector": {10: 0.1, 200: 0.7, 1000: 0.9}},
]

client.insert(
    collection_name="my_sparse_collection",
    data=sparse_vectors
)

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;

List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
{
    JsonObject row = new JsonObject();
    SortedMap<Long, Float> sparse = new TreeMap<>();
    sparse.put(1L, 0.5f);
    sparse.put(100L, 0.3f);
    sparse.put(500L, 0.8f);
    row.add("sparse_vector", gson.toJsonTree(sparse));
    rows.add(row);
}
{
    JsonObject row = new JsonObject();
    SortedMap<Long, Float> sparse = new TreeMap<>();
    sparse.put(10L, 0.1f);
    sparse.put(200L, 0.7f);
    sparse.put(1000L, 0.9f);
    row.add("sparse_vector", gson.toJsonTree(sparse));
    rows.add(row);
}

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("my_sparse_collection")
        .data(rows)
        .build());

const data = [
  { sparse_vector: { "1": 0.5, "100": 0.3, "500": 0.8 } },
  { sparse_vector: { "10": 0.1, "200": 0.7, "1000": 0.9 } },
];
client.insert({
  collection_name: "my_sparse_collection",
  data: data,
});


curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "data": [
        {"sparse_vector": {"1": 0.5, "100": 0.3, "500": 0.8}},
        {"sparse_vector": {"10": 0.1, "200": 0.7, "1000": 0.9}}        
    ],
    "collectionName": "my_sparse_collection"
}'

## {"code":0,"cost":0,"data":{"insertCount":2,"insertIds":["453577185629572534","453577185629572535"]}}

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

# Prepare search parameters
search_params = {
    "params": {"drop_ratio_search": 0.2},  # Additional optional search parameters
}

# Prepare the query vector
query_vector = [{1: 0.2, 50: 0.4, 1000: 0.7}]

في هذا المثال، drop_ratio_search هي معلمة اختيارية مخصصة للمتجهات المتناثرة، مما يسمح بضبط القيم الصغيرة في متجه الاستعلام أثناء البحث. على سبيل المثال، باستخدام {"drop_ratio_search": 0.2} ، سيتم تجاهل أصغر 20% من القيم في متجه الاستعلام أثناء البحث.

بعد ذلك، قم بتنفيذ بحث التشابه باستخدام الطريقة search.

res = client.search(
    collection_name="my_sparse_collection",
    data=query_vector,
    limit=3,
    output_fields=["pk"],
    search_params=search_params,
)

print(res)

# Output
# data: ["[{'id': '453718927992172266', 'distance': 0.6299999952316284, 'entity': {'pk': '453718927992172266'}}, {'id': '453718927992172265', 'distance': 0.10000000149011612, 'entity': {'pk': '453718927992172265'}}]"]

import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.SparseFloatVec;
import io.milvus.v2.service.vector.response.SearchResp;

Map<String,Object> searchParams = new HashMap<>();
searchParams.put("drop_ratio_search", 0.2);

SortedMap<Long, Float> sparse = new TreeMap<>();
sparse.put(10L, 0.1f);
sparse.put(200L, 0.7f);
sparse.put(1000L, 0.9f);

SparseFloatVec queryVector = new SparseFloatVec(sparse);

SearchResp searchR = client.search(SearchReq.builder()
        .collectionName("my_sparse_collection")
        .data(Collections.singletonList(queryVector))
        .annsField("sparse_vector")
        .searchParams(searchParams)
        .topK(3)
        .outputFields(Collections.singletonList("pk"))
        .build());
        
System.out.println(searchR.getSearchResults());

// Output
//
// [[SearchResp.SearchResult(entity={pk=453444327741536759}, score=1.31, id=453444327741536759), SearchResp.SearchResult(entity={pk=453444327741536756}, score=1.31, id=453444327741536756), SearchResp.SearchResult(entity={pk=453444327741536753}, score=1.31, id=453444327741536753)]]

client.search({
    collection_name: 'my_sparse_collection',
    data: {1: 0.2, 50: 0.4, 1000: 0.7},
    limit: 3,
    output_fields: ['pk'],
    params: {
        drop_ratio_search: 0.2
    }
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_sparse_collection",
    "data": [
        {"1": 0.2, "50": 0.4, "1000": 0.7}
    ],
    "annsField": "sparse_vector",
    "limit": 3,
    "searchParams":{
        "params":{"drop_ratio_search": 0.2}
    },
    "outputFields": ["pk"]
}'

## {"code":0,"cost":0,"data":[{"distance":0.63,"id":"453577185629572535","pk":"453577185629572535"},{"distance":0.1,"id":"453577185629572534","pk":"453577185629572534"}]}

لمزيد من المعلومات حول معلمات البحث عن التشابه، راجع بحث التشابه الأساسي.

الحدود

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

  • حاليًا، يتم دعم مقاييس المسافة IP و BM25 (للبحث في النص الكامل) فقط للمتجهات المتفرقة. إن الأبعاد العالية للمتجهات المتفرقة تجعل المسافة L2 ومسافة جيب التمام غير عملية.

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

  • أنواع البيانات المدعومة للمتجهات المتفرقة:

    • يجب أن يكون جزء البُعد عددًا صحيحًا غير موقع 32 بت;
    • يمكن أن يكون جزء القيمة رقمًا عائمًا غير سالب 32 بت غير سالب.
  • يجب أن تستوفي المتجهات المتفرقة المتطلبات التالية للإدراج والبحث:

    • قيمة واحدة على الأقل في المتجه لا تساوي صفرًا;
    • مؤشرات المتجهات غير سالبة.

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

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

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

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

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

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

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

جرب Managed Milvus مجاناً

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

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

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