6 concetti fondamentali per capire Elasticsearch

Elasticsearch è un motore di ricerca sempre più diffuso anche nelle aziende medie e piccole. Benchè sia utilizzato da grandi players come Netflix, Microsoft, eBay, Facebook e altri, le sue funzionalità possono miglirare moltissimo le performance di qualsiasi impresa. In questo articolo condividiamo sei concetti fondamentali di Elasticsearch che vale la pena conoscere prima di utilizzarlo nei propri sistemi. In un altro articolo abbiamo spiegato in breve che cosa è Elasticsearch.

In questo artcolo invece vi proponiamo 6 concetti non banali utili alla comprensione di Elastisearch:

1) Elastic Stack
2) Due tipi di data set
3) Il punteggio di ricerca
4) Il modello di dati
5) Pianificazione degli shards
6) Tipi di nodo


1. Elastic Stack

Elasticsearch è stato inizialmente sviluppato come prodotto indipendente. Il suo unico ruolo era fornire un motore di ricerca scalabile, che fosse utilizzabile tramite qualsiasi linguaggio. Così è stato creato con un modello distribuito al centro con un’interfaccia API REST per la comunicazione.

Dopo una fase di prima adozione, sono stati inventati nuovi strumenti per lavorare con Elasticsearch. È arrivato Kibana, per la visualizzazione e l’analisi dei dati, e Logstash, per la raccolta dei files di registro. Attualmente ci sono una serie di strumenti che sono tutti sviluppati sotto la cura dell’azienda produttrice Elastic:

Elasticsearch – per la ricerca,
Kibana – analisi e visualizzazione dei dati,
Logstash: pipeline di elaborazione dati lato server,
Beats: caricatori di dati monouso,
Elastic Cloud: hosting di cluster Elasticsearch,
Machine Learning: per scoprire modelli di dati,
APM – Monitoraggio delle prestazioni delle applicazioni,
Swiftype: ricerca nel sito con un clic.

Il numero di strumenti cresce ogni anno, il che consente alle aziende di raggiungere nuovi obiettivi e creare nuove opportunità.

2. Due tipi di data set

Fondamentalmente in Elasticsearch si può indicizzare (cioè memorizzare) qualsiasi tipo di dato. Ma in realtà ce ne sono due classi, che hanno un forte impatto sulla configurazione e gestione del cluster: dati statici e serie di dati temporali.

I dati statici sono set di dati che possono crescere o cambiare lentamente. Come un catalogo o un inventario di articoli. Si possono pensare come i dati che si archiviano nei database regolari. Post di blog, libri della biblioteca, ordini, ecc. Si indicizzano questi dati in Elasticsearch per consentire ricerche velocissime, che ridicolizzano le prestazioni dei normali database SQL.

D’altra parte, si possono memorizzare set di dati temporali. Questi possono essere eventi associati a un momento nel tempo che in genere cresce rapidamente, come file di registro o metriche. Fondamentalmente si indicizzano in Elasticsearch per l’analisi dei dati, la scoperta di modelli e il monitoraggio dei sistemi.

A seconda del tipo di dati archiviati, è necessario modellare il cluster in modo diverso. Per i dati statici si dovrebbero scegliere un numero fisso di indici e shards. Non cresceranno molto velocemente e si potrà sempre cercare in tutti i documenti nel set di dati.

Per le serie di dati temporali è necessario scegliere indici a rotazione con limiti di tempo. Saranno i dati recenti ad essere interrogati piu’ spessoe alla fine si renderà necessario eliminare, o almeno archiviare i documenti obsoleti per risparmiare spazio sulle macchine.

3. Il punteggio di ricerca (search score)

Lo scopo principale di Elasticsearch è fornire un motore di ricerca. L’obiettivo è fornire i migliori documenti corrispondenti. Ma come fa effettivamente Elasticsearch a sapere quali sono?

Per ogni query di ricerca Elasticsearch calcola un punteggio di pertinenza. Il punteggio si basa sull’algoritmo tf-idf, che sta per Term Frequency – Inverse Document Frequency.

Fondamentalmente due valori vengono calcolati in questo algoritmo. Il primo, la frequenza dei termini, indica la frequenza con cui un determinato termine viene utilizzato in un documento. Il secondo – frequenza del documento inversa – dice quanto sia unico un dato termine in tutti i documenti.

Ad esempio, se abbiamo due documenti:

1) To be or not to be, that is the question.
2) To be. I am. You are. He, she is.

Il TF per il termine “question” è

1) per il documento 1: 1/10 (1 occorrenza su 10 termini)
2) per il documento 2: 0/9 (0 occorrenze su 9 termini).

D’altra parte l’IDF viene calcolato come un singolo valore per un intero set di dati. È un rapporto tra tutti i documenti e i documenti contenenti il termine cercato.
Nel nostro caso è:

log(2/1) = 0.301

(2 – numero di tutti i documenti, 1 – numero di documenti contenenti il termine ‘question’).

Infine il punteggio tf-idf per entrambi i documenti viene calcolato come prodotto di entrambi i valori:

documento 1: 1/10 x 0,301 = 0,1 * 0,301 = 0,03
documento 2: 0/9 x 0,301 = 0 * 0,301 = 0,00

Ora vediamo che il documento 1 ha una rilevanza di valore 0,03, mentre il documento 2 ha ottenuto 0,00. Pertanto il documento 1 verrà pubblicato più in alto nell’elenco dei risultati.

Potrete leggere la descrizione di un esempio pratico di utilizzo del ‘search score’ in quest’articolo che riguarda Elasticsearch e WordPress .

4. Modello di dati

Elasticsearch ha due vantaggi in termini di prestazioni. È scalabile orizzontalmente e molto veloce. Da dove viene quest’ultima caratteristica? E’ dovuta al modo in cui i dati vengono archiviati.

Quando si indicizza un documento, questo attraversa tre passaggi: filtri dei caratteri, un tokenizer e filtri dei token. Sono usati per normalizzare il documento. Ad esempio un documento:

To be or not to be, that is the question.

viene effettivamente memorizzato come:

to be or not to be that is the question

se i segni di punteggiatura vengono rimossi e tutti i termini sono resi minuscoli.

Ma questa non è tutto. Può essere memorizzato anche come

question

se viene applicato il filtro delle parole non significative che rimuove tutti i termini del linguaggio comune come: to, be, or, not, that, is, the. Vi sono elenchi di cosiddette ‘stop words’ in moltissimi linguaggi, incluso l’Italiano.

Questa è la parte dell’indicizzazione. Ma gli stessi passaggi vengono applicati durante la ricerca di documenti. La query viene anche filtrata per i caratteri, tokenizzata e filtrata per i token. Quindi Elasticsearch cerca documenti con i termini normalizzati. I campi in Elasticsearch sono memorizzati in una struttura di indice invertita e rende la raccolta dei documenti corrispondenti molto veloce.

È possibile definire filtri specifici per ogni campo. Le definizioni sono raggruppate in strutture chiamate analizzatori (analyzers). Un campo può essere analizzato con più analizzatori per raggiungere obiettivi diversi. Quindi in una fase di ricerca si può definire quale tipo di campo si vuole scansionare per ottenere i risultati desiderati.

Applicando queste modalità, ElasticSearch può fornire risultati molto più velocemente rispetto ai database normali.

5. Pianificazione degli shards

Una delle domande più frequenti dei neofiti di Elasticsearch è: quanti shards e indici è consigliato avere? Questa domanda sorge perchè il numero di frammenti può essere impostato solo all’inizio della creazione dell’indice.

Quindi la risposta dipende davvero dal set di dati che si intende indicizzare. La regola pratica è che gli shards dovrebbero essere costituiti da 20–40 GB di dati.Il concetto di ‘shard’ proviene da Apache Lucene (che è il motore di ricerca utilizzato sotto il cofano di Elasticsearch). Tenendo presente tutte le strutture ed i costi macchina generali che Apache Lucene utilizza per gli indici invertiti e le ricerche veloci, non ha senso avere piccoli frammenti, come 100 MB o 1 GB.

20–40 GB è la dimensione consigliata dai consulenti Elastic. Bisogna avere presente che un frammento non può essere ulteriormente suddiviso e risiede sempre su un singolo nodo. Lo shard di tali dimensioni può essere facilmente spostato su altri nodi o replicato, se necessario, all’interno di un cluster. Avere questa capacità di sharding offre un compromesso consigliato tra velocità e consumo di memoria.

Ovviamente in ogni caso particolare, le metriche delle prestazioni possono mostrare qualcosa di diverso, quindi bisogna tenere presente che questa è solo una raccomandazione ma è sempre possibile raggiungere altri obiettivi di rendimento.

Per sapere quanti shards per indice si dovrebbero avere, è possibile semplicemente stimarlo, indicizzando un numero di documenti in un indice temporaneo e vedere quanta memoria stanno consumando e quanti di di questi ci si aspetti di avere in un periodo di tempo (in un set di dati di una serie temporale) o globalmente (in un set di dati statici).

Non bisogna dimenticare che anche se si configura in modo errato il numero di shards o di indici, è sempre possibile reindicizzare i dati in un nuovo indice con un numero diverso di shards impostato.

Ultimo, ma non per importanza. Si possono sempre eseguire query per più indici contemporaneamente. Ad esempio, si possono avere indici a rotazione per i dati basati sui log con conservazione giornaliera e semplicemente chiedere risultati per tutti i giorni del mese scorso in una query. L’interrogazione di 30 indici con 1 shards ha lo stesso impatto sulle prestazioni dell’interrogazione di 1 indice con 30 shards.

6. Tipi di nodo

I nodi di Elasticsearch possono svolgere più ruoli. Per impostazione predefinita, il che è positivo per i piccoli cluster, possono servirli tutti. I ruoli di cui sto scrivendo sono:

1) master node,
2) data node,
3) ingest node,
4) coordinating-only node.

Ogni ruolo ha le sue conseguenze. I nodi principali sono responsabili delle impostazioni e delle modifiche a livello di cluster, come la creazione o l’eliminazione di indici, l’aggiunta o la rimozione di nodi e l’allocazione di shards ai nodi.

Ogni cluster dovrebbe essere composto da almeno 3 nodi idonei per il master e in realtà non è necessario averne altri. Di tutti i nodi idonei per il master, uno viene scelto come nodo master e il suo ruolo è eseguire azioni a livello di cluster. Gli altri due nodi sono necessari esclusivamente per l’alta disponibilità. I nodi master hanno requisiti bassi su CPU, RAM e memoria su disco.

I nodi di dati (data nodes) vengono utilizzati per l’archiviazione e la ricerca dei dati. Quindi hanno requisiti elevati su tutte le risorse: CPU, RAM e disco. Più dati hai, maggiori sono le aspettative riguardo all’allocazione di risorse.

I nodi di importazione (ingest nodes) vengono utilizzati per la pre-elaborazione dei documenti prima che avvenga l’effettiva indicizzazione. Intercettano le query bulk e di indice, applicano le trasformazioni e quindi ritrasmettono i documenti alle API di indice o bulk. Richiedono poco disco, RAM media e CPU alta.

I nodi di solo coordinamento (coordinating-only nodes) viene utilizzato come bilanciatore del carico per le richieste dei client. Sanno dove possono risiedere documenti specifici e servono le richieste di ricerca solo a quei nodi. Quindi eseguono azioni scatter & gatter sui risultati ricevuti. I requisiti per loro sono: poco disco, RAM media o alta e CPU media o alta.

Ogni nodo può svolgere uno o più dei ruoli sopra elencati. Il ruolo di coordinamento è svolto da qualsiasi tipo di nodo. Per avere un nodo di solo coordinamento devi disabilitare su di esso tutti gli altri ruoli nella configurazione.

Ecco qualche consiglio sulla maniera piu’ comune di configurare un cluster:

1) tre nodi principali, non esposti al mondo e che mantengono lo stato del cluster e le impostazioni del cluster,
2) un paio di nodi di solo coordinamento: ascoltano le richieste esterne e agiscono come bilanciatori intelligenti del carico per l’intero cluster,
3) un numero di nodi di dati, a seconda delle esigenze del set di dati,
4) un paio di nodi di importazione (facoltativamente) – se si esegue una pipeline di importazione e si desidera alleviare gli altri nodi dall’impatto della pre-elaborazione dei documenti.

I numeri specifici dipendono dal proprio particolare caso d’uso e devono essere dimensionati in base ai test delle prestazioni.

Ovviamente, maggiori dettagli su tutto questo li potrete trovare sul sito ufficiale di Elastic.