Procurando um guia?
Confira nosso guia de boas práticas para JSON com exemplos, recursos avançados e considerações sobre o uso do tipo JSON.
JSON armazena documentos JavaScript Object Notation (JSON) em uma única coluna.
No ClickHouse Open-Source, o tipo de dados JSON é considerado pronto para produção a partir da versão 25.3. Não é recomendável usar esse tipo em produção em versões anteriores.
JSON, você pode usar a seguinte sintaxe:
Quando usar o tipo JSON
JSON foi projetado para consultar, filtrar e agregar campos específicos em objetos JSON com estruturas dinâmicas ou imprevisíveis. Ele faz isso dividindo objetos JSON em subcolunas separadas, o que reduz drasticamente a quantidade de dados lidos e acelera as consultas em campos selecionados em comparação com alternativas como Map ou o parsing de strings.
No entanto, isso envolve trade-offs importantes:
INSERTs mais lentos - Dividir JSON em subcolunas, realizar inferência de tipos e gerenciar estruturas de armazenamento flexíveis torna os inserts mais lentos em comparação com armazenar JSON como uma simples colunaString.- Mais lento ao ler objetos inteiros - Se você precisa recuperar documentos JSON completos (em vez de campos específicos), o tipo
JSONé mais lento do que ler de uma colunaString. A sobrecarga de reconstruir objetos a partir de subcolunas separadas não traz nenhum benefício quando você não está fazendo consultas no nível de campo. - Sobrecarga de armazenamento - Manter subcolunas separadas acrescenta uma sobrecarga estrutural em comparação com armazenar JSON como um único valor em string.
Use o tipo JSON quando:
- Seus dados têm uma estrutura dinâmica ou imprevisível, com chaves que variam entre documentos
- Os tipos de campo ou os esquemas mudam ao longo do tempo ou variam entre registros
- Você precisa consultar, filtrar ou agregar dados em caminhos específicos dentro de objetos JSON cuja estrutura não pode ser prevista antecipadamente
- Seu caso de uso envolve dados semiestruturados, como logs, eventos ou conteúdo gerado por usuários, com esquemas inconsistentes
Use uma coluna String (ou tipos estruturados) quando:
- A estrutura dos seus dados é conhecida e consistente — nesse caso, use colunas normais ou os tipos
Tuple,Array,DynamicouVariant - Documentos
JSONsão tratados como blobs opacos, apenas armazenados e recuperados integralmente, sem análise em nível de campo - Você não precisa consultar nem filtrar campos individuais do JSON dentro do banco de dados
- O
JSONé simplesmente um formato de transporte/armazenamento e não é analisado no ClickHouse
Criando JSON
Nesta seção, veremos as várias maneiras de criar JSON.
Usando JSON na definição de uma coluna de tabela
Query (Example 1)
Response (Example 1)
Query (Example 2)
Response (Example 2)
Usando CAST com ::JSON
É possível converter diversos tipos usando a sintaxe especial ::JSON.
CAST de String para JSON
Query
Response
CAST de Tuple para JSON
Query
Response
CAST de Map para JSON
Query
Response
Os caminhos JSON são armazenados de forma achatada. Isso significa que, quando um objeto JSON é reconstituído a partir de um caminho como retornará:e não:
a.b.c,
não é possível saber se o objeto deve ser construído como { "a.b.c" : ... } ou { "a": { "b": { "c": ... } } }.
Nossa implementação sempre assumirá a segunda forma.Por exemplo:Consulta
Resposta
Leitura de caminhos JSON como subcolunas
O tipoJSON oferece suporte à leitura de cada caminho como uma subcoluna separada.
Se o tipo do caminho solicitado não for especificado na declaração do tipo JSON,
a subcoluna desse caminho sempre terá o tipo Dynamic.
Por exemplo:
Query
Response
Query (Reading JSON paths as sub-columns)
Response (Reading JSON paths as sub-columns)
getSubcolumn para ler subcolunas do tipo JSON:
Query
Response
json['key'] também pode ser usada para acessar caminhos JSON. O acesso aninhado é suportado por meio de encadeamento:
Query
Response
Nullable(JSON) e retorna o mesmo valor e tipo que a
dot syntax equivalente, seguindo as mesmas regras de nulabilidade de json.key: um caminho que pode representar
NULL (Dynamic, ou um typed path que pode ser encapsulado em Nullable) resulta em NULL para uma linha NULL,
enquanto um typed path não nulo, como Array ou Map, mantém seu default value nesse caso.
O acesso encadeado por colchetes é achatado em um único caminho JSON quando optimize_functions_to_subcolumns
está habilitado, de modo que json['a']['b'] lê o caminho a.b exatamente como json.a.b faz: uma linha em que a contém
um scalar em vez de um object não possui a.b e resulta em NULL. Sem essa optimization, o acesso externo
é aplicado ao valor Dynamic de json['a'], e tal linha segue a
configuração dynamic_throw_on_type_mismatch.
Se o caminho solicitado não for encontrado nos dados, ele será preenchido com valores NULL:
Query
Response
Query
Response
a.b, o tipo é UInt32, conforme especificamos na declaração do tipo JSON,
e, para todas as outras subcolunas, o tipo é Dynamic.
Também é possível ler subcolunas de um tipo Dynamic usando a sintaxe especial json.some.path.:TypeName:
Query
Response
Dynamic podem ser convertidas para qualquer tipo de dado. Nesse caso, será lançada uma exceção se o tipo interno em Dynamic não puder ser convertido para o tipo solicitado:
Query
Response
Query
Response
Para ler subcolunas com eficiência em partes Compact do MergeTree, certifique-se de que a configuração do MergeTree write_marks_for_substreams_in_compact_parts esteja habilitada.
Leitura de sub-objetos JSON como subcolunas
O tipoJSON permite ler objetos aninhados como subcolunas do tipo JSON usando a sintaxe especial json.^some.path:
Query
Response
Query
Response
Quando os caminhos são armazenados em dados compartilhados básicos (
map), a leitura de subcolunas de subobjeto pode ser ineficiente, pois exige a varredura de toda a estrutura de dados compartilhados. Com a serialização de dados compartilhados map_with_buckets, advanced ou advanced_chunked, a leitura de subcolunas desses dados compartilhados é altamente otimizada.Leitura de subcolunas combinadas de JSON
O tipoJSON permite ler um caminho como uma subcoluna combinada usando a sintaxe especial json.@some.path.
Uma subcoluna combinada para um determinado caminho retorna:
- O valor literal armazenado nesse caminho como
Dynamic, se o caminho tiver um valor literal. - Um subobjeto JSON nesse caminho como
Dynamic, se o caminho não tiver um valor literal, mas tiver subcaminhos aninhados. NULL, se não existir nem um valor literal nem qualquer subcaminho para esse caminho.
json.a) e a subcoluna de subobjeto (json.^a).
O exemplo a seguir compara os três tipos de subcoluna para o caminho a:
Query
Response
Query
Response
- Linha 1:
acontém o literal42.json.ao retorna comoDynamic(Int64),json.^aretorna um subobjeto vazio{}(sem chaves aninhadas ema) ejson.@aretorna o literal42. - Linha 2:
acontém um objeto aninhado.json.aretornaNULL(não há literal nesse caminho),json.^aretorna o subobjeto comoJSONejson.@atambém retorna o subobjeto comoDynamic(JSON). - Linha 3:
aestá completamente ausente. Tantojson.aquantojson.@aretornamNULL, enquantojson.^aretorna um{}vazio.
Quando os caminhos são armazenados em dados compartilhados básicos (
map), a leitura de subcolunas combinadas pode ser ineficiente, pois exige varrer toda a estrutura de dados compartilhados. Com a serialização de dados compartilhados map_with_buckets, advanced ou advanced_chunked, a leitura de subcolunas a partir de dados compartilhados é altamente otimizada.Inferência de tipo para caminhos
Durante a análise deJSON, o ClickHouse tenta detectar o tipo de dado mais adequado para cada caminho JSON.
Isso funciona de forma semelhante à inferência automática de esquema a partir dos dados de entrada,
e é controlado pelas mesmas configurações:
- input_format_try_infer_dates
- input_format_try_infer_datetimes
- schema_inference_make_columns_nullable
- input_format_json_try_infer_numbers_from_strings
- input_format_json_infer_incomplete_types_as_strings
- input_format_json_read_numbers_as_strings
- input_format_json_read_bools_as_strings
- input_format_json_read_bools_as_numbers
- input_format_json_read_arrays_as_strings
- input_format_json_infer_array_of_dynamic_from_array_of_different_types
Query
Response
Query
Response
Query
Response
Query
Response
Como lidar com arrays de objetos JSON
Caminhos JSON que contêm um array de objetos são interpretados como o tipoArray(JSON) e inseridos em uma coluna Dynamic para esse caminho.
Para ler um array de objetos, você pode extraí-lo da coluna Dynamic como uma subcoluna:
Query
Response
Query
Response
max_dynamic_types/max_dynamic_paths do tipo JSON aninhado foram reduzidos em relação aos valores padrão.
Isso é necessário para evitar que o número de subcolunas cresça de forma descontrolada em arrays aninhados de objetos JSON.
Vamos tentar ler subcolunas de uma coluna JSON aninhada:
Query
Response
Array(JSON) usando uma sintaxe especial:
Query
Response
[] após o caminho indica o nível do array. Por exemplo, json.path[][] será transformado em json.path.:Array(Array(JSON))
Vamos verificar os caminhos e tipos dentro do nosso Array(JSON):
Query
Response
Array(JSON):
Query
Response
JSON aninhada:
Query
Response
Tratamento de chaves JSON com NULL
Na nossa implementação de JSON,null e a ausência de valor são considerados equivalentes:
Query
Response
Tratamento de chaves JSON com pontos
Internamente, a coluna JSON armazena todos os caminhos e valores de forma achatada. Isso significa que, por padrão, estes 2 objetos são considerados iguais:a.b e valor 42. Durante a formatação de JSON, sempre formamos objetos aninhados com base nas partes do caminho separadas por ponto:
Query
Response
{"a.b" : 42} agora está formatado como {"a" : {"b" : 42}}.
Essa limitação também faz com que o parsing de objetos JSON válidos como este falhe:
Query
Response
25.8). Nesse caso, durante o parsing, todos os pontos nas chaves JSON serão
escapados como %2E e restaurados durante a formatação.
Query
Response
Query
Response
Query
Response
parser de identificadores e do analyzer, a subcoluna json.`a.b` é equivalente à subcoluna json.a.b e não lerá o caminho com ponto escapado:
Query
Response
SKIP/SKIP REGEX), será necessário usar pontos com escape na dica:
Query
Response
Query
Response
Lendo o tipo JSON a partir de dados
Todos os formatos de texto (JSONEachRow,
TSV,
CSV,
CustomSeparated,
Values, etc.) suportam a leitura do tipo JSON.
Exemplos:
Query
Response
CSV/TSV/etc., o JSON é obtido por parsing a partir de uma string que contém o objeto JSON:
Query
Response
Atingindo o limite de caminhos dinâmicos no JSON
O tipo de dadosJSON pode armazenar internamente apenas um número limitado de caminhos como subcolunas separadas.
Por padrão, esse limite é 1024, mas você pode alterá-lo na declaração do tipo usando o parâmetro max_dynamic_paths.
Quando o limite é atingido, todos os novos caminhos inseridos em uma coluna JSON serão armazenados em uma única estrutura de dados compartilhada.
Ainda é possível ler esses caminhos como subcolunas,
mas isso pode ser menos eficiente (veja a seção sobre dados compartilhados).
Esse limite é necessário para evitar um número enorme de subcolunas diferentes, o que pode tornar a tabela inutilizável.
Vamos ver o que acontece quando o limite é atingido em alguns cenários diferentes.
Ao atingir o limite durante o parsing dos dados
Durante o parsing de objetosJSON dos dados, quando o limite é atingido para o bloco de dados atual,
todos os novos caminhos serão armazenados em uma estrutura de dados compartilhada. Podemos usar as duas funções de introspecção a seguir: JSONDynamicPaths, JSONSharedDataPaths
Query
Response
e e f.g, o limite foi atingido,
e eles foram inseridos em uma estrutura de dados compartilhada.
Durante mesclagens de partes de dados em motores de tabela MergeTree
Durante a mesclagem de várias partes de dados em uma tabelaMergeTree, a coluna JSON na parte de dados resultante pode atingir o limite de caminhos dinâmicos
e não conseguir armazenar todos os caminhos das partes de origem como subcolunas.
Nesse caso, o ClickHouse escolhe quais caminhos permanecerão como subcolunas após a mesclagem e quais caminhos serão armazenados na estrutura de dados compartilhada.
Na maioria dos casos, o ClickHouse tenta manter os caminhos que contêm
o maior número de valores não nulos e mover os caminhos mais raros para a estrutura de dados compartilhada. No entanto, isso depende da implementação.
Vamos ver um exemplo desse tipo de mesclagem.
Primeiro, vamos criar uma tabela com uma coluna JSON, definir o limite de caminhos dinâmicos como 3 e depois inserir valores com 5 caminhos diferentes:
Query
JSON contendo um único caminho:
Query
Response
Query
Response
a, b e c, que são os mais frequentes, e transferiu os caminhos d e e para uma estrutura de dados compartilhada.
Estrutura de dados compartilhada
Conforme descrito na seção anterior, quando o limitemax_dynamic_paths é atingido, todos os novos caminhos são armazenados em uma única estrutura de dados compartilhada.
Nesta seção, veremos os detalhes da estrutura de dados compartilhada e como lemos as subcolunas de caminhos a partir dela.
Consulte a seção “funções de introspecção” para obter detalhes sobre as funções usadas para inspecionar o conteúdo de uma coluna JSON.
Estrutura de dados compartilhada em memória
Em memória, a estrutura de dados compartilhada é apenas uma subcoluna do tipoMap(String, String) que armazena o mapeamento entre um caminho JSON achatado e um valor codificado em binário.
Para extrair dela a subcoluna de um caminho, basta iterar por todas as linhas nessa coluna Map e tentar encontrar o caminho solicitado e seus valores.
Estrutura de dados compartilhada em partes do MergeTree
Em tabelas MergeTree, armazenamos os dados em partes de dados que mantêm tudo em disco (local ou remoto). E os dados em disco podem ser armazenados de uma forma diferente da memória. Atualmente, existem 4 serializações diferentes da estrutura de dados compartilhada em partes de dados do MergeTree:map, map_with_buckets,
advanced e advanced_chunked.
A versão da serialização é controlada pelas
configurações do MergeTree object_shared_data_serialization_version
e object_shared_data_serialization_version_for_zero_level_parts
(a parte de nível zero é a parte criada durante a inserção de dados na tabela; durante operações de mesclagem, as partes têm nível mais alto).
Observação: alterar a serialização da estrutura de dados compartilhada é compatível apenas
com a v3 versão de serialização de objeto
Map
Na versão de serializaçãomap, os dados compartilhados são serializados como uma única coluna do tipo Map(String, String), da mesma forma que são armazenados na
memória. Para ler uma subcoluna de caminho desse tipo de serialização, o ClickHouse lê toda a coluna Map e
extrai o caminho solicitado na memória.
Essa serialização é eficiente para gravar dados e ler toda a coluna JSON, mas não é eficiente para ler subcolunas de caminhos.
Map com buckets
Na versão de serializaçãomap_with_buckets, os dados compartilhados são serializados como N colunas (“buckets”) do tipo Map(String, String).
Cada bucket desse tipo contém apenas um subconjunto de caminhos. Para ler a subcoluna de um caminho nesse tipo de serialização, o ClickHouse
lê toda a coluna Map de um único bucket e extrai o caminho solicitado na memória.
Essa serialização é menos eficiente para gravar dados e ler a coluna JSON inteira, mas é mais eficiente para ler subcolunas de caminhos
porque lê dados apenas dos buckets necessários.
O número de buckets N é controlado pelas configurações do MergeTree object_shared_data_buckets_for_compact_part (8 por padrão)
e object_shared_data_buckets_for_wide_part (32 por padrão).
O valor máximo permitido para ambas as configurações é 256.
Avançado
Na versão de serializaçãoadvanced, os dados compartilhados são serializados em uma estrutura de dados especial que maximiza o desempenho
da leitura de subcolunas de caminhos, armazenando algumas informações adicionais que permitem ler apenas os dados dos caminhos solicitados.
Essa serialização também oferece suporte a buckets, de modo que cada bucket contenha apenas um subconjunto de caminhos.
Essa serialização é bastante ineficiente para gravação de dados (portanto, não é recomendável usar essa serialização para partes de nível zero); a leitura da coluna JSON inteira é ligeiramente menos eficiente em comparação com a serialização map, mas ela é muito eficiente para ler subcolunas de caminhos.
Observação: devido ao armazenamento de algumas informações adicionais dentro da estrutura de dados, o uso de espaço em disco é maior com essa serialização em comparação com as
serializações map e map_with_buckets.
Para uma visão geral mais detalhada das novas serializações de dados compartilhados e dos detalhes de implementação, leia a postagem no blog.
Advanced chunked
A serializaçãoadvanced_chunked é igual à advanced, mas com suporte à divisão de linhas em fragmentos menores durante a serialização.
Isso reduz o pico de uso de memória durante mesclagens de colunas JSON com muitos caminhos únicos, porque apenas os dados de um fragmento
precisam ser materializados por vez, em vez de todo o intervalo de linhas.
O tamanho do fragmento é controlado pela configuração do MergeTree object_shared_data_target_chunk_rows (8192 por padrão).
Esse não é um limite rígido: se o último fragmento ficar menor que a metade do valor-alvo, ele é mesclado com o fragmento anterior,
de modo que os tamanhos reais dos fragmentos variam de target/2 a 1.5 * target.
Controlando o número de caminhos dinâmicos dentro de JSON em partes do MergeTree
A principal forma de definir um limite para caminhos dinâmicos em JSON é usar o parâmetromax_dynamic_paths na declaração do tipo JSON.
Mas alterar max_dynamic_paths em colunas existentes exige executar ALTER TABLE <table> MODIFY COLUMN <column> JSON(max_dynamic_paths=K), o que iniciará uma mutação em segundo plano que reescreverá todas as partes existentes.
Essa mutação pode ser bastante pesada e pode afetar o desempenho do servidor até sua conclusão. Para evitar isso, você pode usar estas 3 configurações, que ajudam a alterar o limite de caminhos dinâmicos em tabelas MergeTree para novas partes de dados:
merge_max_dynamic_subcolumns_in_wide_part- uma configuração do MergeTree que limita o número de subcolunas dinâmicas de cada coluna JSON durante a mesclagem em uma parte de dados Wide.merge_max_dynamic_subcolumns_in_compact_part- uma configuração do MergeTree que limita o número de subcolunas dinâmicas de cada coluna JSON durante a mesclagem em uma parte de dados Compact.max_dynamic_subcolumns_in_json_type_parsing- uma configuração de sessão que limita o número de subcolunas dinâmicas de cada coluna JSON durante o parsing de dados JSON em uma coluna JSON.
max_dynamic_paths, mesmo que os valores das configurações descritas sejam maiores.
Funções de introspecção
Há várias funções que podem ajudar a inspecionar o conteúdo da coluna JSON:JSONAllPathsJSONAllPathsWithTypesJSONAllValuesJSONDynamicPathsJSONDynamicPathsWithTypesJSONSharedDataPathsJSONSharedDataPathsWithTypesdistinctDynamicTypesdistinctJSONPaths and distinctJSONPathsAndTypes
2020-01-01:
Query
Response
Query
Response
ALTER MODIFY COLUMN para o tipo JSON
É possível alterar uma tabela existente e mudar o tipo da coluna para o novo tipoJSON. Atualmente, só há suporte a ALTER de um tipo String.
Exemplo
Query
Response
Lazy Type Hints (Beta)
Este recurso está em beta e exige que a configuração
enable_json_lazy_type_hints esteja habilitada.ALTER TABLE ... MODIFY COLUMN, o ClickHouse normalmente reescreve todas as partes de dados para materializar os novos type hints. Em tabelas com grandes volumes de dados históricos (centenas de terabytes), isso pode ser extremamente custoso.
Lazy type hints permitem adicionar type hints como uma operação somente de metadados, sem reescrever os dados existentes:
- Partes antigas: os type hints são aplicados em tempo de consulta, convertendo de
Dynamicpara o tipo indicado - Partes novas: os type hints são materializados durante operações de
INSERT - Mesclagens: os type hints são materializados quando as partes são mescladas
Como habilitar Lazy Type Hints
Exemplo
Query
Response
Verificando se não ocorreu nenhuma mutação
Você pode verificar se oALTER foi concluído sem gerar uma mutação consultando a tabela system.mutations:
Materializando type hints
Para materializar type hints em dados existentes, você pode:- Aguardar as mesclagens em segundo plano: o ClickHouse materializa automaticamente os type hints quando as partes são mescladas
- Forçar a mesclagem: use
OPTIMIZE TABLE test_lazy FINALpara mesclar todas as partes imediatamente - Reescrever as partes: use
ALTER TABLE test_lazy REWRITE PARTSpara reescrever as partes com os novos metadados
Limitações
- A conversão de tipos no momento da consulta pode ter um impacto significativo no desempenho em comparação com tipos pré-materializados, especialmente para objetos JSON grandes
-
O recurso se aplica apenas à modificação de
typed_paths(type hints); outros parâmetros de JSON, comomax_dynamic_paths,SKIPouSKIP REGEXP, ainda exigem mutações -
Modificar uma type hint (ou remover um caminho tipado) não é uma operação somente de metadados e é rejeitado quando a subcoluna afetada é usada em uma estrutura persistida por posição:
- na chave primária/de ordenação ou chave de partição — a alteração é proibida, pois os valores do índice primário/da partição em disco não podem ser reconstruídos por um
ALTERsomente de metadados (como ocorre com qualquer outra coluna-chave); - em data skipping indexes explícitos — primeiro remova o índice ou desative
enable_json_lazy_type_hintspara executar a alteração como uma mutação completa que reconstrói o índice. - em uma projeção cuja chave de ordenação (
ORDER BY) lê a subcoluna — primeiro remova a projeção, pois umALTERsomente de metadados não pode reconstruir o índice primário da projeção.
- na chave primária/de ordenação ou chave de partição — a alteração é proibida, pois os valores do índice primário/da partição em disco não podem ser reconstruídos por um
Comparação entre valores do tipo JSON
Os objetos JSON são comparados de forma semelhante aos Maps. Por exemplo:Query
Response
Variant.
Data skipping indexes para JSON
Data skipping indexes podem ser usados com colunasJSON de três formas:
- Índices em subcolunas específicas — crie um skip index padrão em um caminho JSON conhecido, assim como em uma coluna comum. Isso indexa os valores desse caminho.
- Índices baseados em caminhos com
JSONAllPaths— indexe o conjunto de caminhos presentes em cada grânulo para ignorar grânulos que não possam conter o caminho consultado. - Índices baseados em valores com
JSONAllValues— indexe todos os valores em todos os caminhos JSON usando um índice de texto para acelerar a busca textual completa em qualquer subcoluna JSON com um único índice.
Índices em subcolunas específicas
Você pode criar um skip index em qualquer subcoluna JSON usando a mesma sintaxe usada para colunas regulares. Qualquer tipo de índice compatível funciona (minmax, set, bloom_filter, tokenbf_v1, ngrambf_v1, etc.).
Há duas maneiras de referenciar uma subcoluna JSON em uma expressão de índice:
- Caminho tipado declarado no type hint JSON — acesse-o diretamente pelo nome:
json.a. - Caminho dinâmico com cast explícito — use a sintaxe de cast
:::json.b::String.
json.a || json.b::String.
Exemplo
Query
minmax na subcoluna tipada data.sensor_id restringe a varredura aos grânulos correspondentes:
Query
Response
bloom_filter na subcoluna com cast data.location::String também funciona:
Query
Response
Índices baseados em caminhos com JSONAllPaths
Data skipping indexes também podem ser criados em colunasJSON usando a função JSONAllPaths.
Isso funciona de maneira semelhante à criação de skip indexes em colunas Map com mapKeys — o índice armazena o conjunto de caminhos JSON presentes em cada grânulo e o utiliza para ignorar os grânulos que não podem conter o caminho consultado.
Tipos de índice compatíveis
JSONAllPaths pode ser usado com os seguintes tipos de skip index:
bloom_filter— oferece suporte aequals,ineIS NOT NULL.tokenbf_v1— oferece suporte aequalseIS NOT NULL.ngrambf_v1— oferece suporte aequalseIS NOT NULL.text(índice invertido) — oferece suporte aequals,ineIS NOT NULL.
Exemplo
Query
EXPLAIN indexes = 1 para verificar se o skip index está sendo usado. Quando um caminho existe apenas em uma parte, o índice ignora a outra parte:
Query
Response
Query
Response
IS NOT NULL também usa o índice — ele ignora os grânulos em que o caminho não existe (já que o valor seria NULL):
Query
Response
Como funciona
A expressãoJSONAllPaths(json_column) produz um Array(String) que contém todos os caminhos presentes em um valor JSON.
O skip index armazena essas strings de caminho em sua estrutura de dados (filtro de Bloom ou índice invertido).
Quando uma consulta filtra por json.some.path, o índice verifica se a string "some.path" está presente no índice de cada grânulo e ignora os grânulos em que ela está ausente.
Apenas o acesso simples por caminho é comparado com o índice, opcionalmente com uma type hint ou um cast (json.a.b, json.a.b.:Int64, json.a.b::String).
Filtros sobre a subcoluna de sub-object (json.^a) e sobre a subcoluna combinada de literal+sub-object (json.@`a) não usam o índice: essas subcolunas não são NULL sempre que existir qualquer subcaminho de a, portanto a presença do próprio caminho a em JSONAllPaths não é uma condição equivalente.
Segurança com caminhos ausentes
Quando um caminho JSON está ausente de um grânulo, a subcoluna resulta em:NULLpara o tipoDynamic(por exemplo,json.path) e subcolunas tipadas comoNullable(por exemplo,json.path.:Int64) — comparações comNULLsempre retornam falso, portanto o skipping é seguro.- O valor padrão do tipo para expressões
CASTnãoNullable(por exemplo,json.path::Int64produz0quando o caminho está ausente) — o skipping é seguro apenas quando o valor comparado difere do valor padrão. O índice lida automaticamente com essa distinção.
Busca de texto completo com JSONAllValues
Índices de texto podem ser usados para acelerar a busca de texto completo em colunas JSON por meio da funçãoJSONAllValues.
JSONAllValues retorna todos os valores de uma coluna JSON como Array(String), que pode ser indexado com um índice de texto.
Um único índice em JSONAllValues(json_column) cobre todos os caminhos JSON, permitindo a busca de texto completo em qualquer subcoluna sem criar índices separados para cada caminho.
Consulte Índices baseados em valores com JSONAllValues na documentação sobre índices de texto para ver detalhes e exemplos.
Dicas para melhorar o uso do tipo JSON
Antes de criar a colunaJSON e carregar dados nela, considere as seguintes dicas:
- Analise seus dados e especifique o máximo possível de caminhos com tipos. Isso tornará o armazenamento e a leitura muito mais eficientes.
- Pense em quais caminhos você precisará e quais nunca precisará. Especifique os caminhos de que você não precisará na seção
SKIPe, se necessário, na seçãoSKIP REGEXP. Isso melhorará o armazenamento. - Não defina o parâmetro
max_dynamic_pathscom valores muito altos, pois isso pode tornar o armazenamento e a leitura menos eficientes. Embora isso dependa muito de parâmetros do sistema, como memória, CPU etc., uma regra geral é não definirmax_dynamic_pathsacima de 10 000 para o armazenamento no sistema de arquivos local e 1024 para o armazenamento no sistema de arquivos remoto.