milvus-logo
LFAI
Home
  • Benutzerhandbuch

Array-Feld

Der Typ Array wird verwendet, um Felder zu speichern, die mehrere Werte desselben Datentyps enthalten. Er bietet eine flexible Möglichkeit, Attribute mit mehreren Elementen zu speichern, was ihn besonders in Szenarien nützlich macht, in denen eine Reihe von zusammenhängenden Daten gespeichert werden muss. In Milvus können Sie Array-Felder neben Vektordaten speichern, was komplexere Abfrage- und Filteranforderungen ermöglicht.

In einem Musikempfehlungssystem kann ein Array-Feld zum Beispiel eine Liste von Tags für einen Song speichern; in der Analyse des Benutzerverhaltens kann es Benutzerbewertungen für Songs speichern. Nachfolgend finden Sie ein Beispiel für ein typisches Array-Feld.

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

In diesem Beispiel sind tags und ratings beides Array-Felder. Das Feld tags ist ein String-Array, das Song-Genres wie Pop, Rock und Klassik repräsentiert, während das Feld ratings ein Integer-Array ist, das Benutzerbewertungen für den Song im Bereich von 1 bis 5 darstellt. Diese Array-Felder bieten eine flexible Möglichkeit, mehrwertige Daten zu speichern, was die Durchführung detaillierter Analysen bei Abfragen und Filterungen erleichtert.

Array-Feld hinzufügen

Um Array-Felder in Milvus zu verwenden, definieren Sie den entsprechenden Feldtyp beim Erstellen des Sammlungsschemas. Dieser Prozess beinhaltet.

  1. Einstellung von datatype auf den unterstützten Array-Datentyp ARRAY.

  2. Verwenden Sie den Parameter element_type, um den Datentyp der Elemente im Array anzugeben. Dies kann ein beliebiger skalarer Datentyp sein, der von Milvus unterstützt wird, z. B. VARCHAR oder INT64. Alle Elemente in einem Array müssen denselben Datentyp haben.

  3. Verwenden Sie den Parameter max_capacity, um die maximale Kapazität des Arrays zu definieren, d.h. die maximale Anzahl der Elemente, die es enthalten kann.

So definieren Sie ein Auflistungsschema, das Array-Felder enthält.

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)
# 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)
        .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": 100
    }
}'

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
    ]
}"

In diesem Beispiel.

  • tags ist ein String-Array, wobei element_type auf VARCHAR gesetzt ist, was bedeutet, dass die Elemente im Array Strings sein müssen. max_capacity ist auf 10 gesetzt, was bedeutet, dass das Array bis zu 10 Elemente enthalten kann.

  • ratings ist ein Integer-Array, bei dem element_type auf INT64 gesetzt ist, was bedeutet, dass die Elemente Integer sein müssen. max_capacity ist auf 5 gesetzt, was bedeutet, dass bis zu 5 Bewertungen möglich sind.

  • Wir fügen auch ein Primärschlüsselfeld pk und ein Vektorfeld embedding hinzu.

Das Primärfeld und das Vektorfeld sind obligatorisch, wenn Sie eine Sammlung erstellen. Das Primärfeld identifiziert jede Entität eindeutig, während das Vektorfeld für die Ähnlichkeitssuche entscheidend ist. Weitere Einzelheiten finden Sie unter Primärfeld & AutoID, Dense Vector, Binary Vector oder Sparse Vector.

Index-Parameter setzen

Das Setzen von Indexparametern für Array-Felder ist optional, kann aber die Abfrageeffizienz erheblich verbessern.

Im folgenden Beispiel erstellen wir einen AUTOINDEX für das Feld tags, was bedeutet, dass Milvus automatisch einen passenden skalaren Index basierend auf dem Datentyp erstellt.

# 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"
        }
    ]'

Zusätzlich zu AUTOINDEX können Sie andere skalare Indextypen wie INVERTED oder BITMAP angeben. Unterstützte Indextypen finden Sie unter Skalare Indizes.

Außerdem müssen Sie einen Index für das Vektorfeld erstellen, bevor Sie die Sammlung erstellen. In diesem Beispiel verwenden wir AUTOINDEX, um die Einrichtung des Vektorindex zu vereinfachen.

# 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"
        }
    ]'

Sammlung erstellen

Verwenden Sie die definierten Schema- und Indexparameter, um eine Sammlung zu erstellen.

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
}"

Daten einfügen

Nachdem Sie die Sammlung erstellt haben, können Sie Daten einfügen, die Array-Felder enthalten.

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"
}'

In diesem Beispiel.

  • Jeder Dateneintrag enthält ein Primärfeld (pk), während tags und ratings Array-Felder sind, die zum Speichern von Tags und Bewertungen verwendet werden.

  • embedding ist ein 3-dimensionales Vektorfeld, das für Vektorähnlichkeitssuchen verwendet wird.

Suche und Abfrage

Array-Felder ermöglichen eine skalare Filterung während der Suche und erweitern die Vektorsuchfunktionen von Milvus. Sie können Abfragen basierend auf den Eigenschaften von Array-Feldern neben Vektorähnlichkeitssuchen durchführen.

Filter-Abfragen

Sie können Daten auf der Grundlage von Eigenschaften von Array-Feldern filtern, z. B. auf ein bestimmtes Element zugreifen oder prüfen, ob ein Array-Element eine bestimmte Bedingung erfüllt.

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"]}}}}]}

In dieser Abfrage filtert Milvus Entitäten heraus, bei denen das erste Element des Arrays ratings kleiner als 4 ist, und gibt Entitäten zurück, die die Bedingung erfüllen.

Vektorsuche mit Array-Filterung

Durch die Kombination von Vektorähnlichkeit mit Array-Filterung können Sie sicherstellen, dass die abgerufenen Daten nicht nur in der Semantik ähnlich sind, sondern auch bestimmte Bedingungen erfüllen, wodurch die Suchergebnisse genauer werden und den Geschäftsanforderungen entsprechen.

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"]}}}}]}

In diesem Beispiel gibt Milvus die Top 5 Entitäten zurück, die dem Abfragevektor am ähnlichsten sind, wobei das erste Element des Arrays tags "pop" ist.

Darüber hinaus unterstützt Milvus erweiterte Array-Filteroperatoren wie ARRAY_CONTAINS, ARRAY_CONTAINS_ALL, ARRAY_CONTAINS_ANY und ARRAY_LENGTH, um die Abfragemöglichkeiten weiter zu verbessern. Weitere Details finden Sie unter Metadaten-Filterung.

Grenzwerte

  • Datentyp: Alle Elemente in einem Array-Feld müssen denselben Datentyp haben, wie in element_type angegeben.

  • Array-Kapazität: Die Anzahl der Elemente in einem Array-Feld muss kleiner oder gleich der maximalen Kapazität sein, die bei der Erstellung des Arrays festgelegt wurde, wie unter max_capacity angegeben.

  • String-Behandlung: String-Werte in Array-Feldern werden so gespeichert, wie sie sind, ohne semantisches Escaping oder Konvertierung. Zum Beispiel werden 'a"b', "a'b", 'a\'b' und "a\"b" wie eingegeben gespeichert, während 'a'b' und "a"b" als ungültige Werte betrachtet werden.

Übersetzt vonDeepL

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
Feedback

War diese Seite hilfreich?