milvus-logo
LFAI
Home
  • Guia do utilizador

Campo de matriz

O tipo Array é utilizado para armazenar campos que contêm vários valores do mesmo tipo de dados. Proporciona uma forma flexível de armazenar atributos com vários elementos, tornando-o especialmente útil em cenários em que é necessário guardar um conjunto de dados relacionados. No Milvus, é possível armazenar campos Array juntamente com dados vectoriais, permitindo requisitos de consulta e filtragem mais complexos.

Por exemplo, num sistema de recomendação de música, um campo Array pode armazenar uma lista de etiquetas para uma canção; na análise do comportamento do utilizador, pode armazenar as classificações dos utilizadores para as canções. Abaixo está um exemplo de um campo Array típico.

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

Neste exemplo, tags e ratings são ambos campos de matriz. O campo tags é uma matriz de cadeias de caracteres que representa géneros de música como pop, rock e clássico, enquanto o campo ratings é uma matriz de números inteiros que representa as classificações dos utilizadores para a música, variando de 1 a 5. Estes campos de matriz fornecem uma forma flexível de armazenar dados com vários valores, facilitando a realização de análises detalhadas durante as consultas e a filtragem.

Adicionar um campo Array

Para utilizar campos Array no Milvus, defina o tipo de campo relevante ao criar o esquema da coleção. Este processo inclui.

  1. Definir datatype como o tipo de dados Array suportado, ARRAY.

  2. Utilizar o parâmetro element_type para especificar o tipo de dados dos elementos da matriz. Pode ser qualquer tipo de dados escalar suportado pelo Milvus, como VARCHAR ou INT64. Todos os elementos do mesmo Array têm de ter o mesmo tipo de dados.

  3. Utilizar o parâmetro max_capacity para definir a capacidade máxima do array, ou seja, o número máximo de elementos que pode conter.

Eis como definir um esquema de coleção que inclui campos Array.

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

Neste exemplo.

  • tags é uma matriz de cadeia de caracteres com element_type definido como VARCHAR, indicando que os elementos da matriz devem ser cadeias de caracteres. max_capacity está definido como 10, o que significa que a matriz pode conter até 10 elementos.

  • ratings é uma matriz de inteiros com element_type definido para INT64, indicando que os elementos têm de ser inteiros. max_capacity está definido para 5, permitindo um máximo de 5 classificações.

  • Também adicionamos um campo de chave primária pk e um campo vetorial embedding.

O campo primário e o campo vetorial são obrigatórios quando se cria uma coleção. O campo primário identifica exclusivamente cada entidade, enquanto o campo vetorial é crucial para a pesquisa por semelhança. Para obter mais detalhes, consulte Campo primário e AutoID, Vetor denso, Vetor binário ou Vetor esparso.

Definir parâmetros de índice

A definição de parâmetros de índice para campos Array é opcional, mas pode melhorar significativamente a eficiência da recuperação.

No exemplo a seguir, criamos um AUTOINDEX para o campo tags, o que significa que o Milvus criará automaticamente um índice escalar apropriado com base no tipo de dados.

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

Para além de AUTOINDEX, pode especificar outros tipos de índices escalares como INVERTED ou BITMAP. Para tipos de índice suportados, consulte Índices escalares.

Além disso, você deve criar um índice para o campo de vetor antes de criar a coleção. Neste exemplo, usamos AUTOINDEX para simplificar a configuração do índice de vetor.

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

Criar coleção

Utilize o esquema definido e os parâmetros de índice para criar uma coleção.

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

Inserir dados

Depois de criar a coleção, pode inserir dados que incluam campos Array.

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

Neste exemplo.

  • Cada entrada de dados inclui um campo primário (pk), enquanto tags e ratings são campos Array usados para armazenar tags e classificações.

  • embedding é um campo vetorial tridimensional utilizado para pesquisas de semelhança vetorial.

Pesquisa e consulta

Os campos de matriz permitem a filtragem escalar durante as pesquisas, melhorando as capacidades de pesquisa vetorial do Milvus. Pode efetuar consultas com base nas propriedades dos campos Array juntamente com as pesquisas de semelhança de vectores.

Filtrar consultas

Pode filtrar dados com base nas propriedades dos campos Array, como aceder a um elemento específico ou verificar se um elemento do array cumpre uma determinada condição.

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

Nesta consulta, o Milvus filtra as entidades em que o primeiro elemento da matriz ratings é inferior a 4, devolvendo as entidades que correspondem à condição.

Pesquisa vetorial com filtragem de matrizes

Ao combinar a semelhança de vectores com a filtragem de matrizes, pode garantir que os dados recuperados não são apenas semelhantes em termos de semântica, mas também cumprem condições específicas, tornando os resultados da pesquisa mais precisos e alinhados com as necessidades empresariais.

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

Neste exemplo, o Milvus devolve as 5 principais entidades mais semelhantes ao vetor de consulta, sendo o primeiro elemento da matriz tags "pop" .

Além disso, o Milvus suporta operadores avançados de filtragem de matrizes como ARRAY_CONTAINS, ARRAY_CONTAINS_ALL, ARRAY_CONTAINS_ANY e ARRAY_LENGTH para melhorar ainda mais as capacidades de consulta. Para obter mais detalhes, consulte Filtragem de metadados.

Limites

  • Tipo de dados: Todos os elementos de um campo Array devem ter o mesmo tipo de dados, conforme especificado pelo element_type.

  • Capacidade da matriz: O número de elementos num campo Matriz tem de ser inferior ou igual à capacidade máxima definida quando a Matriz foi criada, conforme especificado em max_capacity.

  • Tratamento de cadeias de caracteres: Os valores de cadeia de caracteres em campos de matriz são armazenados como estão, sem escape semântico ou conversão. Por exemplo, 'a"b', "a'b", 'a\'b', e "a\"b" são armazenados como introduzidos, enquanto 'a'b' e "a"b" são considerados valores inválidos.

Traduzido porDeepLogo

Try Managed Milvus for Free

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

Get Started
Feedback

Esta página foi útil?