A matriz é O diferença entre o modelo relacional e o modelo JSON. - Gerald Sangudi

Resumo

A matriz JSON oferece flexibilidade quanto ao tipo de elementos, ao número de elementos, ao tamanho dos elementos e à profundidade dos elementos. Isso aumenta a flexibilidade dos bancos de dados JSON operacionais, como o Couchbase e o MongoDB. O desempenho de consultas com um predicado de matriz em bancos de dados operacionais depende dos índices de matriz. No entanto, os índices de matriz nesses bancos de dados vêm com limitações. Por exemplo, somente uma chave de matriz é permitida por índice. Os índices de matriz, mesmo quando criados, só podem processar predicados AND com eficiência. A próxima versão do Couchbase 6.6 remove essas limitações do JSON usando um índice invertido integrado para ser usado para indexar e consultar arrays no N1QL. Este artigo explica o histórico e o funcionamento dessa nova implementação.

Introdução

Uma matriz é um tipo básico incorporado ao JSON definido como Um matriz é uma coleção ordenada de valores. Uma matriz começa com [suporte esquerdo e termina com ]suporte direito. Os valores são separados por ,vírgulaUma matriz lhe dá flexibilidade porque pode conter um número arbitrário de valores escalares, vetoriais e de objetos. Um perfil de usuário pode ter um array de hobbies, um perfil de cliente um array de carros, um perfil de membro um array de amigos. O Couchbase N1QL fornece um conjunto rico de operadores para manipular matrizes; o MongoDB tem uma lista de operadores para lidar com matrizes também.

Antes de começar a consultar, você precisa modelar seus dados em matrizes. Todos os bancos de dados de documentos JSON, como o Couchbase e o MongoDB, recomendam que você desnormalize seu modelo de dados para melhorar o desempenho e o desenvolvimento de aplicativos. Isso significa que você deve transformar sua relação 1:N em um único documento, incorporando o N em 1. No JSON, você faria isso usando uma matriz. No exemplo abaixo, o documento (1) contém 8 (N) curtidas. Em vez de armazenar uma referência de chave estrangeira para outra tabela, no JSON, armazenamos dados em linha. 

Os valores aqui são matrizes de strings. Em JSON, cada elemento pode ser de qualquer tipo válido de JSON: escalares (numérico, cadeia de caracteres etc.), objetos ou vetores (matrizes). Cada documento de hotel contém uma matriz de avaliações. Esse é o processo de desnormalização. Conversão de várias relações 1:N em um único objeto de hotel que contém N public_likes e M avaliações. Com isso, o objeto hotel incorpora duas matrizes: public_likes e avaliações. Pode haver qualquer número de valores de qualquer tipo nessas matrizes. Esse é o principal fator que contribui para a flexibilidade do esquema JSON. Quando você precisar adicionar novas curtidas ou avaliações, basta adicionar um novo valor ou um objeto a esse array. 

Assim como o objeto hotel acima, você desnormaliza seu modelo de dados em JSON, podendo haver muitas matrizes para cada objeto. Os perfis têm matrizes para hobbies, carros, cartões de crédito, preferências etc. Cada uma dessas matrizes pode ser escalar (valores numéricos/string/booleanos simples) ou vetorial (matrizes de outras escalares, matrizes de objetos etc.). 

 

Depois de modelar e armazenar os dados, você precisa processá-los - selecionar, unir, projetar. Couchbase N1QL (SQL para JSON) oferece uma linguagem expressiva para fazer isso e muito mais. Veja a seguir os casos de uso comuns.

Indexação de matrizes:

As matrizes de indexação são um desafio para os índices baseados em árvore B. No entanto, o banco de dados JSON precisa fazer isso para atender aos requisitos de desempenho: O MongoDB faz isso; O Couchbase faz isso. No entanto, ambos têm limitações. Você só pode ter uma chave de matriz em um índice. Isso é verdadeiro do MongoDBIsto é verdadeiro do Couchbase N1QL. O principal motivo dessa limitação é que, quando você indexa elementos de uma matriz, precisa de entradas de índice separadas.  

O tamanho do índice cresce exponencialmente conforme o número de chaves da matriz no índice e o número de elementos da matriz no índice. Daí a limitação. As implicações dessa limitação são: 

  • Empurre apenas um predicado de matriz para a varredura de índice e trate os outros predicados após a varredura de índice.
    • Isso significa que as consultas com vários predicados de matriz podem ser lentas
  • Evite índices compostos com chaves de matriz para evitar índices enormes.
    • Isso significa que as consultas com predicados complexos em chaves de matriz serão lentas

Boas notícias do CAMPO ESQUERDO.

O índice de pesquisa de texto completo foi projetado para lidar com a pesquisa de padrões de texto com base na relevância. Isso é feito por meio da tokenização de cada campo. No exemplo abaixo, cada documento é analisado para obter tokens:

Para cada token, ele mantém a lista de documentos em que o token está presente. Essa é a estrutura de árvore invertida! Ao contrário de um índice baseado em árvore B, ele evita repetir o mesmo valor de token um número N de vezes, um para cada documento em que ele está presente. Quando se tem milhões ou bilhões de documentos, isso representa uma enorme economia. 

O segundo aspecto a ser observado aqui é que o índice invertido usado para um conjunto de tokens!    De fato, a estrutura de árvore invertida na pesquisa de texto completo é ideal para indexação e pesquisa de valores de matriz, especialmente quando esses valores têm duplicatas. 

A indexação de matrizes usando o índice invertido será o mesmo processo, exceto pelo fato de não haver tokenização. Vamos revisitar a indexação do nosso documento "bob", com documentos adicionais, "Sam" e "Neill"

O Couchbase FTS tem um analisador chamado analisador de palavras-chave. Isso indexa os valores no estado em que se encontram, em vez de tentar encontrar sua raiz por meio de stemização. Basicamente, o valor é o token. Para indexação de valores de matriz, podemos usar esse índice e explorar as eficiências de um índice invertido. Vamos construir um índice FTS nos documentos bob, sam, neil.  No caso da árvore invertida, cada campo recebe sua própria árvore invertida: uma para id, a e b. Como essas árvores são individuais, elas não crescem exponencialmente como o índice composto da árvore B. O número de entradas de índice é proporcional ao número de itens exclusivos em cada campo. Nesse caso, temos 14 entradas para os 3 documentos com três campos de um total de 24 valores. A criação de um índice de árvore B em (id, a, b) para o mesmo documento criará 36 inscrições!

Observe que, para três documentos com duas entradas de índice, a diferença é de 157%. À medida que o número de documentos e o número de matrizes aumentam, a economia com o uso de um índice invertido também aumenta.

Inverted index on three fields.

Índice invertido em três campos.

No entanto, temos um problema.  Como você processa os predicados?

O índice B-Tree armazena todos os valores em (id, a e b) juntos, enquanto o índice invertido no FTS tem árvores distintas para cada campo. Portanto, aplicar vários predicados não é tão fácil. Isso se aplica ao nosso processamento de matriz, bem como ao processamento de texto. É comum no processamento de texto fazer perguntas como: search for all Californiano residentes com esqui como seus hobby.

Para processar isso, o FTS aplica o predicado em cada campo individualmente para obter a lista de chaves de documento para cada predicado. Em seguida, ele aplica o predicado booleano E em cima dela. Essa camada usa o famoso pacote de bitmap roaring para criar e processar o bitmap de ids de documentos para finalizar o resultado. Sim, há um processamento extra aqui em comparação com um índice mais simples baseado em B-TREE, mas isso torna possível indexar muitas matrizes e processar a consulta em um tempo razoável.

Árvore invertida: Uma árvore que continua presenteando!

O índice composto B-Tree combina a varredura e a aplicação do predicado AND. A abordagem de árvore invertida separa os dois. O índice e a varredura de cada campo são diferentes do processamento do predicado composto. Devido a essa separação, a camada de bitmap pode processar predicados OR, NOT juntamente com predicados AND. Alterar o AND no exemplo anterior para OR é simplesmente uma instrução para o processamento de bitmap na qualificação e deduplicação do documento

Lançamento do COUCHBASE:

O Couchbase 6.6 oferecerá suporte ao uso de índices FTS para processar predicados de matriz complexos. Isso melhora o custo total de propriedade do manuseio de matrizes e permite que os desenvolvedores e designers usem, indexem e consultem matrizes conforme necessário, sem limitações. Aguarde os próximos anúncios, documentação, blogs de recursos, etc.

Referências

  1. Trabalhando com matrizes JSON no N1QL
  2. Utilização de matrizes: Modelagem, consulta e indexação
  3. Operadores de coleção N1QL do Couchbase
  4. MongoDB: Consultar um array
  5. Couchbase FTS
  6. GRÁTIS: Treinamento interativo do Couchbase
  7. FTS BLogs:  https://www.couchbase.com/blog/tag/fts/
  8. Operadores de coleta
  9. Indexação ARRAY
  10. Aproveitando ao máximo suas matrizes... com a indexação de matrizes N1QL
  11. Aproveitamento máximo de suas matrizes com índices de matrizes de cobertura e muito mais.
  12. Indexação do Couchbase
  13. NEST e UNNEST: normalização e desnormalização de JSON em tempo real

Autor

Postado por Keshav Murthy

Keshav Murthy é vice-presidente de P&D da Couchbase. Anteriormente, ele trabalhou na MapR, IBM, Informix e Sybase, com mais de 20 anos de experiência em design e desenvolvimento de bancos de dados. Ele liderou a equipe de P&D de SQL e NoSQL na IBM Informix. Recebeu dois prêmios President's Club na Couchbase e dois Outstanding Technical Achievement Awards na IBM. Keshav é bacharel em Ciência da Computação e Engenharia pela Universidade de Mysore, Índia, detém dez patentes nos EUA e tem três patentes pendentes nos EUA.

Deixar uma resposta