Elasticsearch

Usando Elasticsearch para escalar campanhas automáticas de marketing

Oi, eu sou Goku, digo Regina 😅 Trabalho na Engenharia da Social Miner e esse é o meu primeiro post na vida! Que tenso! Aqui estou eu pra falar um pouquinho sobre Elasticsearch, então bora lá.

Shay Benon trabalhava no repositório de dados NoSQL chamado Apache Lucene e percebeu a necessidade de uma interface mais amigável, basicamente essa é a origem do projeto open-source que conhecemos como Elasticsearch com utilização simplificada através de uma API Restful, requests e responses em formato JSON, sem contar o fato de que não é apenas uma interface para rodar sobre o Lucene e atualmente serve também de ferramenta de Big Data.

A arquitetura do Elasticsearch é basicamente composta por um cluster de máquinas contendo nós, que são as instâncias do próprio ES, responsáveis por coordenar o funcionamento dos shards. Os shards, por sua vez, são instâncias do Apache Lucene onde ficam os dados em modo de escrita, os dados para leitura ficam disponíveis em réplicas.

Cluster Elasticsearch
Cluster Elasticsearch

Tratando-se de um repositório orientado a documentos, sua estrutura é semelhante a outros da categoria, como o MongoDB, por exemplo. Os dados são organizados em índices, que por sua vez, são divididos em tipos. Comparado a um banco relacional, podemos dizer que índices são equivalentes a bancos de dados, os tipos equivalem a tabelas e os documentos são como registros dentro das tabelas.

Até aqui sem grandes novidades. O diferencial do Elasticsearch está à partir do processo de gravação de registros. Nele, você cria uma frase (registro) e essa frase é dividida em palavras e essas palavras sim, serão indexadas no que conhecemos como índice invertido. Quando você realiza uma busca, o ES retorna todos os documentos que contém a palavra buscada.

Mesmo que baseado em documentos, ao trabalhar com Elasticsearch você precisa de um schema mínimo para lidar com os campos dentro do seu documento, isso porque o ES pode até reconhecer o formato de datas, booleanos e números, mas para todos os outros campos, o tratamento será de string. Em um cenário onde um Id é um guid, por exemplo, a busca poderia retornar resultados errados simplesmente porque o id procurado é semelhante a vários outros. Para antecipar esse tipo de problema, opcionalmente podemos criar mapeamentos dos principais campos descrevendo como queremos a leitura dos mesmos usando os analysers, que são, resumidamente:

Standard: ‘quebra’ o texto baseando-se em traços, pontos, espaços e passa tudo para letra minúscula.
Simple: ‘quebra’ o texto, mas mantém apenas strings, ou seja, números, datas e booleanos encontrados no meio da frase serão ignorados.
Whitespace: ‘quebra’ o texto baseado somente em espaço em branco.
Language: consegue compreender melhor um determinado idioma, o default é inglês, mas pode ser configurável.

Uma vez configurados os principais campos do documento, começa a brincadeira: se tratando de um repositório distribuído, os requests de input chegam até o nó master que passa o request para o nó com menor carga. Esse nó secundário (em alguns casos pode sim ser o nó master) envia o documento para o shard que escreve a informação e passa o documento para a réplica. Na réplica a operação é finalizada e o status é enviado de volta por todo o percurso até chegar ao nó master, e por fim gerar uma resposta.

Pipeline de request Elasticsearch
Pipeline de request Elasticsearch

Depois de toda essa viagem para gravar dados, vêm a leitura, que também apresenta peculiaridades de acordo o tipo de busca, mas isso você pode buscar na documentação do Elasticsearch disponível no site https://www.elastic.co/learn que, diga-se de passagem, possui uma vasta (e atualizada) documentação que vale a pena ser consultada. Voltando ao processo de busca, o request chega ao nó master e é disparado de forma assíncrona para todos os nós. Cada nó é responsável por buscar a informação em suas respectivas réplicas e atribuir a cada resposta uma pontuação de proximidade entre busca e resultado. Qualquer que seja a resposta dos nós, quando pronta a resposta é enviada ao nó master que por sua vez, agrega todas as respostas em um único resultado e retorna essa informação.

Pipeline de resposta Elasticsearch
Pipeline de resposta Elasticsearch

Tudo parece legal, mas ainda está meio vago? Vamos ver como a Social Miner tem usado o Elasticsearch em nossas campanhas automáticas 👍

Uma das campanhas automáticas que a plataforma da Social Miner disponibiliza é campanha de produtos mais acessados (top trending). A idéia geral é que dado um período e alguma(s) palavra(s) chave, além de outros filtros opcionais, os nossos algoritmos detectem os produtos mais acessados, descubram quem ainda não viu esses produtos, mas que tenham interesses correlatos.

Existem é claro, diversas soluções possíveis para isso, desde formas de armazenamento a pré-processamentos e consolidação de dados, mas é importante frisar que os dois fatores mais importantes dessa operação são variáveis que impactam diretamente na performance da busca afinal estamos lidando com strings em um range de dados que pode variar de 2 milhões de logs diários multiplicados pelo número de dias do período de interesse. Então como tratamos isso?

Dentro de um banco de dados tradicional não faz sentido algum eu separar arquivos de dados de um mesmo tipo, pura e simplesmente por conta do seu volume, mas dentro do ES, dados volumosos como os logs de navegação podem ser divididos em índices separados por data, que reduz de forma expressiva os dados que sobem em memória. Pode-se dizer que o problema de data está resolvido. Se em um DB tradicional é necessário ler e filtrar o campo de data, com esta configuração se torna possível acessar diretamente o grupo registros de interesse.

Com relação ao problema com as palavras chave, a solução está em um termo que mencionei anteriormente como índice invertido. Em um DB tradicional eu teria que usar uma regex (nada performática) para identificar pequenos trechos dentro da URL ou teria que quebrar a URL em palavras a fim de realizar qualquer busca com uma velocidade minimamente aceitável. Lembrando que o Elasticsearch trata documentos como frases e que os analysers configurados permitem dividir essas frases em palavras. O que acontece quando indexamos um documento é que quando enviar como input a url “http://socialminer.com”, o ES gravar o documento completo, mas vai indexar como no esquema abaixo e ainda que eu precise usar uma expressão regular, para localizar apenas o termo “social”, por exemplo, será muito mais performático porque a quantidade de caracteres testados é menor.

Índice invertido Elasticsearch
Índice invertido Elasticsearch

Lembrando que, no fim do dia, um índice nada mais é do que uma tabela chave-valor e que ocupa sim algum espaço, é importante criar mapeamentos específicos de forma a não permitir que o analyser padrão indexe incorretamente informações como os ids de página e usuário e posto que um índice não pode ser desfeito a menos que se deletem os documentos indexados, é de fundamental importância que este mapeamento seja feito logo no início.

Aff, esse artigo já está mega extenso e ainda nem falamos sobre recomendação ou big data! Tudo bem, a idéia aqui era um texto mais introdutório mesmo. Mas quem sabe um outro dia a gente possa se encontrar de novo.

Leave a Reply

Your email address will not be published. Required fields are marked *