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

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

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

  • حقل المصفوفة

حقل المصفوفة

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

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

{
  "tags": ["pop", "rock", "classic"],
  "ratings": [5, 4, 3]
}

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

إضافة حقل مصفوفة

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

  1. تعيين datatype إلى نوع بيانات المصفوفات المدعوم، ARRAY.

  2. استخدام المعلمة element_type لتحديد نوع بيانات العناصر في المصفوفة. يمكن أن يكون هذا أي نوع بيانات قياسي مدعوم من قبل Milvus، مثل VARCHAR أو INT64. يجب أن تكون جميع العناصر في نفس المصفوفة من نفس نوع البيانات.

  3. استخدام المعلمة max_capacity لتحديد السعة القصوى للمصفوفة، أي الحد الأقصى لعدد العناصر التي يمكن أن تحتويها.

إليك كيفية تعريف مخطط مجموعة يتضمن حقول المصفوفات.

from pymilvus import MilvusClient, DataType

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

schema = client.create_schema(
    auto_id=False,
    enable_dynamic_fields=True,
)

# Add an Array field with elements of type VARCHAR
schema.add_field(field_name="tags", datatype=DataType.ARRAY, element_type=DataType.VARCHAR, max_capacity=10, max_length=65535)
# Add an Array field with elements of type INT64
schema.add_field(field_name="ratings", datatype=DataType.ARRAY, element_type=DataType.INT64, max_capacity=5)

# Add primary field
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)

# Add vector field
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)

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("tags")
        .dataType(DataType.Array)
        .elementType(DataType.VarChar)
        .maxCapacity(10)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("ratings")
        .dataType(DataType.Array)
        .elementType(DataType.Int64)
        .maxCapacity(5)
        .maxLength(65535)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("pk")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("embedding")
        .dataType(DataType.FloatVector)
        .dimension(3)
        .build());

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const schema = [
  {
    name: "tags",
    data_type: DataType.Array,
    element_type: DataType.VarChar,
    max_capacity: 10,
    max_length: 65535
  },
  {
    name: "rating",
    data_type: DataType.Array,
    element_type: DataType.Int64,
    max_capacity: 5,
  },
  {
    name: "pk",
    data_type: DataType.Int64,
    is_primary_key: true,
  },
  {
    name: "embedding",
    data_type: DataType.FloatVector,
    dim: 3,
  },
];

export arrayField1='{
    "fieldName": "tags",
    "dataType": "Array",
    "elementDataType": "VarChar",
    "elementTypeParams": {
        "max_capacity": 10,
        "max_length": 65535
    }
}'

export arrayField2='{
    "fieldName": "ratings",
    "dataType": "Array",
    "elementDataType": "Int64",
    "elementTypeParams": {
        "max_capacity": 5
    }
}'

export pkField='{
    "fieldName": "pk",
    "dataType": "Int64",
    "isPrimary": true
}'

export vectorField='{
    "fieldName": "embedding",
    "dataType": "FloatVector",
    "elementTypeParams": {
        "dim": 3
    }
}'

export schema="{
    \"autoID\": false,
    \"fields\": [
        $arrayField1,
        $arrayField2,
        $pkField,
        $vectorField
    ]
}"

في هذا المثال

  • tags هي مصفوفة سلاسل مع ضبط element_type على VARCHAR ، مما يشير إلى أن العناصر في المصفوفة يجب أن تكون سلاسل. max_capacity مضبوطة على 10، مما يعني أن المصفوفة يمكن أن تحتوي على ما يصل إلى 10 عناصر.

  • ratings هي مصفوفة عدد صحيح مع تعيين element_type إلى INT64 ، مما يشير إلى أن العناصر يجب أن تكون أعدادًا صحيحة. max_capacity مضبوط على 5، مما يسمح بما يصل إلى 5 تصنيفات.

  • نضيف أيضًا حقل مفتاح أساسي pk وحقل متجه embedding.

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

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

يعد تعيين معلمات الفهرس لحقول المصفوفة أمرًا اختياريًا ولكن يمكن أن يحسن كفاءة الاسترجاع بشكل كبير.

في المثال التالي، نقوم بإنشاء AUTOINDEX للحقل tags ، مما يعني أن ميلفوس سيقوم تلقائيًا بإنشاء فهرس قياسي مناسب بناءً على نوع البيانات.

# Prepare index parameters
index_params = client.prepare_index_params()  # Prepare IndexParams object

index_params.add_index(
    field_name="tags",  # Name of the Array field to index
    index_type="AUTOINDEX",  # Index type
    index_name="inverted_index"  # Index name
)

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

List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
        .fieldName("tags")
        .indexName("inverted_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .build());

const indexParams = [{
    index_name: 'inverted_index',
    field_name: 'tags',
    index_type: IndexType.AUTOINDEX,
)];

export indexParams='[
        {
            "fieldName": "tags",
            "indexName": "inverted_index",
            "indexType": "AUTOINDEX"
        }
    ]'

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

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

# Add vector index
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",  # Use automatic indexing to simplify complex index settings
    metric_type="COSINE"  # Specify similarity metric type, such as L2, COSINE, or IP
)

indexes.add(IndexParam.builder()
        .fieldName("embedding")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.COSINE)
        .build());

 indexParams.push({
    index_name: 'embedding_index',
    field_name: 'embedding',
    index_type: IndexType.AUTOINDEX,
});

export indexParams='[
        {
            "fieldName": "tags",
            "indexName": "inverted_index",
            "indexType": "AUTOINDEX"
        },
        {
            "fieldName": "embedding",
            "metricType": "COSINE",
            "indexType": "AUTOINDEX"
        }
    ]'

إنشاء مجموعة

استخدم المخطط المحدد ومعلمات الفهرس لإنشاء مجموعة.

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

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_array_collection")
        .collectionSchema(schema)
        .indexParams(indexes)
        .build();
client.createCollection(requestCreate);

client.create_collection({
    collection_name: "my_array_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_array_collection\",
    \"schema\": $schema,
    \"indexParams\": $indexParams
}"

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

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

data = [
    {
        "tags": ["pop", "rock", "classic"],
        "ratings": [5, 4, 3],
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "tags": ["jazz", "blues"],
        "ratings": [4, 5],
        "pk": 2,
        "embedding": [0.78, 0.91, 0.23]
    },
    {
        "tags": ["electronic", "dance"],
        "ratings": [3, 3, 4],
        "pk": 3,
        "embedding": [0.67, 0.45, 0.89]
    }
]

client.insert(
    collection_name="my_array_collection",
    data=data
)

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();
rows.add(gson.fromJson("{\"tags\": [\"pop\", \"rock\", \"classic\"], \"ratings\": [5, 4, 3], \"pk\": 1, \"embedding\": [0.1, 0.2, 0.3]}", JsonObject.class));
rows.add(gson.fromJson("{\"tags\": [\"jazz\", \"blues\"], \"ratings\": [4, 5], \"pk\": 2, \"embedding\": [0.4, 0.5, 0.6]}", JsonObject.class));
rows.add(gson.fromJson("{\"tags\": [\"electronic\", \"dance\"], \"ratings\": [3, 3, 4], \"pk\": 3, \"embedding\": [0.7, 0.8, 0.9]}", JsonObject.class));

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

const data = [
    {
        "tags": ["pop", "rock", "classic"],
        "ratings": [5, 4, 3],
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "tags": ["jazz", "blues"],
        "ratings": [4, 5],
        "pk": 2,
        "embedding": [0.78, 0.91, 0.23]
    },
    {
        "tags": ["electronic", "dance"],
        "ratings": [3, 3, 4],
        "pk": 3,
        "embedding": [0.67, 0.45, 0.89]
    }
];

client.insert({
  collection_name: "my_array_collection",
  data: data,
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "data": [
        {
        "tags": ["pop", "rock", "classic"],
        "ratings": [5, 4, 3],
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "tags": ["jazz", "blues"],
        "ratings": [4, 5],
        "pk": 2,
        "embedding": [0.78, 0.91, 0.23]
    },
    {
        "tags": ["electronic", "dance"],
        "ratings": [3, 3, 4],
        "pk": 3,
        "embedding": [0.67, 0.45, 0.89]
    }       
    ],
    "collectionName": "my_array_collection"
}'

في هذا المثال

  • يتضمن كل إدخال بيانات حقلًا أساسيًا (pk)، بينما tags و ratings هما حقلا مصفوفة يستخدمان لتخزين العلامات والتقييمات.

  • embedding هو حقل متجه ثلاثي الأبعاد يستخدم لعمليات البحث عن التشابه المتجه.

البحث والاستعلام

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

تصفية الاستعلامات

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

filter = 'ratings[0] < 4'

res = client.query(
    collection_name="my_array_collection",
    filter=filter,
    output_fields=["tags", "ratings", "embedding"]
)

print(res)

# Output
# data: ["{'pk': 3, 'tags': ['electronic', 'dance'], 'ratings': [3, 3, 4], 'embedding': [np.float32(0.67), np.float32(0.45), np.float32(0.89)]}"] 

import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;

String filter = "ratings[0] < 4";
QueryResp resp = client.query(QueryReq.builder()
        .collectionName("my_array_collection")
        .filter(filter)
        .outputFields(Arrays.asList("tags", "ratings", "embedding"))
        .build());

System.out.println(resp.getQueryResults());

// Output
//
// [QueryResp.QueryResult(entity={ratings=[3, 3, 4], pk=3, embedding=[0.7, 0.8, 0.9], tags=[electronic, dance]})]

client.query({
    collection_name: 'my_array_collection',
    filter: 'ratings[0] < 4',
    output_fields: ['tags', 'ratings', 'embedding']
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_array_collection",
    "filter": "ratings[0] < 4",
    "outputFields": ["tags", "ratings", "embedding"]
}'
# {"code":0,"cost":0,"data":[{"embedding":[0.67,0.45,0.89],"pk":3,"ratings":{"Data":{"LongData":{"data":[3,3,4]}}},"tags":{"Data":{"StringData":{"data":["electronic","dance"]}}}}]}

في هذا الاستعلام، يقوم Milvus بتصفية الكيانات التي يكون فيها العنصر الأول من المصفوفة ratings أقل من 4، مع إرجاع الكيانات التي تطابق الشرط.

البحث المتجه مع تصفية المصفوفة

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

filter = 'tags[0] == "pop"'

res = client.search(
    collection_name="my_array_collection",
    data=[[0.3, -0.6, 0.1]],
    limit=5,
    search_params={"params": {"nprobe": 10}},
    output_fields=["tags", "ratings", "embedding"],
    filter=filter
)

print(res)

# Output
# data: ["[{'id': 1, 'distance': 1.1276001930236816, 'entity': {'ratings': [5, 4, 3], 'embedding': [0.11999999731779099, 0.3400000035762787, 0.5600000023841858], 'tags': ['pop', 'rock', 'classic']}}]"]

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

String filter = "tags[0] == \"pop\"";
SearchResp resp = client.search(SearchReq.builder()
        .collectionName("my_array_collection")
        .annsField("embedding")
        .data(Collections.singletonList(new FloatVec(new float[]{0.3f, -0.6f, 0.1f})))
        .topK(5)
        .outputFields(Arrays.asList("tags", "ratings", "embedding"))
        .filter(filter)
        .build());

System.out.println(resp.getSearchResults());

// Output
//
// [[SearchResp.SearchResult(entity={ratings=[5, 4, 3], embedding=[0.1, 0.2, 0.3], tags=[pop, rock, classic]}, score=-0.2364331, id=1)]]

client.search({
    collection_name: 'my_array_collection',
    data: [0.3, -0.6, 0.1],
    limit: 5,
    output_fields: ['tags', 'ratings', 'embdding'],
    filter: 'tags[0] == "pop"'
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_array_collection",
    "data": [
        [0.3, -0.6, 0.1]
    ],
    "annsField": "embedding",
    "limit": 5,
    "filter": "tags[0] == \"pop\"",
    "outputFields": ["tags", "ratings", "embedding"]
}'

# {"code":0,"cost":0,"data":[{"distance":-0.24793813,"embedding":[0.12,0.34,0.56],"id":1,"ratings":{"Data":{"LongData":{"data":[5,4,3]}}},"tags":{"Data":{"StringData":{"data":["pop","rock","classic"]}}}}]}

في هذا المثال، يقوم Milvus بإرجاع أفضل 5 كيانات الأكثر تشابهًا مع متجه الاستعلام، حيث يكون العنصر الأول في مصفوفة tags هو "pop".

بالإضافة إلى ذلك، يدعم ميلفوس عوامل تصفية المصفوفات المتقدمة مثل ARRAY_CONTAINS و ARRAY_CONTAINS_ALL و ARRAY_CONTAINS_ANY و ARRAY_LENGTH لتعزيز قدرات الاستعلام. لمزيد من التفاصيل، راجع تصفية البيانات الوصفية.

الحدود

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

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

  • التعامل مع السلسلة: يتم تخزين قيم السلسلة في حقول المصفوفات كما هي، دون هروب دلالي أو تحويل. على سبيل المثال، يتم تخزين 'a"b' و "a'b" و 'a\'b' و "a\"b" كما تم إدخالها، بينما 'a'b' و "a"b" تعتبر قيمًا غير صالحة.

جرب Managed Milvus مجاناً

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

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

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