Olá amigos! Há pessoas com diferentes níveis de experiência a contribuir para os nossos fóruns - e isso é ótimo! Mas, neste momento, estou à procura de verdadeiros titãs do Ruby!
O Elasticsearch é um motor de pesquisa que se baseia numa biblioteca fiável e madura - Apache Lucene. Grande atividade no git projeto O repositório Elastic e a implementação em projectos como o GitHub, SoundCloud, Stack Overflow e LinkedIn são testemunhos da sua grande popularidade. A parte "Elastic" diz tudo sobre a natureza do sistema, cujas capacidades são enormes: desde uma simples pesquisa de ficheiros em pequena escala, passando pela descoberta de conhecimentos, até à análise de grandes volumes de dados em tempo real. O que torna a Elastic mais poderosa do que a concorrência é o conjunto de configurações e comportamentos predefinidos, que permitem criar um cluster e começar a adicionar documentos ao índice em alguns minutos. A Elastic configurará um cluster para si, definirá um índice e definirá os tipos de campos para o primeiro documento obtido e, quando adicionar outro servidor, tratará automaticamente da divisão dos dados do índice entre servidores. nós o que as configurações padrão implicam, e isso muitas vezes acaba sendo enganoso. Este artigo dá início a uma série em que tratarei dos problemas mais populares que poderá encontrar durante o processo de criação de aplicações baseadas na Elastic.
O número de fragmentos não pode ser alterado
Vamos indexar o primeiro documento usando índice API:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"first_name" : "Jane",
"last_name" : "Smith",
"steet_number": 12
}'
Neste momento, a Elastic cria um índice para nós, intitulado myindex. O que não é visível aqui é o número de shards atribuídos ao índice. Os shards podem ser entendidos como processos individuais responsáveis pela indexação, armazenamento e pesquisa de parte dos documentos de um índice inteiro. Durante o processo de indexação de documentos, a elastic decide em que fragmento um documento deve ser encontrado. Isto baseia-se na seguinte fórmula:
shard = hash(document_id) % number_of_primary_shards
É agora claro que o número de fragmentos primários não pode ser alterado para um índice que contenha documentos. Por isso, antes de indexar o primeiro documento, crie sempre um índice manualmente, fornecendo o número de fragmentos que considera suficiente para um volume de dados indexados:
$ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"settings" : {
"number_of_shards" : 10
}
}'
Valor por defeito para número_de_fragmentos é 5. Isto significa que o índice pode ser dimensionado para até 5 servidores, que recolhem dados durante a indexação. Para o ambiente de produção, o valor dos fragmentos deve ser definido consoante a frequência esperada de indexação e o tamanho dos documentos. Para ambientes de desenvolvimento e teste, recomendo que o valor seja definido como 1 - porquê? Será explicado no próximo parágrafo deste artigo.
Ordenar os resultados da pesquisa de texto com um número relativamente pequeno de documentos
Quando procuramos um documento com uma frase:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"query": {
"match": {
"title": "A rápida raposa castanha"
}
}
}'
A Elastic processa a pesquisa de texto em poucos passos, simplesmente falando:
- A frase do pedido é convertida na mesma forma idêntica em que o documento foi indexado, no nosso caso será um conjunto de termos:
["rápido", "castanho", "raposa"] ("o" foi retirado por ser insignificante),
- o índice está a ser pesquisado para procurar os documentos que contêm pelo menos uma das palavras pesquisadas,
- cada documento que corresponde a uma correspondência é avaliado em termos de relevância para a frase de pesquisa,
- os resultados são ordenados pela relevância calculada e a primeira página de resultados é devolvida ao utilizador.
Na terceira etapa, são tidos em conta os seguintes valores (entre outros):
- quantas palavras da frase de pesquisa estão no documento
- a frequência com que uma determinada palavra ocorre num documento (TF - term frequency)
- se e com que frequência as palavras correspondentes ocorrem noutros documentos (IDF - inverse document frequency) - quanto mais popular for a palavra noutros documentos, menos significativa é
- qual a extensão do documento
O funcionamento do IDF é importante para nós. A Elastic, por motivos de desempenho, não calcula este valor relativamente a cada documento no índice - em vez disso, cada shard (trabalhador de índice) calcula o seu IDF local e utiliza-o para ordenação. Portanto, durante a pesquisa de índice com baixo número de documentos, podemos obter resultados substancialmente diferentes dependendo do número de shards em um índice e da distribuição de documentos.
Imaginemos que temos 2 fragmentos num índice; no primeiro existem 8 documentos indexados com a palavra "fox" e no segundo apenas 2 documentos com a mesma palavra. Como resultado, a palavra "fox" será significativamente diferente em ambos os fragmentos, o que pode produzir resultados incorrectos. Portanto, um índice que consiste apenas num fragmento primário deve ser criado para fins de desenvolvimento:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
'{"settings" : { "number_of_shards" : 1 } }'
A visualização dos resultados das páginas de pesquisa "distantes" mata o seu cluster
Como já escrevi em parágrafos anteriores, os documentos de um índice são partilhados entre processos de índice totalmente individuais - fragmentos. Cada processo é completamente independente e lida apenas com os documentos que lhe são atribuídos.
Quando pesquisamos um índice com milhões de documentos e esperamos obter os 10 melhores resultados, cada fragmento deve devolver os seus 10 melhores resultados correspondentes ao nóque iniciou a pesquisa. De seguida, as respostas de cada fragmento são reunidas e os 10 melhores resultados de pesquisa são escolhidos (dentro de todo o índice). Esta abordagem permite distribuir eficientemente o processo de pesquisa entre muitos servidores.
Imaginemos que a nossa aplicação permite visualizar 50 resultados por página, sem as restrições relativas ao número de páginas que podem ser visualizadas por um utilizador. Lembre-se de que o nosso índice é composto por 10 fragmentos primários (1 por servidor).
Vejamos como será a aquisição de resultados de pesquisa para a 1ª e a 100ª página:
Página n.º 1 dos resultados da pesquisa:
- O nó que recebe uma consulta (controlador) transmite-a a 10 fragmentos.
- Cada fragmento devolve os seus 50 melhores documentos correspondentes, ordenados por relevância.
- Depois de recebidas as respostas de todos os fragmentos, o controlador funde os resultados (500 documentos).
- Os nossos resultados são os 50 melhores documentos da etapa anterior.
Página n.º 100 dos resultados da pesquisa:
- O nó que recebe uma consulta (controlador) transmite-a a 10 fragmentos.
- Cada fragmento devolve os seus 5000 documentos com melhor correspondência, ordenados por relevância.
- Depois de receber as respostas de cada fragmento, o controlador funde os resultados (50000 documentos).
- Os nossos resultados são os documentos da etapa anterior posicionados 4901 - 5000.
Assumindo que um documento tem 1KB de tamanho, no segundo caso significa que ~50MB de dados têm de ser enviados e processados no cluster, de modo a visualizar 100 resultados para um utilizador.
Não é difícil notar que o tráfego de rede e a carga do índice aumentam significativamente com cada página de resultados sucessiva. É por isso que não é recomendável disponibilizar ao utilizador as páginas de pesquisa "distantes". Se o nosso índice estiver bem configurado, o utilizador deverá encontrar o resultado em que está interessado nas primeiras páginas de pesquisa e estaremos a proteger-nos de uma carga desnecessária do nosso cluster. Para provar esta regra, verifique até que número de páginas de resultados de pesquisa os motores de pesquisa Web mais populares permitem a visualização.
O que também é interessante é a observação do tempo de resposta do navegador para páginas de resultados de pesquisa sucessivas. Por exemplo, abaixo pode ver os tempos de resposta para páginas de resultados de pesquisa individuais na Pesquisa Google (o termo de pesquisa era "motor de pesquisa"):
| Página de resultados da pesquisa (10 documentos por página) | Tempo de resposta | Tempo de resposta
|——————————————–|—————|
| 1 | 250ms |
| 10 | 290ms |
| 20 | 350ms |
| 30 | 380ms |
| 38 (último disponível) | | |
Na próxima parte, analisarei mais detalhadamente os problemas relacionados com a indexação de documentos.