Por que usamos elasticsearch para buscas?

Charles Silva
TechBlogHotmart
10 min readAug 30, 2018

--

A importância da busca

Todo mundo que utiliza a internet está sempre procurando por algo, muitas vezes no sentido literal, ou seja, digitando em algum mecanismo de busca para obter um retorno satisfatório. Segundo o internetlivestats, o Google (o maior site de buscas) chega a receber mais de 100 bilhões de buscas por mês (em números de 2012, já que a Google não exibe publicamente os números atuais do seu buscador). Um número impressionante que nos mostra o quão importante é um mecanismo de busca para os usuários.

Dado esta importância, os usuários possuem algumas exigências básicas:

  • Velocidade de resposta: mecanismos que demoram a dar um retorno ao usuário começam a serem desprezados, com o aumento do uso da internet com celular essa exigência se tornou mais forte, pois muitas pessoas não tem uma boa conexão.
    Alguns exemplos que nos mostra essa importância:
    - Para Amazon, 1s a mais no carregamento da página custa 1.6 bilhão de dólares por ano.
    - A expectativa de um comprador online em 2006 era de 4s para carregamento da página. Em 2010, 2s. Segundo uma pesquisa da Forrester Consulting.
  • Relevância do conteúdo: uma vez que os dados foram retornados, esperamos sempre que as melhores opções estejam no topo da resposta. É isso que chamamos de relevância. O sistema que executa a busca deve ser capaz de trazer a informação que julgar mais importante, geralmente utilizando algum critério por ele definido.

Como o elasticsearch pode ajudar?

Primeiro precisamos saber: o que é o elasticsearch?

No site oficial diz que o “Elasticsearch é um software open source, que provê uma interface RESTful de pesquisa e análise de dados capaz de solucionar um número crescente de casos de uso.”

É uma ferramenta poderosa, muito utilizada em busca de dados, com funcionalidades que ajudam a resolver as exigências básicas, como as que já foram citadas, de uma forma simples e robusta.

O Elasticsearch trabalha utilizando o Apache Lucene, uma biblioteca Java para manipular informações full-text search. Quem conhece o Lucene sabe que não é simples trabalhar com essa biblioteca.

De forma resumida, o full-text search é uma técnica utilizada para buscar ocorrências de palavras dentro de um texto.

É nesse ponto que o Elasticsearch nos ajuda, além de abstrair o uso da biblioteca, nos traz diversas features para trabalhar com buscas, ajudando também a cuidar de complexidades de gerenciamento e crescimento da infraestrutra necessária.

Algumas das features:

  • Prover suporte a thread-pool, queues, cluster, monitoramento;
  • Ser uma aplicação distribuída, altamente escalável de forma horizontal;
  • Alta disponibilidade;
  • Schema-less (não exige declaração do esquema a ser utilizado).

Algumas gigantes do mercado mundial que usam o Elasticsearch:

  • Netflix
  • Facebook
  • Dell
  • Airbus
  • Blizzard

Como Elasticsearch funciona?

Para ajudar a entender como ele manipula dados, podemos fazer uma analogia a um banco de dados.

O Elasticsearch armazena os dados utilizando o conceito de “schema-less”. Isso significa que não é necessário definir a estrutura dos dados que serão inseridos de maneira prévia, como acontece com bancos de dados relacionais conhecidos no mercado: MySQL, Oracle, SQLServer entre outros…

Fazendo uma analogia com os tradicionais bancos relacionais a estrutura dos dados utilizados pelo Elasticsearch seria:

  • Índices: são os banco de dados.
  • Tipos: a tabela do banco, talvez não exista mais no futuro, para versões mais novas é permitido apenas um tipo por índice, ou seja, não é mais o conceito de banco e tabelas.
  • Documentos: registros do banco de dados
  • Campos: colunas

Em versões antigas, o elasticsearch tratava tipos como tabelas. Porém, devido aos problemas causados por este entendimento, o elasticsearch resolveu descontinuar esse comportamento e atualmente um índice aceita somente um tipo, como pode ser visto aqui.

Falando um pouco da “infraestrutura” que o Elasticsearch nos oferece, temos alguns termos importantes para aprender:

  • Cluster: conjunto de nós, é o topo da hierarquia
  • Nós: entidades que armazenam os dados (normalmente cada nó é um computador, mas isso não é sempre verdade)
  • Shard: particionamento do dado dentro do nó (é também uma instância do Lucene).
  • Réplica Shard: Uma réplica exata de um shard primário armazenada em outro nó.
fonte:blog.logdna.com

Dado esta estrutura utilizada pelo Elasticsearch, podemos dizer que ele controla os dados salvos de maneira a utilizar de forma mais escalável e eficiente os recursos a ele oferecido.

Vejamos um exemplo:

Você pode ter 2 computadores (ou mais), cada um executando uma instância do Elasticsearch.

Um computador pode ser o nó master, ou seja, o responsável por comandar operações do cluster entre outras atividades.

O outro computador pode ser o nó “data” que armazena dados, mas não trabalha com gerenciamento do cluster. Não abordarei as funções dos tipos de nós dentro do cluster, estas informações rendem um novo post. É importante ressaltar que é obrigatório ter pelo menos um nó master no cluster e recomendado ter outros nós elegíveis para se tornarem master, uma vez que apenas um nó master pode se tornar ponto único de falha. Uma explicação detalhada pode se encontrada aqui.

Se mais recursos de hardware forem necessários, podemos adicionar mais computadores (nós) rodando instâncias do Elasticsearch ao cluster já existente.

Bom, agora o Elasticsearch com essa estrutura criada vai nos oferecer uma boa API para gerenciar os serviços.

Além da API de manipular os dados ser responsável por fazer a replicação, também cuidará do sucesso das transações, da saúde do cluster, entre outros trabalhos de gerenciamento.

Citando as principais APIs e suas funções:

  • Cluster API: operações a nível de cluster, como obter status dos nós.
  • Index API: responsável por manipular os índices, como salvar dados versionados.
  • Get API: permite buscar utilizando o método HTTP GET.
  • Bulk API: realizar operações para múltiplos índices e dados em um único request.

A configuração “default” da ferramenta foi construída para trabalhar de forma bem robusta, aceitando esse escalonamento horizontal. Mas se for necessário uma alteração, geralmente é bem simples.

Pode ser feita mudando propriedades do arquivo de configuração da aplicação ou através de chamadas REST da API.

Por que as buscas são tão rápidas com bons resultados?

Primeiro: porque o Elasticsearch foi construído para facilitar o gerenciamento das suas atividades de forma simples e eficiente conforme já explicamos, permitindo assim escalar a infraestrutura conforme necessidade.

Segundo: sua estrutura de armazenamento. Ele grava as informações de uma forma diferente dos tradicionais banco de dados relacionais, utilizando uma estrutura que chamamos de índice invertido.

Nesse caso o índice é o mesmo do banco de dados relacional, ou seja uma estrutura já conhecida, que ajuda a armazenar dados para usar futuramente.

Imagine uma tabela de “artigos”, com a seguinte estrutura:

Artigos

Agora imagine que queiramos pesquisar todos os artigos que contenha a palavra “Brasil” no título ou texto. Como faríamos em um banco de dados relacional?

Teríamos que utilizar um SQL parecido com esse:

SELECT * FROM artigo WHERE titulo LIKE ‘%Brasil%’ OR texto LIKE ‘%Brasil%’;

Neste caso, sabemos que utilizar índices nas colunas não será uma boa opção, principalmente na coluna “texto”, isso porque precisamos utilizar o operador “LIKE” envolvendo a busca sobre o wildcard “%”, o que traz um grande problema de performance, para saber mais detalhes do problema, leia esse artigo.

A consulta não será nada eficaz, já que o banco de dados terá que percorrer todos os registros para encontrar as palavras dentro das colunas.

Portanto, fará um fullscan na tabela e isso não será nada bom. Imagine que essa tabela tenha milhões de registros…

É nessa hora que nosso amigo índice invertido se destaca. Sua estrutura é montada através das palavras, chamadas de “termos” no Elasticsearch.

Estes termos são salvos contendo o endereço do documento, ficando parecido com isso:

Estrutura de armazenamento

Índice invertido do campo “texto”: omitido demais termos para facilitar o entendimento.

Como podemos ver, é criada uma estrutura de índice invertido para cada campo “indexado” do Elasticsearch. Essa estrutura contém as seguintes informações:

  • Termo: o termo em si. (Conforme abordaremos abaixo)
  • Frequência: quantidade de vezes que o termo aparece nesse campo, na soma de todos os documentos
  • Documentos: quais documentos possuem o termo.

O índice também armazena outras informações importantes para tratar relevância, mas, vamos escrever sobre elas em outro momento.

Você deve ter percebido que o valor salvo no termo foi “modificado”, ficando em minúsculo. Nesse caso ele utilizou o Standard Analyzer, que é o default para campos do tipo texto. É importante conhecer os tipos de campo existentes, se possuem suporte a analyze e qual se comportamento padrão, a lista dos tipos podem se encontradas aqui.

O Elasticsearch aplica algumas regras para salvar cada palavra de forma separada e simples para futuras buscas. É o que chamamos de processo de analyze, que abordaremos com mais detalhes daqui a pouco.

Com essa estrutura é possível ver o porque o Elasticsearch é tão rápido para buscas: ele já tem o termo salvo e quais documentos o possui, não sendo necessário fazer uma fullscan nos dados.

Claro, o ES possui uma implementação eficaz para trabalhar com dados na memória e manipular os dados no sistema operacional, mas sem dúvidas o fato de trabalhar com índices invertidos o faz ser mais apropriado para buscar do que bancos relacionais.

Por que a relevância do resultado é tão boa?

Conforme vimos na seção anterior, as “palavras” são salvas no índice de forma separada das demais, mesmo que estejam no mesmo documento e na mesma coluna, o Elasticsearch irá “quebrar” um texto em termos para que consiga criar esse índice.

Para separar essas palavras do texto ele utiliza uma técnica chamada Analyzer, essa técnica é responsável por processar o texto que está sendo salvo. O Analyzer default, chamado de “Standard Analyzer” é o detalhe do seu funcionamento pode ser visto aqui.

De forma geral o que o Analyzer faz é:

  • Separar as palavras (geralmente por espaço);
  • Deixar as palavras em minúsculo;
  • Remover acentos;
  • Remover artigos

Esses são alguns dos principais procedimentos realizados pelos Analyzers e existem vários tipos. Cada um possui seu grupo de regras a aplicar nos dados, você também pode criar seu próprio Analyzer utilizando um conjunto de regras já existentes ou até mesmo criar suas regras.

Com isso, o Elasticsearch consegue armazenar palavras de forma bem uniforme. Veja como ficaria o seguinte texto: “The 2 QUICK Brown-Foxes jumped over the lazy dog’s bone.”

Os termos ficariam assim:

[ the, 2, quick, brown, foxes, jumped, over, the, lazy, dog’s, bone ]

Perceba que o procedimento separou as palavras e aplicou as regras citadas antes de salvar o termo.

Outro exemplo: as palavras [“América”, “America”, “america”] seriam armazenadas como [“america”]. Mas como o Elasticsearch vai achar o resultado se na busca eu digitar “América” e o termo salvo é “america”?

Bom, nesse caso o Elasticsearch irá aplicar as mesmas regras quando for buscar o resultado, ou seja, mesmo que você busque por “América” ele irá pesquisar por “america”, retornando o dado.

Como a ferramenta é muito flexível é possível também escolher aplicar o processo só no momento do insert ou da busca. Em alguns cenários isso pode ser interessante, é muito utilizado por exemplo em implementação de buscas de autocomplete ou sugestões.

Para passar pelo processo de Analyzer, o campo deve ter sido marcado no mapeamento para ser um campo do tipo “analisado”. Por padrão os campos “textos” já são. Se quisermos que o processo não se aplique, é necessário deixar explícito no mapeamento. Campos que não são do tipo de texto é importante verificar se o padrão é de ser ou não “analisado”.

Para chegar em uma boa relevância o Elasticsearch aplica o conceito de score, para cada resultado ele dá uma nota de sua relevância.

Para atingir esse valor ele aplica algumas outras técnicas, conforme descrito na documentação:

Frequência de termo

Com que frequência o termo aparece no campo? Quanto mais vezes, mais relevante. Um campo contendo 5 menções do mesmo termo tem mais chance de ser relevante do que um campo contendo apenas uma menção.

Frequência de documento inversa

Com que frequência o termo aparece no índice? Quanto mais, menos relevância. Termos que aparecem em muitos documentos tem um peso menor do que os que aparecem em menos documentos.

Comprimento do campo

Qual tamanho do campo? Quanto mais palavras no campo, menos relevância o campo tende a ser. Um termo que aparece, por exemplo, em um título tende a ser mais relevante do que aparecer em um campo de descrição.

Além dessas técnicas citadas o Elasticsearch possui diversas configurações para dar peso a um determinado campo.

Imagine na tabela de artigo, um termo encontrado no título pode ter um score maior que um termo encontrado na coluna de texto. Lembrando que essa é apenas uma configuração, você tem diversas opções de score.

Devo migrar meu banco de dados atual?

O processo de utilização do Elasticsearch deve ser bem pensado. Geralmente, as pessoas o utilizam como um banco de dados secundário, cujo o objetivo será atender as funcionalidades que requerem uma busca mais eficiente, robusta.

Com isso, a maior parte dos sistemas continuam trabalhando com seu banco de dados principal e replicando os dados no Elasticsearch para essas necessidades. Essa replicação acontece de forma a salvar somente o que é relevante para o contexto de buscas e é feita pensando na melhor estrutura de dados para o cenário.

Elasticsearch é só para buscas?

Não. Como consta na própria documentação da empresa responsável “é utilizado para muitos casos além de full-text search, como analytics, auto complete, spell checker, engine de alerta, armazenamento de logs, etc”.

Conclusão

O Elasticsearch é uma ferramenta simples de configurar, possui uma flexibilidade incrível e é uma excelente opção para se trabalhar com busca de dados.

Tem o poder de executar consultas de maneira rápida e com excelente relevância dos resultados. A comunidade é participativa nos fóruns e possui uma excelente documentação.

Há vários artigos que explicam cada detalhe do que tratamos aqui de maneira geral. Você pode continuar nos acompanhando para receber mais conteúdos sobre o tema.

Observação: Quando esse texto foi escrito a versão corrente do Elasticsearch era 6.4

--

--