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 Il repository e l'implementazione in progetti come GitHub, SoundCloud, Stack Overflow e LinkedIn testimoniano la sua grande popolarità. Il termine "Elastic" dice tutto sulla natura del sistema, le cui capacità sono enormi: dalla semplice ricerca di file su piccola scala, alla scoperta della conoscenza, fino all'analisi dei big data in tempo reale. Ciò che rende Elastic più potente della concorrenza è l'insieme di configurazioni e comportamenti predefiniti, che consentono di creare un cluster e iniziare ad aggiungere documenti all'indice in un paio di minuti. Elastic configurerà un cluster per voi, definirà un indice e definirà i tipi di campi per il primo documento ottenuto e, quando aggiungerete un altro server, si occuperà automaticamente di dividere i dati dell'indice tra i server.Sfortunatamente, l'automazione di cui sopra ci rende poco chiaro cosa implichino le impostazioni predefinite, che spesso si rivelano fuorvianti. Questo articolo inizia una serie in cui tratterò i problemi più comuni che si possono incontrare durante il processo di creazione di un'applicazione basata su Elastic.
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.