As pessoas não querem um índice de quatro teclas. Elas precisam de uma resposta em quatro ms.

Ted Levitt

O desenvolvimento de aplicativos é exigente. Cada aplicativo está tentando progredir em nome do cliente - procurando o produto certo ou o formulário certo, fazendo pedidos, cancelando, enviando, verificando o status etc.

A consulta típica e os bancos de dados e a infraestrutura baseados em B-Tree são adequados para o desenvolvimento de muitos dos módulos. Ainda assim, há casos em que a pesquisa baseada em SQL e B-Tree é ineficaz para atender ao seu SLA.

Aqui estão os sete problemas que você encontraria no desenvolvimento de SQL e as soluções para eles usando a tecnologia de pesquisa. Usei o Couchbase N1QL como exemplo de implementação de SQL, o Couchbase GSI como exemplo de índices baseados em B-Tree (logicamente falando) e o FTS (Couchbase Full-Text Search) como exemplo de tecnologia de pesquisa.

Também usarei o amostra de viagem modelo e dados no conjunto de dados de amostra do Couchbase nos exemplos.

Desafios do desenvolvedor

1. O problema de pesquisa NAME (também conhecido como o problema LIKE)

A mídia social pode gostar de como frequentemente, mas o SQL não. Os predicados do tipo LIKE são uma das primeiras coisas a serem observadas quando são usados em uma consulta. Sem um uso cuidadoso, o predicado LIKE aumentará a latência, reduzirá a taxa de transferência e encerrará sua operação. Aqui está um exemplo de predicados LIKE que vi em aplicativos reais de clientes.

  • WHERE name LIKE "%joe%";
  • WHERE UPPER(name) LIKE "%JOE%"
  • WHERE REGEX_CONTAINS(name, ".*joe.*")
  • WHERE name LIKE "% joe %"

Problemas:

  • Mesmo quando você tiver um índice sobre o nome, terá que verificar todo o índice para determinar todos os documentos com joe.
  • Você teria que criar um índice funcional (por exemplo, UPPER(name)) e ter a chave adicional com o nome para salvar o caso exato do nome. Por exemplo, McDonald
  • Com os três primeiros predicados, você obterá não apenas joe, mas também as cadeias de caracteres joel, sojoel, bejoel etc.

2. O problema de combinações múltiplas

Quando os nomes são divididos em nome, nome do meio e sobrenome, você precisa pesquisar em todos os lugares. Às vezes, você deseja pesquisar uma cadeia de caracteres em qualquer um dos nomes. Combine isso com a correspondência do número de chamada. Sua consulta será semelhante a esta.


SELECT c.customerid, c.fname, c.mname, c.lname, c.address
FROM customer c
WHERE (c.fname in ['John', 'Doe']
     OR c.mname in ['John', 'Doe']
     OR c.lname in ['John', 'Doe'])
     OR (ANY p in c.contacts satisfaz p = '6509264813')
     OR (ANY q in c.services satisfaz q = '6509264813')

Agora, tente criar um índice B-TREE que ofereça não apenas a baixa latência que você deseja, mas também uma alta taxa de transferência.  

3. Além da correspondência exata

As correspondências no mundo real são inexatas. William pode ser abreviado como Will, Willy, Bill e Billy. Os irlandeses e os escoceses têm abreviações adicionais. Como você procura por Billy e acaba encontrando um William?


4. Pesquisa com base em requisitos comerciais

Cada empresa tem regras para resolver as informações do cliente (nome, endereço e data de nascimento) para um cliente específico. Algumas dão maior prioridade ao endereço, outras ao nome ou endereço. As regras podem dizer que dois dos quatro devem ser uma correspondência exata e os outros devem ser uma correspondência parcial. Os predicados N1QL tornam-se ainda mais complexos do que no segundo caso. Portanto, o índice GSI adequado para a consulta também se torna complicado.

5. Ordem de relevância

A ordenação do N1QL é baseada na cláusula ORDER BY e na expressão dentro dela. Quando estiver fazendo uma correspondência inexata, talvez queira que a ordem se baseie na pontuação do texto e na distância do padrão de pesquisa fornecido.

6. O problema da matriz.

As matrizes JSON permitem que você armazene as relações 1:N, N:M como uma matriz de objetos ou matrizes com links para outros objetos. Este artigo fornece detalhes sobre a manipulação de matrizes. O segundo artigo descreve outras operações orientadas a conjuntos em matrizes. Para obter o melhor desempenho ao pesquisar dentro de matrizes, você precisa criar índices com chaves de matriz. O índice de matriz vem com uma limitação: cada índice de matriz só pode ter uma chave de matriz por índice. Portanto, quando você tem um objeto de cliente com vários campos de matriz, não é possível pesquisar todos eles usando um único índice. Quando você tem clientes com uma matriz de números de contato e uma matriz de contatos de e-mail, não é possível pesquisar por ambos usando um único índice, o que causa consultas caras. Essa é uma limitação comum dos índices de matriz baseados em b-tree. Como o índice da árvore B armazena elementos de matriz individuais como chaves distintas, ter várias chaves de matriz exigirá que o índice armazene o produto do número de chaves (no exemplo acima, (número de números de contato) * (número de e-mails). O tamanho do índice aumentará exponencialmente. Para evitar isso, os produtos desabilitam a criação de várias chaves de matriz para um único índice.

No entanto, o trabalho do desenvolvedor de procurar com eficiência em várias matrizes JSON permanece.

7. Várias consultas, índice único.

O modelo JSON tem sido usado com sucesso para agregar informações de várias fontes. O objetivo de agregar todas essas informações não é simplesmente armazená-las, mas consultá-las e obter valor comercial. Quando se tem uma consulta ad-hoc em um conjunto de dados, é difícil planejar previamente e recriar os índices necessários para ela. O próprio N1QL fornece o índice adaptativo que ajuda em determinados casos de uso. Se você tiver vários predicados, cada um dos quais pode retornar um grande conjunto de resultados, o índice adaptável terá problemas de desempenho devido à quantidade de transferência de dados do índice para o nó de consulta e ao grande conjunto de resultados intermediários.

Nesse caso, os desenvolvedores precisam monitorar e ajustar continuamente os índices. Os usuários com problemas de desempenho continuarão a reclamar.

 

Soluções:

1. o problema de pesquisa NAME (também conhecido como o problema LIKE)

Se você estiver pesquisando joe, Joel ou jolly, todas elas tendem a ser palavras individuais. Normalmente, você não está procurando por lajoelholla. O índice de pesquisa pega cada palavra em seu campo (nome, título ou comentário), analisa-a com base nas características do idioma, categoriza as palavras em stop words (desinteressantes e que não costumam ser pesquisadas - por exemplo: and, or, not, the em inglês) e termos. Indexar o termo em vez da palavra real tem dois benefícios.

  1. Ele agrupa as palavras relacionadas: Francisco, francisco, franco, francisco, etc. Ao pesquisar por francisco, você também encontrará palavras intimamente relacionadas Francisco.
  2. Esse agrupamento também reduzirá o tamanho do índice porque só precisamos indexar o termo raiz em vez de todos os modificadores dessa palavra.

De volta à pesquisa de nomes: Vamos agora pesquisar o nome do hotel.

  1. Criar um índice FTS em documentos do tipo 'hotel' e o campo nome no documento.
  2. Comece a pesquisar pelo nome:
    • Aqui está a consulta a ser executada:

curl -XPOST -H "Content-Type: application/json" \ http://172.23.120.38:8094/api/index/trhotelname/query \ -d '{ "explain": true, "fields": [ "*" ], "highlight": {}, "query": { "query": "francisco" } }'

  1. Procurando por francisco fornece os nomes dos hotéis:
      • "nome": "The Opal San Francisco",
      • "nome": "Francisco Bay Inn",
      • e mais (totalmente 11 resultados).
      •  

2) O problema de várias partidas

Vimos a consulta complexa anteriormente.

SELECT c.customerid, c.fname, c.mname, c.lname, c.address
FROM customer c
WHERE (c.fname in ['John', 'Doe']
     OR c.mname in ['John', 'Doe']
     OR c.lname in ['John', 'Doe'])
     OR (ANY p in c.contacts satisfaz p = '6509264813')
     OR (ANY q in c.services satisfaz q = '6509264813')

No FTS, podemos definir um campo especial _all que combina vários campos. A pesquisa nesse índice pesquisa automaticamente em TODOS os campos. (Consulte também este artigo) Este é um índice de cinco campos no documento do hotel:

  1. cidade
  2. país
  3. nome
  4. public_likes (um campo de matriz)
  5. descrição

Exemplo de valores para os cinco campos:

[
{
"cidade": "Medway",
"country": "United Kingdom" (Reino Unido),
"description": "Albergue de verão com 40 leitos a cerca de 5 km de Gillingham, instalado em uma distinta Oast House convertida em um ambiente semi-rural.",
"name": "Medway Youth Hostel",
"public_likes": [
"Julius Tromp I",
"Corrine Hilll",
"Jaeden McKenzie",
"Vallie Ryan",
"Brian Kilback",
"Lilian McLaughlin",
"Sra. Moses Feeney",
"Elnora Trantow"
]
}
]

Depois que você definir o índice de pesquisa em todos esses campos, basta começar a consultar.

 

 

 

 

Esta é a definição de índice para o índice do campo _all usado aqui.

 

 

 

3. Além da correspondência exata

Search (FTS) faz mais do que uma pesquisa exata. Ela faz a pesquisa de termos, pesquisa de intervalos, pesquisa difusa, conjunções, disjunções, pesquisa geográfica (vizinho mais próximo), pesquisa regex, pesquisa impulsionada, pesquisa de frases e muito mais. Veja exemplos e detalhes em Documentação do Couchbase FTS.

4. pesquisa com base em requisitos comerciais (seus)

Quando estiver pesquisando hotéis em Nova York, talvez prefira hotéis em Manhattan, mas também queira ver outros hotéis. Agora, basta aumentar o termo de pesquisa Manhattan acrescentando ^5. Esse aumento melhora a pontuação dos documentos que contêm Manhattan. Por padrão, os resultados são ordenados em ordem decrescente de pontuação.

5. Ordenação de relevância

No SQL, a ordenação é baseada no valor da expressão ou do próprio campo. Na pesquisa, a relevância de um documento é calculada pela distância entre o que você está pesquisando e o que o documento contém. Essa é a pontuação que manipulamos ao aumentar a importância de um termo na seção anterior. Você pode classificar os resultados por essa pontuação e qualquer outro campo, usando a cláusula de classificação da solicitação de pesquisa.

6. o problema da matriz

Agora, vamos criar um único índice nas quatro matrizes a seguir.

  1. public_likes
  2. reviews.author
  3. comentários.classificações.localização
  4. comentários.classificações.serviço

Aqui está a definição do índice. Esse é um índice único em quatro chaves de matriz. Isso é algo que você nunca poderia fazer em um índice baseado em árvore B.

Agora, você pode fazer consultas usando predicados em um ou mais dos campos acima.

EXEMPLO 1: hotéis curtidos por "Vallie Ryan" ou classificação de serviço superior a 4

‘{
"explain": verdadeiro,
"fields": [ "*" ],
"highlight": {},
"query" (consulta): { "query": "+public_likes:\"Vallie Ryan\" reviews.ratings.Service:>4″ }
}’

Definição do índice completo.

 

7. várias consultas, índice único.

"Às vezes, as consultas são como uma caixa de chocolates. Você não sabe qual consulta vai receber." Quando se deseja expor os dados a usuários corporativos que podem fazer consultas ad hoc, não é possível criar todo tipo de índice para acelerar todo tipo de consulta. O ajuste de desempenho requer uma abordagem diferente.

Considere o índice criado na seção (2) acima sobre os 5 campos:

  1. cidade
  2. país
  3. nome
  4. public_likes (um campo de matriz)
  5. descrição

Se você criasse uma árvore B (índice GSI no caso do Couchbsae), ela teria a seguinte aparência:

CREATE INDEX itravel ON amostra de viagem(city, country, name, DISTINCT public_likes, description) WHERE type = 'hotel';

As consultas que se beneficiariam com isso são as seguintes regras explicadas aqui. O principal problema é que cada bloco de consulta (especificamente a varredura do índice) terá de usar predicados nas principais chaves do índice. Isso limita a eficácia do índice.

Com o índice search(FTS) criado acima, você pode fazer consultas com base em quaisquer conjutos, disjuntos, must have etc. com qualquer combinação. Com consultas complexas, a pesquisa pode levar mais do que alguns milissegundos, mas você está fazendo tudo isso em um único índice. A flexibilidade com o uso razoável de recursos torna o índice de pesquisa muito valioso.

Observação: Na próxima versão 6.5 do Couchbase, facilitamos a consulta usando o índice de pesquisa. Binh Le explicou isso neste artigo:https://www.couchbase.com/blog/n1ql-and-search-how-to-leverage-fts-index-in-n1ql-query/

Referências

 

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