Descrição geral do campo JSON

Ao criar aplicações como catálogos de produtos, sistemas de gestão de conteúdos ou motores de preferências do utilizador, é frequentemente necessário armazenar metadados flexíveis juntamente com as suas incorporações vectoriais. Os atributos dos produtos variam por categoria, as preferências dos utilizadores evoluem ao longo do tempo e as propriedades dos documentos têm estruturas complexas aninhadas. Os campos JSON no Milvus resolvem este desafio, permitindo-lhe armazenar e consultar dados estruturados flexíveis sem sacrificar o desempenho.

O que é um campo JSON?

Um campo JSON é um tipo de dados definido pelo esquema (DataType.JSON) em Milvus que armazena dados estruturados de valor-chave. Ao contrário das colunas rígidas tradicionais de bases de dados, os campos JSON acomodam objectos aninhados, arrays e tipos de dados mistos, ao mesmo tempo que fornecem várias opções de indexação para consultas rápidas.

Exemplo de estrutura de campo JSON:

{
  "metadata": { 
    "category": "electronics",
    "brand": "BrandA",
    "in_stock": true,
    "price": 99.99,
    "string_price": "99.99",
    "tags": ["clearance", "summer_sale"],
    "supplier": {
      "name": "SupplierX",
      "country": "USA",
      "contact": {
        "email": "support@supplierx.com",
        "phone": "+1-800-555-0199"
      }
    }
  }
}

Neste exemplo, metadata é um único campo JSON que contém uma mistura de valores simples (por exemplo, category, in_stock), matrizes (tags) e objectos aninhados (supplier).

Convenção de nomenclatura: Utilize apenas letras, números e sublinhados nas chaves JSON. Evite caracteres especiais, espaços ou pontos, pois eles podem causar problemas de análise em consultas.

Campo JSON vs. campo dinâmico

Um ponto comum de confusão é a diferença entre um campo JSON e o campo dinâmico. Embora ambos estejam relacionados com o JSON, têm objectivos diferentes.

A tabela abaixo resume as principais diferenças entre um campo JSON e o campo dinâmico:

Caraterística

Campo JSON

Campo dinâmico

Definição de esquema

Um campo escalar que deve ser explicitamente declarado no esquema da coleção com o tipo DataType.JSON.

Um campo JSON oculto (denominado $meta) que armazena automaticamente os campos não declarados.

Caso de utilização

Armazena dados estruturados em que o esquema é conhecido e consistente.

Armazena dados flexíveis, em evolução ou semi-estruturados que não se enquadram num esquema fixo.

Controlo

O utilizador controla o nome e a estrutura do campo.

Gerido pelo sistema para campos indefinidos.

Consulta

Consulta utilizando o nome do campo ou a chave de destino dentro do campo JSON: metadata["key"].

Consulta direta utilizando a chave de campo dinâmica: "dynamic_key" ou através de $meta: $meta["dynamic_key"]

Operações básicas

O fluxo de trabalho fundamental para utilizar um campo JSON envolve a sua definição no esquema, a inserção de dados e, em seguida, a consulta dos dados utilizando expressões de filtro específicas.

Definir um campo JSON

Para utilizar um campo JSON, defina-o explicitamente no esquema da coleção ao criar a coleção. O exemplo seguinte demonstra como criar uma coleção com um campo metadata do tipo DataType.JSON:

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530") # Replace with your server address 

# Create schema
schema = client.create_schema(auto_id=False, enable_dynamic_field=True)

schema.add_field(field_name="product_id", datatype=DataType.INT64, is_primary=True) # Primary field
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5) # Vector field
# Define a JSON field that allows null values
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)

client.create_collection(
    collection_name="product_catalog",
    schema=schema
)

Neste exemplo, o campo JSON definido no esquema de coleção permite valores nulos com nullable=True. Para mais informações, consulte Nullable & Default.

Inserir dados

Uma vez criada a coleção, insira entidades que contenham objectos JSON estruturados no campo JSON designado. Os seus dados devem ser formatados como uma lista de dicionários.

entities = [
    {
        "product_id": 1,
        "vector": [0.1, 0.2, 0.3, 0.4, 0.5],
        "metadata": { # JSON field
            "category": "electronics",
            "brand": "BrandA",
            "in_stock": True,
            "price": 99.99,
            "string_price": "99.99",
            "tags": ["clearance", "summer_sale"],
            "supplier": {
                "name": "SupplierX",
                "country": "USA",
                "contact": {
                    "email": "support@supplierx.com",
                    "phone": "+1-800-555-0199"
                }
            }
        }
    }
]

client.insert(collection_name="product_catalog", data=entities)

Operações de filtragem

Antes de poder efetuar operações de filtragem nos campos JSON, certifique-se de que:

  • Criou um índice em cada campo de vetor.

  • A coleção está carregada na memória.

Mostrar código

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="vector",
    index_type="AUTOINDEX",
    index_name="vector_index",
    metric_type="COSINE"
)

client.create_index(collection_name="product_catalog", index_params=index_params)

client.load_collection(collection_name="product_catalog")

Uma vez cumpridos estes requisitos, pode utilizar as expressões abaixo para filtrar a sua coleção com base nos valores do campo JSON. Essas expressões de filtro utilizam a sintaxe de caminho JSON específica e operadores dedicados.

Filtragem com sintaxe de caminho JSON

Para consultar uma chave específica, utilize a notação entre parênteses para aceder a chaves JSON: json_field_name["key"]. Para chaves aninhadas, encadeie-as: json_field_name["key1"]["key2"].

Para filtrar entidades em que category é "electronics":

# Define filter expression
filter = 'metadata["category"] == "electronics"'

client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

Para filtrar entidades em que a chave aninhada supplier["country"] é "USA":

# Define filter expression
filter = 'metadata["supplier"]["country"] == "USA"'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

Filtragem com operadores específicos de JSON

Milvus também fornece operadores especiais para consultar valores de array em chaves de campo JSON específicas. Por exemplo:

  • json_contains(identifier, expr): Verifica se um elemento específico ou sub-array existe dentro de um array JSON

  • json_contains_all(identifier, expr): Assegura que todos os elementos da expressão JSON especificada estão presentes no campo

  • json_contains_any(identifier, expr): Filtra entidades em que pelo menos um membro da expressão JSON existe no campo

Para encontrar um produto que tenha o valor "summer_sale" sob a chave tags:

# Define filter expression
filter = 'json_contains(metadata["tags"], "summer_sale")'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

Para encontrar um produto que tenha pelo menos um dos valores "electronics", "new", ou "clearance" sob a chave tags:

# Define filter expression
filter = 'json_contains_any(metadata["tags"], ["electronics", "new", "clearance"])'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

Para obter mais informações sobre operadores específicos de JSON, consulte Operadores JSON.

Próximo: Acelerar consultas JSON

Por padrão, as consultas em campos JSON sem aceleração executarão uma varredura completa de todas as linhas, o que pode ser lento em grandes conjuntos de dados. Para acelerar as consultas JSON, o Milvus fornece recursos avançados de indexação e otimização de armazenamento.

A tabela abaixo resume as suas diferenças e os cenários de melhor utilização:

Técnica

Melhor para

Aceleração de matrizes

Notas

Indexação JSON

Pequeno conjunto de chaves frequentemente acedidas, matrizes numa chave de matriz específica

Sim (na chave do array indexado)

Deve pré-selecionar chaves, manutenção necessária se o esquema evoluir

Fragmentação JSON

Aceleração geral em muitas chaves, flexível para consultas variadas

Não (não acelera os valores dentro das matrizes)

Configuração de armazenamento extra, as matrizes ainda precisam de um índice por chave

Índice NGRAM

Pesquisas curinga, correspondência de substring em campos de texto

N/A

Não para filtros numéricos/de intervalo

Dica: você pode combinar essas abordagens - por exemplo, usar a fragmentação JSON para aceleração de consulta ampla, a indexação JSON para chaves de matriz de alta frequência e a indexação NGRAM para pesquisa de texto flexível.

Para obter detalhes de implementação, consulte:

PERGUNTAS FREQUENTES

Há alguma limitação no tamanho de um campo JSON?

Sim. Cada campo JSON está limitado a 65.536 bytes.

Um campo JSON suporta a definição de um valor por defeito?

Não, os campos JSON não suportam valores predefinidos. No entanto, pode definir nullable=True ao definir o campo para permitir entradas vazias.

Consulte Nullable & Default para obter detalhes.

Há alguma convenção de nomenclatura para chaves de campo JSON?

Sim, para garantir a compatibilidade com consultas e indexação:

  • Use apenas letras, números e sublinhados nas chaves JSON.

  • Evite usar caracteres especiais, espaços ou pontos (., /, etc.).

  • Chaves incompatíveis podem causar problemas de análise em expressões de filtro.

Como é que o Milvus lida com valores de cadeia de caracteres em campos JSON?

Milvus armazena valores de string exatamente como aparecem na entrada JSON - sem transformação semântica. As cadeias de caracteres com aspas inadequadas podem resultar em erros durante a análise.

Exemplos de strings válidas:

"a\"b", "a'b", "a\\b"

Exemplos de strings inválidas:

'a"b', 'a\'b'