Salve amici! Ci sono persone con diversi livelli di esperienza che contribuiscono al nostro forum - e questo è fantastico! Ma in questo momento sto cercando dei veri titani di Ruby!
Elasticsearch è un motore di ricerca basato su una libreria affidabile e matura: Apache Lucene. Un'enorme attività in git progetto repository and the implementation in such projects as GitHub, SoundCloud, Stack Overflow and LinkedIn bear testimony to its great popularity. The part “Elastic” says it all about the nature of the system, whose capabilities are enormous: from a simple file search on a small scale, through knowledge discovery, to big data analysis in real time.What makes Elastic a more powerful than the competition is the set of default configurations and behaviors, which allow to create a cluster and start adding documents to the index in a couple of minutes. Elastic will configure a cluster for you, will define an index and define the types of fields for the first document obtained, and when you add another server, it will automatically deal with dividing index data between servers.Unfortunately, the above mentioned automation makes it unclear to us what the default settings implicate, and it often turns out to be misleading. This article starts a series where I will be dealing with the most popular gotchas, which you might encounter during the process of Elastic-based app creation.
Il numero di frammenti non può essere modificato
Indicizziamo il primo documento usando indice API:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"nome_nome" : "Jane",
"last_name" : "Smith",
"steet_number": 12
}'
In questo momento, Elastic crea un indice per noi, intitolato myindex. Ciò che non è visibile è il numero di shard assegnati all'indice. Gli shard possono essere intesi come processi individuali responsabili dell'indicizzazione, della memorizzazione e della ricerca di una parte dei documenti di un intero indice. Durante il processo di indicizzazione dei documenti, Elastic decide in quale shard deve essere trovato un documento. Ciò si basa sulla seguente formula:
shard = hash(document_id) % numero_di_shard_primari
È chiaro che il numero di shard primari non può essere modificato per un indice che contiene documenti. Pertanto, prima di indicizzare il primo documento, è sempre opportuno creare un indice manualmente, indicando il numero di shard che si ritiene sufficiente per un volume di dati indicizzati:
$ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"settings" : {
"number_of_shards" : 10
}
}'
Valore predefinito per numero_di_cristalli è 5. Ciò significa che l'indice può essere scalato fino a 5 server, che raccolgono i dati durante l'indicizzazione. Per l'ambiente di produzione, il valore degli shard deve essere impostato in base alla frequenza di indicizzazione prevista e alla dimensione dei documenti. Per gli ambienti di sviluppo e di test, consiglio di impostare il valore a 1. Perché? Lo spiegheremo nel prossimo paragrafo di questo articolo.
Ordinamento dei risultati della ricerca testuale con un numero relativamente basso di documenti
Quando si cerca un documento con una frase:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"query": {
"match": {
"title": "La volpe bruna e veloce"
}
}
}'
Elastic elabora la ricerca di testo in pochi passi, in modo semplice:
- La frase della richiesta viene convertita nella stessa identica forma in cui è stato indicizzato il documento, nel nostro caso si tratta di un insieme di termini:
["veloce", "marrone", "volpe"]. ("il" è stato rimosso perché insignificante),
- l'indice viene sfogliato per cercare i documenti che contengono almeno una delle parole ricercate,
- Ogni documento che corrisponde viene valutato in termini di rilevanza rispetto alla frase di ricerca,
- i risultati vengono ordinati in base alla rilevanza calcolata e la prima pagina di risultati viene restituita all'utente.
Nella terza fase, vengono presi in considerazione i seguenti valori (tra gli altri):
- quante parole della frase di ricerca sono presenti nel documento
- la frequenza di una determinata parola in un documento (TF - term frequency)
- se e quanto spesso le parole corrispondenti ricorrono in altri documenti (IDF - inverse document frequency) - più la parola è popolare in altri documenti, meno è significativa
- quanto è lungo il documento
Il funzionamento dell'IDF è importante per noi. Elastic, per motivi di prestazioni, non calcola questo valore per ogni documento dell'indice, ma ogni shard (index worker) calcola il proprio IDF locale e lo utilizza per l'ordinamento. Pertanto, durante la ricerca nell'indice con un basso numero di documenti si possono ottenere risultati sostanzialmente diversi a seconda del numero di shard in un indice e della distribuzione dei documenti.
Immaginiamo di avere due shard in un indice; nel primo sono indicizzati 8 documenti con la parola "volpe", mentre nel secondo solo 2 documenti con la stessa parola. Di conseguenza, la parola "volpe" differirà significativamente in entrambi gli shard e ciò potrebbe produrre risultati errati. Pertanto, a scopo di sviluppo, è opportuno creare un indice composto da un solo shard primario:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
'{"settings" : {"number_of_shards" : 1 } }'
La visualizzazione dei risultati delle pagine di ricerca "lontane" uccide il vostro cluster
Come ho già scritto nei paragrafi precedenti, i documenti di un indice sono condivisi tra processi di indice totalmente individuali - shard. Ogni processo è completamente indipendente e si occupa solo dei documenti che gli vengono assegnati.
Quando si cerca in un indice con milioni di documenti e si attende di ottenere i primi 10 risultati, ogni shard deve restituire i suoi 10 risultati meglio assortiti al cluster nodoche ha avviato la ricerca. Poi le risposte di ogni shard vengono unite e vengono scelti i 10 migliori risultati della ricerca (all'interno dell'intero indice). Questo approccio consente di distribuire in modo efficiente il processo di ricerca tra più server.
Immaginiamo che la nostra applicazione consenta di visualizzare 50 risultati per pagina, senza le restrizioni relative al numero di pagine visualizzabili da un utente. Ricordiamo che il nostro indice è composto da 10 shard primari (1 per server).
Vediamo come apparirà l'acquisizione dei risultati di ricerca per la prima e la centesima pagina:
Pagina n. 1 dei risultati della ricerca:
- Il nodo che riceve una query (controller) la passa a 10 shard.
- Ogni shard restituisce i suoi 50 documenti meglio corrispondenti ordinati per rilevanza.
- Dopo aver ricevuto le risposte da ogni shard, il controllore unisce i risultati (500 documenti).
- I nostri risultati sono i primi 50 documenti della fase precedente.
Pagina n. 100 dei risultati della ricerca:
- Il nodo che riceve una query (controller) la passa a 10 shard.
- Ogni shard restituisce i suoi 5000 documenti meglio corrispondenti ordinati per rilevanza.
- Dopo aver ricevuto le risposte da ogni shard, il controller unisce i risultati (50000 documenti).
- I nostri risultati sono i documenti della fase precedente posizionati da 4901 a 5000.
Supponendo che un documento abbia una dimensione di 1KB, nel secondo caso significa che devono essere inviati ed elaborati ~50MB di dati nel cluster per visualizzare 100 risultati per un utente.
Non è difficile notare che il traffico di rete e il carico dell'indice aumentano significativamente a ogni pagina di risultato successiva. Ecco perché non è consigliabile rendere disponibili all'utente le pagine di ricerca "lontane". Se il nostro indice è ben configurato, l'utente dovrebbe trovare il risultato che gli interessa nelle prime pagine di ricerca e noi ci proteggiamo da un carico inutile del nostro cluster. Per dimostrare questa regola, verificate fino a quale numero di pagine di risultati di ricerca i motori di ricerca web più diffusi consentono la visualizzazione.
Interessante è anche l'osservazione dei tempi di risposta del browser per le successive pagine dei risultati di ricerca. Ad esempio, di seguito sono riportati i tempi di risposta delle singole pagine dei risultati di ricerca in Google Search (il termine di ricerca era "motore di ricerca"):
| Pagina dei risultati della ricerca (10 documenti per pagina) | Tempo di risposta |
|——————————————–|—————|
| 1 | 250ms |
| 10 | 290ms |
| 20 | 350ms |
| 30 | 380ms |
| 38 (l'ultimo disponibile) | |
Nella prossima parte analizzerò più da vicino i problemi di indicizzazione dei documenti.