Campo JSON

Un campo JSON es un campo escalar que almacena información adicional junto con incrustaciones vectoriales, en pares clave-valor. He aquí un ejemplo de cómo se almacenan los datos en formato JSON:

{
  "metadata": {
    "product_info": {
      "category": "electronics",
      "brand": "BrandA"
    },
    "price": 99.99,
    "in_stock": true,
    "tags": ["summer_sale", "clearance"]
  }
}

Límites

  • Tamaño del campo: El tamaño de los campos JSON está limitado a 65.536 bytes.

  • Diccionarios anidados: Los diccionarios anidados dentro de los valores de campo JSON se tratan como cadenas sin formato para su almacenamiento.

  • Valores por defecto: Los campos JSON no admiten valores por defecto. Sin embargo, puede establecer el atributo nullable en True para permitir valores nulos. Para más detalles, consulte Nullable & Default.

  • Comparación de tipos: si el valor clave de un campo JSON es un número entero o flotante, sólo puede compararse (mediante filtros de expresión) con otra clave numérica del mismo tipo.

  • Nomenclatura: Al nombrar claves JSON, se recomienda utilizar sólo letras, números y guiones bajos. El uso de otros caracteres puede causar problemas al filtrar o buscar.

  • Manejo de cadenas: Milvus almacena valores de cadena en campos JSON tal y como se introducen, sin conversión semántica. Por ejemplo:

    • 'a"b', "a'b", 'a\\'b', y "a\\"b" se almacenan tal cual.

    • 'a'b' y "a"b" se consideran inválidos.

  • Indexación JSON: Al indexar un campo JSON, puede especificar una o más rutas en el campo JSON para acelerar el filtrado. Cada ruta adicional aumenta la sobrecarga de indexación, por lo que debe planificar cuidadosamente su estrategia de indexación. Para más consideraciones sobre la indexación de un campo JSON, consulte Consideraciones sobre la indexación JSON.

Añadir campo JSON

Para añadir este campo JSON metadata al esquema de su colección, utilice DataType.JSON. El siguiente ejemplo define un campo JSON metadata que permite valores nulos:

# Import necessary libraries
from pymilvus import MilvusClient, DataType

# Define server address
SERVER_ADDR = "http://localhost:19530"

# Create a MilvusClient instance
client = MilvusClient(uri=SERVER_ADDR)

# Define the collection schema
schema = client.create_schema(
auto_id=False,
enable_dynamic_fields=True,
)

# Add a JSON field that supports null values
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)
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("metadata")
        .dataType(DataType.JSON)
        .isNullable(true)
        .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 (
    "context"
    "fmt"

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

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

milvusAddr := "localhost:19530"

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

schema := entity.NewSchema()
schema.WithField(entity.NewField().
    WithName("pk").
    WithDataType(entity.FieldTypeInt64).
    WithIsAutoID(true),
).WithField(entity.NewField().
    WithName("embedding").
    WithDataType(entity.FieldTypeFloatVector).
    WithDim(3),
).WithField(entity.NewField().
    WithName("metadata").
    WithDataType(entity.FieldTypeJSON),
)
import { MilvusClient, 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: "embedding",
    data_type: DataType.FloatVector,
    dim: 3,
  },
];
export jsonField='{
    "fieldName": "metadata",
    "dataType": "JSON"
}'

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

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

export schema="{
    \"autoID\": false,
    \"enableDynamicField\": true,
    \"fields\": [
        $jsonField,
        $pkField,
        $vectorField
    ]
}"
  • Defina enable_dynamic_fields=True si necesita insertar campos indefinidos adicionales en el futuro.

  • Utilice nullable=True para permitir objetos JSON nulos o que falten.

Establecer parámetros de índice

La indexación ayuda a Milvus a filtrar o buscar rápidamente en grandes volúmenes de datos. En Milvus, la indexación es

  • Obligatoria para campos vectoriales (para ejecutar eficientemente búsquedas de similitud).

  • Opcional para campos JSON (para acelerar los filtros escalares en rutas JSON específicas).

Indexar un campo JSONCompatible with Milvus 2.5.10+

Por defecto, los campos JSON no están indexados, por lo que cualquier consulta de filtro (por ejemplo, metadata["price"] < 100) debe escanear todas las filas. Si desea acelerar las consultas en rutas específicas dentro del campo metadata, puede crear un índice invertido en cada ruta que le interese.

En este ejemplo, crearemos dos índices sobre distintas rutas dentro del campo JSON metadata:

index_params = client.prepare_index_params()

# Example 1: Index the 'category' key inside 'product_info' as a string
index_params.add_index(
field_name="metadata", # JSON field name to index
index_type="INVERTED", # Index type. Set to INVERTED
index_name="json_index_1", # Index name
params={
"json_path": "metadata[\"product_info\"][\"category\"]", # Path in JSON field to index
"json_cast_type": "varchar" # Data type that the extracted JSON values will be cast to
}
)

# Example 2: Index 'price' as a numeric type (double)
index_params.add_index(
field_name="metadata",
index_type="INVERTED",
index_name="json_index_2",
params={
"json_path": "metadata[\"price\"]",
"json_cast_type": "double"
}
)
import io.milvus.v2.common.IndexParam;

List<IndexParam> indexes = new ArrayList<>();

Map<String,Object> extraParams_1 = new HashMap<>();
extraParams_1.put("json_path", "metadata[\"product_info\"][\"category\"]");
extraParams_1.put("json_cast_type", "varchar");
indexes.add(IndexParam.builder()
        .fieldName("metadata")
        .indexName("json_index_1")
        .indexType(IndexParam.IndexType.INVERTED)
        .extraParams(extraParams_1)
        .build());

Map<String,Object> extraParams_2 = new HashMap<>();
extraParams_2.put("json_path", "metadata[\"price\"]");
extraParams_2.put("json_cast_type", "double");
indexes.add(IndexParam.builder()
        .fieldName("metadata")
        .indexName("json_index_2")
        .indexType(IndexParam.IndexType.INVERTED)
        .extraParams(extraParams_2)
        .build());
jsonIndex1 := index.NewJSONPathIndex(index.Inverted, "varchar", `metadata["product_info"]["category"]`)
jsonIndex2 := index.NewJSONPathIndex(index.Inverted, "double", `metadata["price"]`)
indexOpt1 := milvusclient.NewCreateIndexOption("my_collection", "metadata", jsonIndex1)
indexOpt2 := milvusclient.NewCreateIndexOption("my_collection", "metadata", jsonIndex2)
const indexParams = [
    {
        field_name: "metadata",
        index_type: "INVERTED",
        index_name: "json_index_1",
        params: {
            json_path: "metadata[\"product_info\"][\"category\"]",
            json_cast_type: "varchar"
        }
    },
    {
        field_name: "metadata",
        index_type: "INVERTED",
        index_name: "json_index_2",
        params: {
            json_path: "metadata[\"price\"]",
            json_cast_type: "double"
        }
    }
]

# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_collection",
    "indexParams": [
        {
            "fieldName": "metadata",
            "indexName": "json_index_1",
            "indexType": "INVERTED",
            "params": {
                "json_path": "metadata[\"product_info\"][\"category\"]",
                "json_cast_type": "varchar"
            }
        }
    ]
}'

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_collection",
    "indexParams": [
        {
            "fieldName": "metadata",
            "indexName": "json_index_2",
            "indexType": "INVERTED",
            "params": {
                "json_path": "metadata[\"price\"]",
                "json_cast_type": "double"
            }
        }
    ]
}'

Parámetro

Descripción

Ejemplo Valor

field_name

Nombre del campo JSON en su esquema.

"metadata"

index_type

Tipo de índice a crear; actualmente sólo se admite INVERTED para la indexación de rutas JSON.

"INVERTED"

index_name

(Opcional) Un nombre de índice personalizado. Especifique nombres diferentes si crea varios índices en el mismo campo JSON.

"json_index_1"

params.json_path

Especifica qué ruta JSON indexar. Puede apuntar a claves anidadas, posiciones de matrices, o ambas (por ejemplo, metadata["product_info"]["category"] o metadata["tags"][0]). Si falta la ruta o el elemento de matriz no existe para una fila en particular, esa fila simplemente se omite durante la indexación, y no se arroja ningún error.

"metadata[\"product_info\"][\"category\"]"

params.json_cast_type

Tipo de datos al que Milvus convertirá los valores JSON extraídos cuando construya el índice. Valores válidos:

  • "bool" o "BOOL"
  • "double" o "DOUBLE"
  • "varchar" o "VARCHAR"Nota: Para valores enteros, Milvus utiliza internamente double para el índice. Los enteros grandes por encima de 2^53 pierden precisión. Si la conversión de tipos falla (debido a un desajuste de tipos), no se lanza ningún error, y el valor de esa fila no se indexa.

"varchar"

Consideraciones sobre la indexación JSON

  • Lógica de filtrado:

    • Si crea un índice de tipo doble (json_cast_type="double"), sólo las condiciones de filtro de tipo numérico pueden utilizar el índice. Si el filtro compara un índice doble con una condición no numérica, Milvus vuelve a la búsqueda por fuerza bruta.

    • Si crea un índice de tipo varchar (json_cast_type="varchar"), sólo las condiciones de filtro de tipo cadena pueden utilizar el índice. De lo contrario, Milvus vuelve a la fuerza bruta.

    • La indexaciónbooleana se comporta de forma similar a la de tipo varchar.

  • Expresiones de términos:

    • Puede utilizar json["field"] in [value1, value2, …]. Sin embargo, el índice sólo funciona para valores escalares almacenados en esa ruta. Si json["field"] es una matriz, la consulta vuelve a la fuerza bruta (aún no se admite la indexación de tipo matriz).
  • Precisión numérica:

    • Internamente, Milvus indexa todos los campos numéricos como dobles. Si un valor numérico supera 2532^{53} 2 , pierde precisión, y las consultas sobre esos valores fuera de rango pueden no coincidir exactamente.
  • Integridad de los datos:

    • Milvus no analiza ni transforma claves JSON más allá de su reparto especificado. Si los datos de origen son inconsistentes (por ejemplo, algunas filas almacenan una cadena para la clave "k" mientras que otras almacenan un número), algunas filas no serán indexadas.

Indexar un campo vectorial

El siguiente ejemplo crea un índice en el campo vectorial embedding, utilizando el tipo de índice AUTOINDEX. Con este tipo, Milvus selecciona automáticamente el índice más adecuado en función del tipo de datos. También puede personalizar el tipo de índice y los parámetros para cada campo. Para más detalles, consulte Índice Explicado.

# Set index params

# Index `embedding` with AUTOINDEX and specify similarity metric type
index_params.add_index(
field_name="embedding",
index_name="vector_index",
index_type="AUTOINDEX", # Use automatic indexing to simplify complex index settings
metric_type="COSINE" # Specify similarity metric type, options include L2, COSINE, or IP
)
import io.milvus.v2.common.IndexParam;
import java.util.*;

indexes.add(IndexParam.builder()
        .fieldName("embedding")
        .indexName("vector_index")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.COSINE)
        .build());
vectorIndex := index.NewAutoIndex(entity.COSINE)
indexOpt := milvusclient.NewCreateIndexOption("my_collection", "embedding", vectorIndex)
indexParams.push({
    index_name: 'embedding_index',
    field_name: 'embedding',
    index_name: 'vector_index',
    metricType: MetricType.CONSINE,
    index_type: IndexType.AUTOINDEX,
));
export indexParams='[
        {
            "fieldName": "embedding",
            "indexName": "vector_index",
            "metricType": "COSINE",
            "indexType": "AUTOINDEX"
        }
    ]'

Crear colección

Una vez definidos el esquema y el índice, crea una colección que incluya el campo JSON.

client.create_collection(
    collection_name="my_collection",
    schema=schema,
    index_params=index_params
)
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_collection")
        .collectionSchema(schema)
        .indexParams(indexes)
        .build();
client.createCollection(requestCreate);
err = client.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("my_collection", schema).
    WithIndexOptions(indexOpt1, indexOpt2, indexOpt))
if err != nil {
    fmt.Println(err.Error())
    // handler err
}
await client.create_collection({
    collection_name: "my_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_collection\",
    \"schema\": $schema,
    \"indexParams\": $indexParams
}"

Insertar datos

Una vez creada la colección, inserte las entidades que coincidan con el esquema.

# Sample data
data = [
    {
        "metadata": {
            "product_info": {"category": "electronics", "brand": "BrandA"},
            "price": 99.99,
            "in_stock": True,
            "tags": ["summer_sale"]
        },
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "metadata": None,  # Entire JSON object is null
        "pk": 2,
        "embedding": [0.56, 0.78, 0.90]
    },
    {
        # JSON field is completely missing
        "pk": 3,
        "embedding": [0.91, 0.18, 0.23]
    },
    {
        # Some sub-keys are null
        "metadata": {
            "product_info": {"category": None, "brand": "BrandB"},
            "price": 59.99,
            "in_stock": None
        },
        "pk": 4,
        "embedding": [0.56, 0.38, 0.21]
    }
]

client.insert(
collection_name="my_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("{\"metadata\":{\"product_info\":{\"category\":\"electronics\",\"brand\":\"BrandA\"},\"price\":99.99,\"in_stock\":True,\"tags\":[\"summer_sale\"]},\"pk\":1,\"embedding\":[0.12,0.34,0.56]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\":null,\"pk\":2,\"embedding\":[0.56,0.78,0.90]}", JsonObject.class));
rows.add(gson.fromJson("{\"pk\":3,\"embedding\":[0.91,0.18,0.23]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\":{\"product_info\":{\"category\":null,\"brand\":\"BrandB\"},\"price\":59.99,\"in_stock\":null},\"pk\":4,\"embedding\":[0.56,0.38,0.21]}", JsonObject.class));

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("my_collection")
        .data(rows)
        .build());
_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("my_collection").
    WithInt64Column("pk", []int64{1, 2, 3, 4}).
    WithFloatVectorColumn("embedding", 3, [][]float32{
        {0.12, 0.34, 0.56},
        {0.56, 0.78, 0.90},
        {0.91, 0.18, 0.23},
        {0.56, 0.38, 0.21},
    }).WithColumns(
    column.NewColumnJSONBytes("metadata", [][]byte{
        []byte(`{
    "product_info": {"category": "electronics", "brand": "BrandA"},
    "price": 99.99,
    "in_stock": True,
    "tags": ["summer_sale"]
}`),
        []byte(`null`),
        []byte(`null`),
        []byte(`"metadata": {
    "product_info": {"category": None, "brand": "BrandB"},
    "price": 59.99,
    "in_stock": None
}`),
    }),
))
if err != nil {
    fmt.Println(err.Error())
    // handle err
}
const data = [
    {
        "metadata": {
            "product_info": {"category": "electronics", "brand": "BrandA"},
            "price": 99.99,
            "in_stock": True,
            "tags": ["summer_sale"]
        },
        "pk": 1,
        "embedding": [0.12, 0.34, 0.56]
    },
    {
        "metadata": None,  # Entire JSON object is null
        "pk": 2,
        "embedding": [0.56, 0.78, 0.90]
    },
    {
        # JSON field is completely missing
        "pk": 3,
        "embedding": [0.91, 0.18, 0.23]
    },
    {
        # Some sub-keys are null
        "metadata": {
            "product_info": {"category": None, "brand": "BrandB"},
            "price": 59.99,
            "in_stock": None
        },
        "pk": 4,
        "embedding": [0.56, 0.38, 0.21]
    }
];

await client.insert({
    collection_name: "my_collection",
    data: data
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data '{
    "data": [
        {
             "metadata":  {
                   "product_info": {"category": "electronics", "brand": "BrandA"},
                  "price":  99.99,
                   "in_stock":  true,
                  "tags": ["summer_sale"]
              }, 
             "varchar_field2": "High quality product", 
             "pk": 1, 
             "embedding": [0.1, 0.2, 0.3]
          },
          {
              "metadata": null,
              "pk": 2,
              "embedding": [0.56, 0.78, 0.90]
          },
         {
               "pk": 3,
               "embedding": [0.91, 0.18, 0.23]
         },
        {
              "metadata": {
                     "product_info": {"category": null, "brand": "BrandB"},
                     "price": 59.99,
                     "in_stock": null
               },
              "pk": 4,
              "embedding": [0.56, 0.38, 0.21]
         }
    ],
    "collectionName": "my_collection"
}'

Consulta con expresiones de filtro

Después de insertar las entidades, utilice el método query para recuperar las entidades que coincidan con las expresiones de filtro especificadas.

Para los campos JSON que permiten valores nulos, el campo se tratará como nulo si falta todo el objeto JSON o se establece en None. Para obtener más información, consulte Campos JSON con valores nulos.

Para recuperar entidades en las que metadata no es nulo:

# Query to filter out records with null metadata

filter = 'metadata is not null'

res = client.query(
collection_name="my_collection",
filter=filter,
output_fields=["metadata", "pk"]
)

# Expected result:
# Rows with pk=1 and pk=4 have valid, non-null metadata.
# Rows with pk=2 (metadata=None) and pk=3 (no metadata key) are excluded.

print(res)

# Output:
# data: [
# "{'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}, 'pk': 1}",
# "{'metadata': {'product_info': {'category': None, 'brand': 'BrandB'}, 'price': 59.99, 'in_stock': None}, 'pk': 4}"
# ]
import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;

String filter = "metadata is not null";
QueryResp resp = client.query(QueryReq.builder()
        .collectionName("my_collection")
        .filter(filter)
        .outputFields(Arrays.asList("metadata", "pk"))
        .build());

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

// Output
//
// [
//    QueryResp.QueryResult(entity={metadata={"product_info":{"category":"electronics","brand":"BrandA"},"price":99.99,"in_stock":true,"tags":["summer_sale"]}, pk=1}),
//    QueryResp.QueryResult(entity={metadata={"product_info":{"category":null,"brand":"BrandB"},"price":59.99,"in_stock":null}, pk=4})
// ]
filter := "metadata is not null"
rs, err := client.Query(ctx, milvusclient.NewQueryOption("my_collection").
    WithFilter(filter).
    WithOutputFields("metadata", "pk"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}

fmt.Println("pk", rs.GetColumn("pk").FieldData().GetScalars())
fmt.Println("metadata", rs.GetColumn("metadata").FieldData().GetScalars())
await client.query({
    collection_name: 'my_scalar_collection',
    filter: 'metadata["category"] == "electronics" and metadata["price"] < 150',
    output_fields: ['metadata']
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_collection",
    "filter": "metadata is not null",
    "outputFields": ["metadata", "pk"]
}'

#{"code":0,"cost":0,"data":[{"metadata":"{\"product_info\": {\"category\": \"electronics\", \"brand\": \"BrandA\"}, \"price\": 99.99, \"in_stock\": true, \"tags\": [\"summer_sale\"]}","pk":1},{"metadata":"","pk":2},{"metadata":"","pk":3},{"metadata":"{\"product_info\": {\"category\": null, \"brand\": \"BrandB\"}, \"price\": 59.99, \"in_stock\": null}","pk":4}]}

Para recuperar entidades donde metadata["product_info"]["category"] es "electronics":

filter = 'metadata["product_info"]["category"] == "electronics"'

res = client.query(
collection_name="my_collection",
filter=filter,
output_fields=["metadata", "pk"]
)

# Expected result:
# - Only pk=1 has "category": "electronics".
# - pk=4 has "category": None, so it doesn't match.
# - pk=2 and pk=3 have no valid metadata.

print(res)

# Output:
# data: [
# "{'pk': 1, 'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}}"
# ]
String filter = "metadata[\"product_info\"][\"category\"] == \"electronics\"";

QueryResp resp = client.query(QueryReq.builder()
        .collectionName("my_collection")
        .filter(filter)
        .outputFields(Arrays.asList("metadata", "pk"))
        .build());

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

// Output
// [QueryResp.QueryResult(entity={metadata={"product_info":{"category":"electronics","brand":"BrandA"},"price":99.99,"in_stock":true,"tags":["summer_sale"]}, pk=1})]
filter = `metadata["product_info"]["category"] == "electronics"`
rs, err := client.Query(ctx, milvusclient.NewQueryOption("my_collection").
    WithFilter(filter).
    WithOutputFields("metadata", "pk"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}

fmt.Println("pk", rs.GetColumn("pk").FieldData().GetScalars())
fmt.Println("metadata", rs.GetColumn("metadata").FieldData().GetScalars())
const filter = 'metadata["category"] == "electronics"';
const res = await client.query({
    collection_name: "my_collection",
    filter: filter,
    output_fields: ["metadata", "pk"]
});

// Example output:
// {
//.  data: [
//      {'pk': 1, 'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}}
// ]
// }
# restful
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
  "collectionName": "my_collection",
  "filter": "metadata[\"product_info\"][\"category\"] == \"electronics\"",
  "outputFields": ["metadata", "pk"]
}'

#{"code":0,"cost":0,"data":[{"metadata":"{\"product_info\": {\"category\": \"electronics\", \"brand\": \"BrandA\"}, \"price\": 99.99, \"in_stock\": true, \"tags\": [\"summer_sale\"]}","pk":1}]}

Búsqueda vectorial con expresiones de filtro

Además del filtrado básico de campos escalares, puede combinar búsquedas de similitud vectorial con filtros de campos escalares. Por ejemplo, el siguiente código muestra cómo añadir un filtro de campo escalar a una búsqueda vectorial:

filter = 'metadata["product_info"]["brand"] == "BrandA"'

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

# Expected result:
# - Only pk=1 has "brand": "BrandA" in metadata["product_info"].
# - pk=4 has "brand": "BrandB".
# - pk=2 and pk=3 have no valid metadata.
# Hence, only pk=1 matches the filter.

print(res)

# Output:
# data: [
# "[{'id': 1, 'distance': -0.2479381263256073, 'entity': {'metadata': {'product_info': {'category': 'electronics', 'brand': 'BrandA'}, 'price': 99.99, 'in_stock': True, 'tags': ['summer_sale']}}}]"
# ]
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;

String filter = "metadata[\"product_info\"][\"brand\"] == \"BrandA\"";

SearchResp resp = client.search(SearchReq.builder()
        .collectionName("my_collection")
        .annsField("embedding")
        .data(Collections.singletonList(new FloatVec(new float[]{0.3f, -0.6f, 0.1f})))
        .topK(5)
        .outputFields(Collections.singletonList("metadata"))
        .filter(filter)
        .build());

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

// Output
//
// [
//   [
//     SearchResp.SearchResult(entity={metadata={"product_info":{"category":"electronics","brand":"BrandA"},"price":99.99,"in_stock":true,"tags":["summer_sale"]}}, score=-0.24793813, id=1)
//   ]
// ]

queryVector := []float32{0.3, -0.6, -0.1}
filter = "metadata[\"product_info\"][\"brand\"] == \"BrandA\""

annParam := index.NewCustomAnnParam()
annParam.WithExtraParam("nprobe", 10)
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "my_collection", // collectionName
    5,               // limit
    []entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("embedding").
    WithFilter(filter).
    WithOutputFields("metadata").
    WithAnnParam(annParam))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}

for _, resultSet := range resultSets {
    fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
    fmt.Println("Scores: ", resultSet.Scores)
    fmt.Println("metadata", resultSet.GetColumn("metadata").FieldData().GetScalars())
}
await client.search({
    collection_name: 'my_collection',
    data: [0.3, -0.6, 0.1],
    limit: 5,
    output_fields: ['metadata'],
    filter: 'metadata["category"] == "electronics" and metadata["price"] < 150',
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
  "collectionName": "my_collection",
  "data": [
    [0.3, -0.6, 0.1]
  ],
  "annsField": "embedding",
  "limit": 5,
  "searchParams": {
    "params": {
      "nprobe": 10
    }
  },
  "outputFields": ["metadata"],
  "filter": "metadata[\"product_info\"][\"brand\"] == \"BrandA\""
}'

##{"code":0,"cost":0,"data":[{"metadata":"{\"product_info\": {\"category\": \"electronics\", \"brand\": \"BrandA\"}, \"price\": 99.99, \"in_stock\": true, \"tags\": [\"summer_sale\"]}","pk":1}]}

Además, Milvus soporta operadores avanzados de filtrado JSON como JSON_CONTAINS, JSON_CONTAINS_ALL, y JSON_CONTAINS_ANY, que pueden mejorar aún más las capacidades de consulta. Para más detalles, consulte Operadores JSON.

Traducido porDeepL

Prueba Milvus gestionado gratis

Zilliz Cloud no da problemas, funciona con Milvus y es 10 veces más rápido.

Empezar
Feedback

¿Fue útil esta página?