Milvus
Zilliz
Home
  • Guia do utilizador
  • Home
  • Docs
  • Guia do utilizador

  • Esquema e campos de dados

  • Campo dinâmico

Campo dinâmico

O Milvus permite-lhe inserir entidades com estruturas flexíveis e evolutivas através de uma funcionalidade especial designada por campo dinâmico. Este campo é implementado como um campo JSON oculto chamado $meta, que armazena automaticamente quaisquer campos nos seus dados que não estejam explicitamente definidos no esquema da coleção.

Como funciona

Quando o campo dinâmico está ativado, o Milvus adiciona um campo $meta oculto a cada entidade. Este campo é do tipo JSON, o que significa que pode armazenar qualquer estrutura de dados compatível com JSON e pode ser indexado utilizando a sintaxe de caminho JSON.

Durante a inserção de dados, qualquer campo não declarado no esquema é automaticamente armazenado como um par chave-valor dentro deste campo dinâmico.

Não é necessário gerir o $meta manualmente - o Milvus trata-o de forma transparente.

Por exemplo, se o esquema da coleção definir apenas id e vector, e inserir a seguinte entidade:

{
  "id": 1,
  "vector": [0.1, 0.2, 0.3],
  "name": "Item A",    // Not in schema
  "category": "books"  // Not in schema
}

Com a funcionalidade de campo dinâmico activada, o Milvus armazena-a internamente como:

{
  "id": 1,
  "vector": [0.1, 0.2, 0.3],
  "$meta": {
    "name": "Item A",
    "category": "books"
  }
}

Isto permite-lhe evoluir a sua estrutura de dados sem alterar o esquema.

Casos de uso comuns incluem:

  • Armazenamento de campos opcionais ou de recuperação pouco frequente

  • Capturar metadados que variam consoante a entidade

  • Suporte de filtragem flexível através de índices em chaves de campo dinâmicas específicas

Tipos de dados suportados

O campo dinâmico suporta todos os tipos de dados escalares fornecidos pelo Milvus, incluindo valores simples e complexos. Estes tipos de dados aplicam-se aos **valores das chaves armazenadas em $meta.

Os tipos suportados incluem:

  • String (VARCHAR)

  • Inteiro (INT8, INT32, INT64)

  • Ponto flutuante (FLOAT, DOUBLE)

  • Booleano (BOOL)

  • Matriz de valores escalares (ARRAY)

  • Objectos JSON (JSON)

Exemplo:

{
  "brand": "Acme",
  "price": 29.99,
  "in_stock": true,
  "tags": ["new", "hot"],
  "specs": {
    "weight": "1.2kg",
    "dimensions": { "width": 10, "height": 20 }
  }
}

Cada uma das chaves e valores acima seria armazenada no campo $meta.

Ativar o campo dinâmico

Para utilizar a funcionalidade de campo dinâmico, defina enable_dynamic_field=True ao criar o esquema de coleção:

from pymilvus import MilvusClient, DataType

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

# Create schema with dynamic field enabled
schema = client.create_schema(
    auto_id=False,
    enable_dynamic_field=True,
)

# Add explicitly defined fields
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)

# Create the collection
client.create_collection(
    collection_name="my_collection",
    schema=schema
)
import io.milvus.v2.client.*;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.collection.request.AddFieldReq;

ConnectConfig config = ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build();
MilvusClientV2 client = new MilvusClientV2(config);

CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder()
        .enableDynamicField(true)
        .build();
schema.addField(AddFieldReq.builder()
        .fieldName("my_id")
        .dataType(DataType.Int64)
        .isPrimaryKey(Boolean.TRUE)
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("my_vector")
        .dataType(DataType.FloatVector)
        .dimension(5)
        .build());

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_collection")
        .collectionSchema(schema)
        .build();
client.createCollection(requestCreate);
import { MilvusClient, DataType, CreateCollectionReq } from '@zilliz/milvus2-sdk-node';

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

// Create collection
const res = await client.createCollection({
  collection_name: 'my_collection',
  schema:  [
      {
        name: 'my_id',
        data_type: DataType.Int64,
        is_primary_key: true,
        autoID: false,
      },
      {
        name: 'my_vector',
        data_type: DataType.FloatVector,
        type_params: {
          dim: '5',
      }
   ],
   enable_dynamic_field: true
});

import (
    "context"

    "github.com/milvus-io/milvus/client/v2/entity"
    "github.com/milvus-io/milvus/client/v2/milvusclient"
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
    Address: "localhost:19530",
})
if err != nil {
    return err
}

schema := entity.NewSchema().WithDynamicFieldEnabled(true)
schema.WithField(entity.NewField().
    WithName("my_id").pk
    WithDataType(entity.FieldTypeInt64).
    WithIsPrimaryKey(true),
).WithField(entity.NewField().
    WithName("my_vector").
    WithDataType(entity.FieldTypeFloatVector).
    WithDim(5),
)

err = client.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("my_collection", schema))
if err != nil {
    return err
}
# restful
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"

export myIdField='{
  "fieldName": "my_id",
  "dataType": "Int64",
  "isPrimary": true,
  "autoID": false
}'

export myVectorField='{
  "fieldName": "my_vector",
  "dataType": "FloatVector",
  "elementTypeParams": {
    "dim": 5
  }
}'

export schema="{
  \"autoID\": false,
  \"enableDynamicField\": true,
  \"fields\": [
    $myIdField,
    $myVectorField
  ]
}"

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

Inserir entidades na coleção

O campo dinâmico permite-lhe inserir campos extra não definidos no esquema. Estes campos serão armazenados automaticamente em $meta.

entities = [
    {
        "my_id": 1, # Explicitly defined primary field
        "my_vector": [0.1, 0.2, 0.3, 0.4, 0.5], # Explicitly defined vector field
        "overview": "Great product",       # Scalar key not defined in schema
        "words": 150,                      # Scalar key not defined in schema
        "dynamic_json": {                  # JSON key not defined in schema
            "varchar": "some text",
            "nested": {
                "value": 42.5
            },
            "string_price": "99.99"        # Number stored as string
        }
    }
]

client.insert(collection_name="my_collection", data=entities)
import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.service.vector.request.InsertReq;

Gson gson = new Gson();
JsonObject row = new JsonObject();
row.addProperty("my_id", 1);
row.add("my_vector", gson.toJsonTree(Arrays.asList(0.1, 0.2, 0.3, 0.4, 0.5)));
row.addProperty("overview", "Great product");
row.addProperty("words", 150);

JsonObject dynamic = new JsonObject();
dynamic.addProperty("varchar", "some text");
dynamic.addProperty("string_price", "99.99");

JsonObject nested = new JsonObject();
nested.addProperty("value", 42.5);

dynamic.add("nested", nested);
row.add("dynamic_json", dynamic);

client.insert(InsertReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(row))
        .build());

const entities = [
  {
    my_id: 1,
    my_vector: [0.1, 0.2, 0.3, 0.4, 0.5],
    overview: 'Great product',
    words: 150,
    dynamic_json: {
      varchar: 'some text',
      nested: {
        value: 42.5,
      },
      string_price: '99.99',
    },
  },
];
const res = await client.insert({
    collection_name: 'my_collection',
    data: entities,
});
_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
    WithInt64Column("my_id", []int64{1}).
    WithFloatVectorColumn("my_vector", 5, [][]float32{
        {0.1, 0.2, 0.3, 0.4, 0.5},
    }).WithColumns(
    column.NewColumnVarChar("overview", []string{"Great product"}),
    column.NewColumnInt32("words", []int32{150}),
    column.NewColumnJSONBytes("dynamic_json", [][]byte{
        []byte(`{
            varchar: 'some text',
            nested: {
                value: 42.5,
            },
            string_price: '99.99',
        }`),
    }),
))
if err != nil {
    return err
}
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data '{
  "data": [
    {
      "my_id": 1,
      "my_vector": [0.1, 0.2, 0.3, 0.4, 0.5],
      "overview": "Great product",
      "words": 150,
      "dynamic_json": {
        "varchar": "some text",
        "nested": {
          "value": 42.5
        },
        "string_price": "99.99"
      }
    }
  ],
  "collectionName": "my_collection"
}'

Chaves de índice no campo dinâmicoCompatible with Milvus 2.5.11+

O Milvus permite-lhe utilizar a indexação de caminhos JSON para criar índices em chaves específicas dentro do campo dinâmico. Estes podem ser valores escalares ou valores aninhados em objectos JSON.

A indexação das chaves do campo dinâmico é opcional. Ainda é possível consultar ou filtrar por chaves de campo dinâmico sem um índice, mas isso pode resultar num desempenho mais lento devido à pesquisa de força bruta.

Sintaxe de indexação de caminho JSON

Para criar um índice de caminho JSON, especifique:

  • Caminho JSON (json_path): O caminho para a chave ou o campo aninhado no seu objeto JSON que pretende indexar.

    • Exemplo: metadata["category"]

      Isso define onde o mecanismo de indexação deve procurar dentro da estrutura JSON.

  • JSON cast type (json_cast_type): O tipo de dados que o Milvus deve utilizar ao interpretar e indexar o valor no caminho especificado.

    • Este tipo deve corresponder ao tipo de dados real do campo que está a ser indexado.

    • Para obter uma lista completa, consulte Tipos de elenco JSON suportados.

Usar o caminho JSON para indexar chaves de campo dinâmico

Como o campo dinâmico é um campo JSON, você pode indexar qualquer chave dentro dele usando a sintaxe de caminho JSON. Isso funciona tanto para valores escalares simples quanto para estruturas aninhadas complexas.

Exemplos de caminho JSON:

  • Para chaves simples: overview, words

  • Para chaves aninhadas: dynamic_json['varchar'], dynamic_json['nested']['value']

index_params = client.prepare_index_params()

# Index a simple string key
index_params.add_index(
    field_name="overview",  # Key name in the dynamic field
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="overview_index",  # Unique index name
    params={
        "json_cast_type": "varchar",   # Data type that Milvus uses when indexing the values
        "json_path": "overview"        # JSON path to the key
    }
)

# Index a simple numeric key
index_params.add_index(
    field_name="words",  # Key name in the dynamic field
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="words_index",  # Unique index name
    params={
        "json_cast_type": "double",  # Data type that Milvus uses when indexing the values
        "json_path": "words" # JSON path to the key
    }
)

# Index a nested key within a JSON object
index_params.add_index(
    field_name="dynamic_json", # JSON key name in the dynamic field
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="json_varchar_index", # Unique index name
    params={
        "json_cast_type": "varchar", # Data type that Milvus uses when indexing the values
        "json_path": "dynamic_json['varchar']" # JSON path to the nested key
    }
)

# Index a deeply nested key
index_params.add_index(
    field_name="dynamic_json",
    index_type="AUTOINDEX", # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="json_nested_index", # Unique index name
    params={
        "json_cast_type": "double",
        "json_path": "dynamic_json['nested']['value']"
    }
)
import io.milvus.v2.common.IndexParam;

Map<String,Object> extraParams1 = new HashMap<>();
extraParams1.put("json_path", "overview");
extraParams1.put("json_cast_type", "varchar");
indexParams.add(IndexParam.builder()
        .fieldName("overview")
        .indexName("overview_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams1)
        .build());

Map<String,Object> extraParams2 = new HashMap<>();
extraParams2.put("json_path", "words");
extraParams2.put("json_cast_type", "double");
indexParams.add(IndexParam.builder()
        .fieldName("words")
        .indexName("words_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams2)
        .build());

Map<String,Object> extraParams3 = new HashMap<>();
extraParams3.put("json_path", "dynamic_json['varchar']");
extraParams3.put("json_cast_type", "varchar");
indexParams.add(IndexParam.builder()
        .fieldName("dynamic_json")
        .indexName("json_varchar_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams3)
        .build());

Map<String,Object> extraParams4 = new HashMap<>();
extraParams4.put("json_path", "dynamic_json['nested']['value']");
extraParams4.put("json_cast_type", "double");
indexParams.add(IndexParam.builder()
        .fieldName("dynamic_json")
        .indexName("json_nested_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams4)
        .build());
const indexParams = [
    {
      collection_name: 'my_collection',
      field_name: 'overview',
      index_name: 'overview_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_path: 'overview',
        json_cast_type: 'varchar',
      },
    },
    {
      collection_name: 'my_collection',
      field_name: 'words',
      index_name: 'words_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_path: 'words',
        json_cast_type: 'double',
      },
    },
    {
      collection_name: 'my_collection',
      field_name: 'dynamic_json',
      index_name: 'json_varchar_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_cast_type: 'varchar',
        json_path: "dynamic_json['varchar']",
      },
    },
    {
      collection_name: 'my_collection',
      field_name: 'dynamic_json',
      index_name: 'json_nested_index',
      index_type: 'AUTOINDEX',
      metric_type: 'NONE',
      params: {
        json_cast_type: 'double',
        json_path: "dynamic_json['nested']['value']",
      },
    },
  ];
import (
    "github.com/milvus-io/milvus/client/v2/index"
)

jsonIndex1 := index.NewJSONPathIndex(index.AUTOINDEX, "varchar", "overview")
    .WithIndexName("overview_index")
jsonIndex2 := index.NewJSONPathIndex(index.AUTOINDEX, "double", "words")
    .WithIndexName("words_index")
jsonIndex3 := index.NewJSONPathIndex(index.AUTOINDEX, "varchar", `dynamic_json['varchar']`)
    .WithIndexName("json_varchar_index")
jsonIndex4 := index.NewJSONPathIndex(index.AUTOINDEX, "double", `dynamic_json['nested']['value']`)
    .WithIndexName("json_nested_index")

indexOpt1 := milvusclient.NewCreateIndexOption("my_collection", "overview", jsonIndex1)
indexOpt2 := milvusclient.NewCreateIndexOption("my_collection", "words", jsonIndex2)
indexOpt3 := milvusclient.NewCreateIndexOption("my_collection", "dynamic_json", jsonIndex3)
indexOpt4 := milvusclient.NewCreateIndexOption("my_collection", "dynamic_json", jsonIndex4)
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"

export overviewIndex='{
  "fieldName": "dynamic_json",
  "indexName": "overview_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "varchar",
    "json_path": "dynamic_json[\"overview\"]"
  }
}'

export wordsIndex='{
  "fieldName": "dynamic_json",
  "indexName": "words_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "double",
    "json_path": "dynamic_json[\"words\"]"
  }
}'

export varcharIndex='{
  "fieldName": "dynamic_json",
  "indexName": "json_varchar_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "varchar",
    "json_path": "dynamic_json[\"varchar\"]"
  }
}'

export nestedIndex='{
  "fieldName": "dynamic_json",
  "indexName": "json_nested_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_cast_type": "double",
          "json_path": "dynamic_json[\"nested\"][\"value\"]"
    }
  }'

Utilizar funções de conversão JSON para conversão de tiposCompatible with Milvus 2.5.14+

Se uma chave de campo dinâmico contiver valores num formato incorreto (por exemplo, números armazenados como cadeias de caracteres), pode utilizar uma função de conversão para o converter:

# Convert a string to double before indexing
index_params.add_index(
    field_name="dynamic_json", # JSON key name
    index_type="AUTOINDEX",
    index_name="json_string_price_index",
    params={
        "json_path": "dynamic_json['string_price']",
        "json_cast_type": "double", # Must be the output type of the cast function
        "json_cast_function": "STRING_TO_DOUBLE" # Case insensitive; convert string to double
    }
)
Map<String,Object> extraParams5 = new HashMap<>();
extraParams5.put("json_path", "dynamic_json['string_price']");
extraParams5.put("json_cast_type", "double");
indexParams.add(IndexParam.builder()
        .fieldName("dynamic_json")
        .indexName("json_string_price_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .extraParams(extraParams5)
        .build());
indexParams.push({
    collection_name: 'my_collection',
    field_name: 'dynamic_json',
    index_name: 'json_string_price_index',
    index_type: 'AUTOINDEX',
    metric_type: 'NONE',
    params: {
      json_path: "dynamic_json['string_price']",
      json_cast_type: 'double',
      json_cast_function: 'STRING_TO_DOUBLE',
    },
  });
jsonIndex5 := index.NewJSONPathIndex(index.AUTOINDEX, "double", `dynamic_json['string_price']`)
    .WithIndexName("json_string_price_index")
indexOpt5 := milvusclient.NewCreateIndexOption("my_collection", "dynamic_json", jsonIndex5)
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"

export stringPriceIndex='{
  "fieldName": "dynamic_json",
  "indexName": "json_string_price_index",
  "params": {
    "index_type": "AUTOINDEX",
    "json_path": "dynamic_json[\"string_price\"]",
    "json_cast_type": "double",
    "json_cast_function": "STRING_TO_DOUBLE"
  }
}'

  • Se a conversão de tipo falhar (por exemplo, o valor "not_a_number" não pode ser convertido num número), o valor é ignorado e desindexado.

  • Para obter detalhes sobre os parâmetros da função de conversão, consulte Campo JSON.

Aplicar índices à coleção

Depois de definir os parâmetros de índice, pode aplicá-los à coleção utilizando create_index():

client.create_index(
    collection_name="my_collection",
    index_params=index_params
)
import io.milvus.v2.service.index.request.CreateIndexReq;

client.createIndex(CreateIndexReq.builder()
        .collectionName("my_collection")
        .indexParams(indexParams)
        .build());
  await client.createIndex(indexParams);
indexTask1, err := client.CreateIndex(ctx, indexOpt1)
if err != nil {
    return err
}
indexTask2, err := client.CreateIndex(ctx, indexOpt2)
if err != nil {
    return err
}
indexTask3, err := client.CreateIndex(ctx, indexOpt3)
if err != nil {
    return err
}
indexTask4, err := client.CreateIndex(ctx, indexOpt4)
if err != nil {
    return err
}
indexTask5, err := client.CreateIndex(ctx, indexOpt5)
if err != nil {
    return err
}
# restful
export indexParams="[
  $varcharIndex,
  $nestedIndex,
  $overviewIndex,
  $wordsIndex,
  $stringPriceIndex
]"

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
  \"collectionName\": \"my_collection\",
  \"indexParams\": $indexParams
}"

Filtrar por chaves de campo dinâmicas

Depois de inserir entidades com chaves de campo dinâmicas, pode filtrá-las utilizando expressões de filtro padrão.

  • Para chaves não JSON (por exemplo, strings, números, booleanos), pode referenciá-las diretamente pelo nome da chave.

  • Para chaves que armazenam objetos JSON, use a sintaxe de caminho JSON para acessar valores aninhados.

Com base na entidade de exemplo da secção anterior, as expressões de filtro válidas incluem:

filter = 'overview == "Great product"'                # Non-JSON key
filter = 'words >= 100'                               # Non-JSON key
filter = 'dynamic_json["nested"]["value"] < 50'       # JSON object key
String filter = 'overview == "Great product"';
String filter = 'words >= 100';
String filter = 'dynamic_json["nested"]["value"] < 50';
filter = 'overview == "Great product"'                // Non-JSON key
filter = 'words >= 100'                               // Non-JSON key
filter = 'dynamic_json["nested"]["value"] < 50'       // JSON object key
filter := 'overview == "Great product"'
filter := 'words >= 100'
filter := 'dynamic_json["nested"]["value"] < 50'
# restful
export filterOverview='overview == "Great product"'
export filterWords='words >= 100'
export filterNestedValue='dynamic_json["nested"]["value"] < 50'

Recuperando chaves de campo dinâmicas: Para retornar chaves de campo dinâmicas nos resultados de pesquisa ou consulta, é necessário especificá-las explicitamente no parâmetro output_fields usando a mesma sintaxe de caminho JSON da filtragem:

# Example: Include dynamic field keys in search results
results = client.search(
    collection_name="my_collection",
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],
    filter=filter,                         # Filter expression defined earlier
    limit=10,
    output_fields=[
        "overview",                        # Simple dynamic field key
        'dynamic_json["varchar"]'          # Nested JSON key
    ]
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.SearchReq
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("YOUR_CLUSTER_ENDPOINT")
        .token("YOUR_CLUSTER_TOKEN")
        .build());

FloatVec queryVector = new FloatVec(new float[]{0.1, 0.2, 0.3, 0.4, 0.5});
SearchReq searchReq = SearchReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(queryVector))
        .topK(5)
        .filter(filter)
        .outputFields(Arrays.asList("overview", "dynamic_json['varchar']"))
        .build();

SearchResp searchResp = client.search(searchReq);
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";

const address = "YOUR_CLUSTER_ENDPOINT";
const token = "YOUR_CLUSTER_TOKEN";
const client = new MilvusClient({address, token});

const query_vector = [0.1, 0.2, 0.3, 0.4, 0.5]

const res = await client.search({
    collection_name: "my_collection",
    data: [query_vector],
    limit: 5,
    filters: filter,
    output_fields: ["overview", "dynamic_json['varchar']"]
})
import (
    "context"
    "fmt"

    "github.com/milvus-io/milvus/client/v2/entity"
    "github.com/milvus-io/milvus/client/v2/milvusclient"
)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

milvusAddr := "YOUR_CLUSTER_ENDPOINT"
token := "YOUR_CLUSTER_TOKEN"

client, err := client.New(ctx, &client.ClientConfig{
    Address: milvusAddr,
    APIKey:  token,
})
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
defer client.Close(ctx)

queryVector := []float32{0.1, 0.2, 0.3, 0.4, 0.5}

resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "my_collection", // collectionName
    5,               // limit
    []entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
    WithANNSField("my_vector").
    WithFilter(filter).
    WithOutputFields("overview", "dynamic_json['varchar']"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
export CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
export FILTER='color like "red%" and likes > 50'

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
  \"collectionName\": \"my_collection\",
  \"data\": [
    [0.1, 0.2, 0.3, 0.4, 0.5]
  ],
  \"annsField\": \"my_vector\",
  \"filter\": \"${FILTER}\",
  \"limit\": 5,
  \"outputFields\": [\"overview\", \"dynamic_json.varchar\"]
}"

As chaves de campo dinâmicas não são incluídas nos resultados por padrão e devem ser solicitadas explicitamente.

Para obter uma lista completa de operadores e expressões de filtro compatíveis, consulte Pesquisa filtrada.

Colocar tudo junto

Até agora, você aprendeu a usar o campo dinâmico para armazenar e indexar de forma flexível chaves que não estão definidas no esquema. Uma vez inserida uma chave de campo dinâmico, pode utilizá-la como qualquer outro campo em expressões de filtro, sem necessidade de sintaxe especial.

Para concluir o fluxo de trabalho numa aplicação do mundo real, também é necessário:

PERGUNTAS FREQUENTES

Quando é que devo definir um campo explicitamente no esquema em vez de utilizar uma chave de campo dinâmica?

Deve definir um campo explicitamente no esquema em vez de utilizar uma chave de campo dinâmica quando:

  • O campo é frequentemente incluído em output_fields: Apenas os campos definidos explicitamente são garantidamente recuperáveis de forma eficiente através de output_fields. As chaves de campo dinâmicas não são optimizadas para recuperação de alta frequência e podem incorrer em custos adicionais de desempenho.

  • O campo é acedido ou filtrado frequentemente: Embora a indexação de uma chave de campo dinâmica possa proporcionar um desempenho de filtragem semelhante ao dos campos de esquema fixo, os campos explicitamente definidos oferecem uma estrutura mais clara e uma melhor manutenção.

  • É necessário um controlo total sobre o comportamento do campo: Os campos explícitos suportam restrições ao nível do esquema, validações e digitação mais clara, o que pode ser útil para gerir a integridade e consistência dos dados.

  • Você quer evitar inconsistências de indexação: Os dados em chaves de campo dinâmicas são mais propensos a inconsistências no tipo ou na estrutura. A utilização de um esquema fixo ajuda a garantir a qualidade dos dados, especialmente se planear utilizar indexação ou casting.

Posso criar vários índices na mesma chave de campo dinâmica com diferentes tipos de dados?

Não, você pode criar apenas um índice por caminho JSON. Mesmo que uma chave de campo dinâmico contenha valores de tipo misto (por exemplo, algumas cadeias de caracteres e alguns números), deve escolher um único json_cast_type ao indexar esse caminho. De momento, não são suportados vários índices na mesma chave com tipos diferentes.

Ao indexar uma chave de campo dinâmica, o que acontece se a conversão de dados falhar?

Se tiver criado um índice numa chave de campo dinâmico e a conversão de dados falhar - por exemplo, um valor destinado a ser convertido para double é uma cadeia de caracteres não numérica como "abc"- esses valores específicos serão ignorados silenciosamente durante a criação do índice. Eles não aparecerão no índice e, portanto, não serão retornados na pesquisa baseada em filtro ou nos resultados da consulta que dependem do índice.

Isto tem algumas implicações importantes:

  • Nenhum fallback para varredura completa: Se a maioria das entidades for indexada com êxito, as consultas de filtragem dependerão inteiramente do índice. As entidades com falhas de fundição serão excluídas do conjunto de resultados - mesmo que correspondam logicamente à condição do filtro.

  • Risco de precisão da pesquisa: Em grandes conjuntos de dados onde a qualidade dos dados é inconsistente (especialmente em chaves de campo dinâmicas), este comportamento pode levar a resultados inesperados em falta. É fundamental garantir uma formatação de dados consistente e válida antes da indexação.

  • Use funções de conversão com cautela: Se utilizar uma json_cast_function para converter cadeias de caracteres em números durante a indexação, certifique-se de que os valores das cadeias de caracteres são convertíveis de forma fiável. Uma incompatibilidade entre json_cast_type e o tipo convertido real resultará em erros ou entradas ignoradas.

O que acontece se a minha consulta utilizar um tipo de dados diferente do tipo de conversão indexado?

Se a sua consulta comparar uma chave de campo dinâmica utilizando um tipo de dados diferente do que foi utilizado no índice (por exemplo, uma consulta com uma comparação de cadeias de caracteres quando o índice foi convertido para double), o sistema não utilizará o índice e poderá voltar a uma pesquisa completa apenas se possível. Para obter o melhor desempenho e precisão, certifique-se de que o seu tipo de consulta corresponde ao json_cast_type utilizado durante a criação do índice.

Try Managed Milvus for Free

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

Get Started
Feedback

Esta página foi útil?