Elasticsearch: il motore di ricerca flessibile
Chi ha bisogno di una potente ricerca full text normalmente sceglie Apache Solr. Nonostante tale processo rimanga tuttora una buona scelta, dal 2010 il mercato offre un’alternativa interessante: Elasticsearch. Come Solr, Elasticsearch è basato su Apache Lucene, ma è fornito di ulteriori funzionalità. Vi spieghiamo le funzionalità del server di ricerca e nel nostro tutorial su Elasticsearch chiariamo come implementare la ricerca full text per il vostro progetto.
Elasticsearch è diventato uno dei più importanti motori di ricerca full text su Internet. Anche le grandi aziende utilizzano questo software: Facebook, ad esempio, ha lavorato con successo per diversi anni con Elasticsearch; anche GitHub, Netflix, SoundCloud e Zalando si affidano a questo motore di ricerca di successo.
Che cos’è Elasticsearch?
Data la quantità di informazioni presenti su alcuni siti web, è possibile garantire un’elevata usabilità implementando una ricerca full text funzionante. Chi non desidera utilizzare le soluzioni di Google o Bing per offrire ai propri visitatori una funzione di ricerca, deve incorporarne una propria, ad esempio con Elasticsearch: il progetto open source è basato su Apache Lucene, anch’esso disponibile gratuitamente.
Elasticsearch offre i vantaggi dello stabile predecessore e li espande con funzionalità aggiuntive. Proprio come con Lucene, la ricerca funziona attraverso un indice: anziché esaminare tutti i documenti durante una ricerca, il programma controlla un indice dei documenti creato in precedenza in cui è archiviato tutto il contenuto. Questo processo richiede molto meno tempo rispetto alla ricerca tra tutti i documenti.
Mentre con Lucene avete completa libertà su dove e come utilizzare la ricerca full text, con questo software occorre iniziare completamente da zero. Elasticsearch d’altra parte vi permette di iniziare più velocemente sul World Wide Web. Con Elasticsearch è possibile creare un server di ricerca stabile in breve tempo che può essere anche facilmente distribuito su più macchine.
Molti nodi (server diversi) si uniscono per formare un cluster. Viene utilizzato il cosiddetto shard, ovvero una partizione del database: Elasticsarch scompone l’indice e distribuisce le singole parti (shards) su più nodi. Ciò divide anche il carico di lavoro. Per i progetti di grandi dimensioni la ricerca full text è inoltre molto più stabile. Per una maggiore sicurezza è possibile copiare i frammenti su più nodi.
Come Lucene, Elasticsearch si basa sul linguaggio di programmazione Java orientato agli oggetti. Il motore di ricerca genera risultati in formato JSON e li consegna tramite un servizio web REST. L’API rende molto facile mettere la funzione di ricerca in un sito web.
Inoltre la funzionalità Elasticsearch offre con Kibana, Beats e Logstash, conosciuti nel loro insieme come elastic stack, dei pratici servizi aggiuntivi che consentono di analizzare la ricerca full text. L’azienda Elastic che sviluppa Elsticsearch è fondata dal creatore del programma e offre anche servizi a pagamento come il cloud hosting.
Che cosa offre Elasticsearch che Google & Co. non hanno?
Come tutti sappiamo Google offre già una popolare funzione di ricerca, tra l’altro facilmente integrabile nel vostro sito web. Allora perché fare una scelta più macchinosa costruendo il proprio motore di ricerca con Elasticsearch? Una possibile risposta è che con Google Custom Search (GCS) si diventa dipendenti dal gigante dei motori di ricerca e si acconsente (almeno nella versione gratuita) a inserire pubblicità nei risultati di ricerca. Con Elasticsearch potete evitare questo inconveniente: il codice è open source e la funzione di ricerca full text è quindi anche vostra. In questo modo non dipendete da nessuno.
Inoltre potete personalizzare Elasticsearch a vostro piacimento. Ad esempio, se gestite la vostra piattaforma online o il vostro negozio online, potete impostare la funzione di ricerca in modo da poter utilizzare Elasticsearch per ricercare i profili degli utenti che hanno effettuato l’accesso. In tali applicazioni il GCS raggiunge i propri limiti.
Elasticsearch vs Apache Solr: quali sono le principali differenze?
Sia Elasticsearch che Apache Solr sono basati su Lucene, ma sono stati sviluppati in offerte indipendenti. Tuttavia molti utenti si stanno chiedendo quale progetto scegliere. Anche se Elasticsearch è un po’ più giovane e diversamente da Solr non è supportato dalla community di Apache, il progetto ha superato il numero di utenti del concorrente. La ragione di ciò è da ricercarsi soprattutto nella maggiore semplicità d’implementazione. Inoltre Elasticsearch è particolarmente popolare per la gestione dei dati dinamici: attraverso uno speciale processo di memorizzazione nella cache, Elasticsearch riesce a ottenere che le modifiche non debbano necessariamente essere immesse nell’intera cache globale: è sufficiente invece cambiare un piccolo segmento. Ciò rende Elasticsearch un’alternativa più flessibile.
Alla fine, tuttavia, la decisione ha spesso solo a che fare con i diversi approcci open source. Solr è pienamente impegnata nella filosofia della Apache Software Foundation: Community over Code. Ogni contributo al codice viene preso sul serio e la community decide insieme quali aggiunte e sviluppi finiranno nel codice finale. Lo sviluppo di Elasticsearch è diverso: anche questo progetto è open source ed è offerto con licenza Apache gratuita, ma soltanto il team di Elastic decide quali modifiche faranno parte del codice. Alcuni sviluppatori non apprezzano questa mentalità gatekeeper e preferiscono rivolgersi a Solr.
Tutorial per Elasticsearch
Prima di iniziare a lavorare con Elasticsearch si consiglia innanzitutto di apprendere alcuni concetti di base. Ad esempio è degna di nota la struttura delle informazioni:
- Index: una query di ricerca su Elasticsearch non si applica mai al contenuto stesso, ma sempre all’indice, dove tutti i contenuti di tutti i documenti sono memorizzati e già preparati, quindi la ricerca richiede poco tempo. Si tratta di un cosiddetto codice invertito: per ogni termine di ricerca è assegnato il luogo in cui è possibile trovare il termine.
- Document: l’output dell’indice sono i documenti in cui sono trovati i dati. Non devono essere necessariamente testi completi (ad esempio, articoli di blog), bastano semplici file contenenti informazioni.
- Field: un documento è composto da diversi campi. Oltre al campo del contenuto attuale, anche altri metadati appartengono a un documento. Ad esempio, con Elasticsearch è possibile cercare in modo specifico i metadati relativi all’autore o al momento della creazione.
Quando parliamo di modificare i dati si tratta di tokenizing: un algoritmo crea i termini individuali da un testo completo. Per una macchina non esistono cose come le parole: un testo è costituito da una lunga stringa di segni e una lettera per un computer ha lo stesso valore di uno spazio. Affinché un testo sia. elaborato in modo significativo, esso deve essere prima suddiviso in token. Ad esempio gli whitespace, quindi spaziature e righe vuote, sono considerati come marker per le parole. Inoltre, nella preparazione si effettua anche la normalizzazione: le parole vengono scritte uniformemente minuscole e la punteggiatura è ignorata. Elasticsearch ha ereditato tutti questi metodi da Apache Lucene.
Nel seguente tutorial stiamo lavorando con la versione 6.3.0 di Elasticsearch. Se si utilizza una versione diversa, alcuni esempi di codice o passagi del tutorial potrebbero funzionare in modo differente.
Installazione
I file necessari per Elasticsearch sono disponibili gratuitamente sul sito web ufficiale di Elastic. Qui i file sono offerti come pacchetti ZIP o tar.gz, motivo per cui possono essere facilmente installati tramite console su Linux e Mac.
Elastic offre Elasticsearch in due pacchetti diversi. La versione standard include anche funzioni a pagamento in prova per un certo periodo di tempo. Invece i pacchetti etichettati con OSS (Open Source Software) contengono solo componenti gratuiti rilasciati con licenza Apache 2.0.
Per ZIP:
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.zip
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.zip.sha512
shasum -a 512 -c elasticsearch-oss-6.3.0.zip.sha512
unzip elasticsearch-oss-6.3.0.zip
cd elasticsearch-6.3.0
Per tar.gz:
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.tar.gz
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.tar.gz.sha512
shasum -a 512 -c elasticsearch-oss-6.3.0.tar.gz.sha512
tar -xzf elasticsearch-oss-6.3.0.tar.gz
cd elasticsearch-6.3.0
Innanzitutto scaricate il pacchetto e la checksum dell’hash (SHA512) che controllerete anche nel terzo passo. Quindi decomprimete il pacchetto e passate alla cartella appropriata.
Anche l’archivio ZIP si può scaricare e utilizzare per l’installazione su Windows, poiché il pacchetto contiene un file batch che potete eseguire. In alternativa, Elastic ora fornisce anche un programma di installazione MSI, che si trova però ancora in fase beta. Il file di installazione di quest’ultimo contiene un’interfaccia grafica che guida l’utente nell’installazione.
Poiché Elasticsearch è basato su Java, il vostro sistema deve avere installato questo linguaggio di programmazione. Potete scaricare gratuitamente il Java Development Kit (JDK) dal sito web ufficiale.
Ora eseguite Elasticsearch dalla console navigando nella cartella bin e digitando “elasticsearch” su Linux, Mac o Windows. Quindi aprite un browser di vostra scelta e chiamate la seguente porta dell’host locale: 'http://localhost:9200/'. Se avete installato correttamente Elasticsarch e Java è impostato correttamente, ora dovreste essere in grado di accedere alla ricerca full text.
Con Elasticsearch comunicate tramite l’API REST, perciò vi occorre un client appropriato. Si consiglia di utilizzare Kibana per questo scopo (anche un’offerta gratuita open source di Elastic va bene). Con questo programma potete utilizzare Elasticsearch direttamente nel browser. Per farlo basta andare su http://localhost:5601/ e accedere a un’interfaccia utente grafica. Nel nostro tutorial su Kibana vi spieghiamo come installare correttamente Kibana. In Kibana e in qualsiasi altro client potete utilizzare i metodi HTTP PUT, GET, POST e DELETE per inviare comandi alla vostra ricerca full text.
Index
Come primo passo dovete innanzitutto creare il vostro indice e alimentarlo con dati. È possibile utilizzare due diversi metodi HTTP: POST e PUT. Si utilizza PUT se si desidera specificare un particolare ID per la voce. Con POST Elasticsearch crea da sé un ID. Nel nostro esempio, vorremmo creare una bibliografia. Ogni voce deve contenere il nome dell’autore, il titolo dell’opera e l’anno di pubblicazione.
POST bibliography/novels
{
"author": "Isabel Allende",
"title": "The house of the spirits",
"year": "1982"
}
Se si desidera utilizzare l’input in questo modo, è necessario utilizzare la console Kibana. Se non si desidera utilizzare questo software, in alternativa è possibile utilizzare cURL. Invece del comando precedente, immettete quanto segue nella riga di comando:
curl -XPOST http://localhost:9200/bibliography/novels -H "Content-Type: application/json" -d '{"author": "Isabel Allende", "title": "The house of the spirits", "year": "1982"}'
Di seguito vi mostriamo solo il codice per Kibana, ma si può facilmente trasferire nella sintassi di cURL. Elasticsearch dovrebbe, se avete inserito tutto correttamente, restituire le seguenti informazioni all’inizio del messaggio:
{
"_index": "bibliography",
"_type": "novels",
"_id": "AKKKIWQBZat9Vd0ET6N1",
"_version": 1,
"result": "created",
}
A questo punto dovrebbe essere chiaro che Elasticsearch troverà un indice con il nome bibliography e il tipo novels. Poiché abbiamo utilizzato il metodo POST, Elasticsearch ha generato automaticamente un ID univoco per la nostra voce. La voce è attualmente nella prima versione ed è stata creata (created) da poco.
All’inizio il tipo (_type) era un genere di sottocategoria in Elasticsearch. Attraverso di esso era possibile assemblare diversi tipi sotto un solo indice. Tuttavia questo ha portato a vari problemi e quindi Elastic sta pianificando di smettere di utilizzare tali tipi. Nella versione 6.x è ancora incluso _type, ma non è più possibile assemblare più tipi sotto un solo indice. A partire dalla versione 7.0 si pianifica di cancellare completamente i tipi, come spiegano gli sviluppatori nel loro blog.
Potete anche usare PUT per dare alla vostra voce un ID specifico. Esso viene definito nella prima riga del codice. È necessario PUT anche se si desidera modificare una versione esistente.
PUT bibliography/novels/1
{
"author": "William Gibson",
"title": "Neuromancer",
"year": "1984"
}
Il seguente output è molto simile a quello che otteniamo con il nostro metodo POST, tuttavia Elasticsearch ci fornisce l’ID che abbiamo dato alla voce nella prima riga. L’ordine delle specifiche è sempre _index/_type/_id.
{
"_index": "bibliography",
"_type": "novels",
"_id": "1",
"_version": 1,
"result": "created",
}
Con il comando PUT e l’ID univoco possiamo anche modificare le voci:
PUT bibliography/novels/1
{
"author": "William Gibson",
"title": "Count Zero",
"year": "1986"
}
Poiché la voce con l’ID 1 esiste già, Elasticsearch la modifica soltanto anziché crearne una nuova. Questo si riflette anche nell’output:
{
"_index": "bibliography",
"_type": "novels",
"_id": "1",
"_version": 2,
"result": "updated",
}
Il numero di versione è aumentato a 2 e come risultato riceviamo updated al posto di created. Potete ovviamente fare lo stesso con un ID creato casualmente da Elasticsearch, ma la lunghezza e la confusione dei segni renderebbe il lavoro successivo molto più complicato. Il processo significa anche che Elasticsearch sovrascrive semplicemente una voce se per esempio confondete i numeri ID. Per evitare modifiche accidentali potete utilizzare l’endpoint _create:
PUT bibliography/novels/1/_create
{
"author": "Mary Shelley",
"title": "Frankenstein; or, The Modern Prometheus",
"year": "1818"
}
Poiché nell’indice esiste già una voce con ID 1, riceverete un messaggio di errore.
Se apportate modifiche a una voce come descritto sopra, creerete una voce completamente nuova in senso stretto e dovrete quindi anche compilare tutti i dettagli, altrimenti potete soltanto integrare le modifiche alla voce esistente. Per questo si utilizza l’endpoint _update:
POST bibliography/novels/1/_update
{
"doc": {
"author": "Franz Kafka",
"genre": "Horror"
}
}
Ora abbiamo aggiunto un ulteriore campo alla voce e modificato un campo esistente senza però eliminare gli altri, tuttavia solo in primo piano. In background infatti Elasticsearch ha ricreato l’intera voce inserendo autonomamente i contenuti già esistenti.
In linea di principio abbiamo semplicemente scritto una voce in un database in modo da poterla richiamare direttamente. Per farlo utilizziamo il metodo GET:
GET bibliography/novels/1
Potete però anche farvi mostrare l’inserimento comodamente sul browser:
http://localhost:9200/bibliography/novels/1
Elasticsearch ci mostra in output tutti i dettagli della nostra voce:
{
"_index": "bibliography",
"_type": "novels",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"author": "William Gibson",
"title": “Count Zero",
"year": "1984"
}
}
Oltre alle informazioni già note, sotto _source trovate i campi del documento. Inoltre Elasticsearch ci informa che è stata effettivamente trovata una voce. Se tentate di richiamare una voce inesistente, non sarà visualizzato alcun messaggio di errore. Invece Elasticsearch segnala “found”: false e non ci sono voci sotto _source.
Avete inoltre anche la possibilità di trascinare solo alcune informazioni dal database. Supponiamo che abbiate memorizzato non soltanto i dati bibliografici nel vostro indice, ma anche il testo completo di ciascun romanzo registrato. Anche questo sarebbe incluso in una semplice richiesta GET. Ma poniamo che al momento vi interessi soltanto il nome dell’autore e il titolo dell’opera. Potete quindi chiedere espressamente soltanto dopo:
GET bibliography/novels/1?_source=author,title
Se non vi interessano i metadati di una voce, potete visualizzare anche solo il contenuto:
GET bibliography/novels/1/_source
Supponiamo che voi non vogliate richiamare soltanto una singola voce nel vostro indice, bensì diverse. Elasticsearch ha implementato l’endpoint _mget (per multi-get). Se lo utilizzate, specificate un array di più ID:
GET bibliography/novels/_mget
{
"ids": ["1", "2", "3"]
}
Anche se una voce non esiste, la richiesta non rimarrà completamente ineseguita, poiché saranno visualizzati tutti i dati esistenti. Per quanto riguarda i dati inesistenti, Elasticsearch comunica di non essere in grado di trovarli. La cancellazione di una voce funziona in modo molto simile al richiamo di una voce. Tuttavia, invece di lavorare con GET, si lavora con DELETE:
DELETE /bibliography/novels/1
Nel seguente output, Elasticsearch vi dice che ha trovato la voce sotto l’ID specificato:
{
"_index": "bibliography",
"_type": "novels",
"_id": "1",
"_version": 5,
"result": "deleted",
}
Inoltre il programma aumenta il numero di versione di uno. Questo per due ragioni:
- Elasticsearch contrassegna la voce solo come cancellata e non la rimuove direttamente dal disco rigido. La voce scomparirà solo nell’ulteriore corso dell’indicizzazione.
- Quando si lavora con indici distribuiti su più nodi, il controllo dettagliato delle versioni è estremamente importante: ecco perché Elasticsearch segna ogni cambiamento come una nuova versione, cambiamenti che comprendono anche l’ordine di cancellazione.
È possibile apportare modifiche anche solo a un numero di versione specifico a voi noto. Se nel cluster esiste già una versione più recente rispetto a quella specificata, il tentativo di modifica genererà un messaggio di errore.
PUT bibliography/novels/1?version=3
{
"author": "Marcel Proust",
"title": " À la recherche du temps perdu",
"year": "1927"
}
Non soltanto potete richiamare più voci contemporaneamente, ma con il comando _bulk potete anche crearne ed eliminarne molte.
POST bibliography/novels/_bulk
{"delete": {"_id": "1"}}
{"create": {"_id": "1"}}
{"author": "Johann Wolfgang von Goethe", "title": "Die Leiden des jungen Werther", "year": "1774"}
{"create": {"_id": "2"}}
{"author": "Umberto Eco", "title": "Il nome della rosa", "year": "1980"}
{"create": {"_id": "3"}}
{"author": "Margaret Atwood", "title": "The Handmaid’s Tale", "year": "1985"}
Ogni ordine ottiene la propria linea: innanzitutto specificate quale azione debba essere eseguita (create, index, update, delete). Inoltre si specifica anche quale voce si desidera creare e in quale posizione. È anche possibile che un’istruzione di questo tipo funzioni con diversi indici. Per farlo dovreste lasciare vuoto il percorso verso POST e assegnare a ciascuna azione il proprio percorso. Durante la creazione delle voci è necessario specificare, anche in una nuova riga, un request body, nel quale risiede il contenuto della voce. L’istruzione DELETE non richiede request body di richiesta, poiché la voce completa viene cancellata.
Finora negli esempi abbiamo sempre specificato i contenuti allo stesso modo, indipendentemente dal campo: Elasticsearch ha interpretato tutte le informazioni con una stringa interconnessa. Pertanto esiste un mapping in Elasticsearch. Ciò determina come gli algoritmi debbano interpretare un input. Usate il seguente codice per vedere quale mappatura è attualmente in uso nel vostro indice:
GET bibliography/novels/_mapping
Tutti i campi sono assegnati a tipi di testo e parole chiave. Elasticsearch ha 6 core datatypes e ancora più campi speciali. I 6 tipi principali sono in parte suddivisi in ulteriori sottocategorie:
- string: include sia testo che keyword. Mentre le parole chiave sono considerate corrispondenze esatte, Elasticsearch presume che il testo debba essere analizzato prima di poter essere utilizzato.
- numeric: Elasticsearch riconosce diversi valori numerici che differiscono principalmente per l’ambito. Ad esempio mentre il tipo byte può assumere valori tra -128 e 127 con long si ha un margine compreso tra -263 bis 263-1.
- date: una data può essere specificata giornalmente o anche con un orario preciso. Inoltre si ha la possibilità di specificare una data nel formato temporale Unix: secondi o millisecondi dal 1. 1. 1970.
- boolean: i campi formattati come booleani possono avere valore vero (true) o falso (false).
- binary: in tali campi è possibile memorizzare dati binari. Per inviarli usate la codifica Base64.
- range: in questo modo specificate un’area. Essa può giacere tra due valori numerici, due date o anche tra due indirizzi IP.
Queste sono le categorie principali che probabilmente userete più spesso. Per altri tipi consultate la documentazione Elasticsearch. I singoli tipi differiscono soprattutto per il fatto che sono o exact-value o full text. Elasticsearch comprende il contenuto del campo come input esatto oppure come contenuto che deve essere elaborato per primo. Nel corso della mappatura anche l’analyzing è importante: l’analisi di un contenuto è suddivisa in tokenizing e normalising:
- Tokenizing: i token individuali sono fatti a partire da un solo testo. Essi possono includere parole singole ma anche termini fissi costituiti da più parole.
- Normalizing: i token sono normalizzati riducendoli in lettere minuscole e alle loro forme base.
Per eseguire questa procedura Elasticsearch utilizza gli Analyzer. Se includete un documento nell’indice e avete eseguito correttamente il vostro mapping, tutti i contenuti saranno esclusi correttamente nell’indice invertito. Per utilizzare la mappatura dovete creare un indice completamente nuovo: non è possibile mappare campi già esistenti.
PUT bibliography
{
"mappings": {
"novels": {
"properties": {
"author": {
"type": "text",
"analyzer": "simple"
},
"title": {
"type": "text",
"analyzer": "standard"
},
"year": {
"type": "date",
"format": "year"
}
}
}
}
}
Abbiamo definito i due campi author e title come testo e quindi come full text. Pertanto essi hanno ancora bisogno di un analyzer adatto. Mentre forniamo l’analyzer standard al campo per il titolo del romanzo, scegliamo per il nome dell’autore il meno complesso simple analyzer. Tuttavia definiamo l’anno di pubblicazione come date, e perciò come exact-value. Poiché Elasticsearch accetta come formato standard una voce costituita da anno, mese e giorno, variamo questa caratteristica, dal momento che vogliamo limitarci a specificare l’anno.
Ricerca
Nel capitolo precedente abbiamo utilizzato Elasticsearch e il suo indice principalmente come database. Il vero vantaggio di Elasticsearch, tuttavia, risiede nella ricerca full text. In altre parole, invece di digitare l’ID di un documento e richiamare così la voce, ora impostiamo Elasticsearch in modo che possiate cercare specificamente il contenuto. Per utilizzare il motore di ricerca il programma ha fornito l’endpoint _search. Combinandolo con il metodo GET è possibile ad esempio visualizzare tutte le voci:
GET bibliography/novels/_search
Per ricerche più complesse, _search utilizza un body in parentesi graffe. Tuttavia alcuni server http non prevedono questo tipo di metodo GET. Pertanto gli sviluppatori hanno deciso che tali ricerche funzionino anche come POST.
Potete anche lasciare il percorso vuoto per cercare tutti gli indici esistenti. Nell’output troverete le informazioni interessanti sotto hits:
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "bibliography",
"_type": "novels",
"_id": "2",
"_score": 1,
"_source": {
"author": "Umberto Eco",
"title": "Il nome della rosa",
"year": "1980"
}
},
],
}
}
Tutte le altre voci nel nostro indice saranno anche elencate nell’output (e omesse qui per motivi di chiarezza). Il feedback di Elasticsearch ci fornisce due ulteriori informazioni oltre ai contenuti effettivi, che possono aiutarci a comprendere la ricerca full text:
- hits: ogni voce che corrisponde ai criteri di ricerca viene valutata da Elasticsearch come hit. Il programma mostra inoltre il numero di hit. Poiché nel nostro esempio ci sono 3 voci nell’indice e vogliamo visualizzarle tutte, si applica "total": 3.
- score: sotto forma di punteggio, Elasticsearch indica quanto sia rilevante la voce della nostra richiesta. Dal momento che abbiamo semplicemente cercato tutti i post nel nostro esempio, tutti hanno anche lo stesso score di 1. Le voci sono ordinate nei risultati della ricerca in ordine di pertinenza decrescente.
Inoltre Elasticsearch fornisce nella risposta altre informazioni su quanti shards sono coinvolti nei risultati della ricerca, su quanti millisecondi ha impiegato la ricerca e se si sia verificato un timeout.
Elasticsearch mostra per impostazione predefinita solo i primi 10 risultati di ricerca. Tuttavia potete influenzarlo impostando i parametri:
- size: quanti risultati dovrebbe mostrare Elasticsearch?
- from: quante voci dovrebbe saltare il programma prima di visualizzarle?
Se ora avete visto soltanto i primi 10 risultati di ricerca e volete vedere soltanto i seguenti 15, dovrete utilizzare una combinazione di entrambi i parametri:
GET bibliography/novels/_search?size=15&from=10
Elasticsearch distingue tra due diversi tipi di ricerca: da una parte utilizza una versione lite, mentre dall’altra una variante più complessa che funziona con la query DSL, una lingua di ricerca specifica. Per la versione Lite inserite la vostra query di ricerca come una semplice stringa direttamente nella query di ricerca:
GET bibliography/novels/_search?q=atwood
Potete anche ricercare soltanto all’interno di un determinato campo:
GET bibliography/novels/_search?q=author:atwood
Di fatto anche nel primo esempio cercate in un campo preciso senza doverlo specificare: il campo _all. Quando si incolla il contenuto di un documento in campi ordinati nell’indice, Elasticsearch crea un campo aggiuntivo in background. In questo tutti i contenuti degli altri campi vengono inoltre memorizzati per consentire tale ricerca in tutti i campi.
Se volete combinare più criteri di ricerca, usate +. Con il segno – escludete determinati criteri. Tuttavia se si utilizzano questi operatori, è necessario applicare la codifica percentuale nella query di ricerca:
GET bibliography/novels/_search?q=%2Bauthor%3Aatwood+%2Btitle%3Ahandmaid
La sintassi della stringa di query di Elasticsearch offre ancora più sottigliezze per personalizzare la ricerca. Nella documentazione del sofware gli sviluppatori di Elasic hanno riassunto tutto l’essenziale: scorciatoie OR, frasi esatte, campi vuoti o metacaratteri.
Questa variante di ricerca è adatta per semplici query, ma per compiti più complessi il metodo Lite può fallire: il rischio di inserire un errore in una stringa lunga è molto grande. Ecco perché Elasticsearch offre un metodo più pratico con Query DSL. Il punto di partenza per tale ricerca è il parametro di query in combinazione con una match query:
GET bibliography/novels/_search
{
"query": {
"match": {
"author": "allende"
}
}
}
Il risultato mostra tutte le voci che contengono la parola “allende” nel campo author. Riconosciamo che l’analisi ha funzionato nella mappatura perché Elasticsearch ignora le lettere maiuscole e minuscole. Per visualizzare tutte le voci potete anche utilizzare match_all in aggiunta alla variante semplice già presentata:
GET bibliography/novels/_search
{
"query": {
"match_all": {}
}
}
Il contrario di questa ricerca è match_none. Elasticsearch vi dà anche la possibilità di cercare un solo termine di ricerca in più campi contemporaneamente:
GET bibliography/novels/_search
{
"query": {
"multi_match": {
"query": "la",
"fields": ["author", "title"]
}
}
}
Per consentire ordini di ricerca complessi potete combinare anche diversi termini di ricerca e valutarli in modo diverso. Avete a disposizione tre modalità di vincolo:
- must: il termine deve verificarsi.
- must_not: il termine non può verificarsi.
- should: se compare questo termine, aumenta la pertinenza nei risultati della ricerca.
Nella pratica le combinerete con una query booleana:
GET bibliography/novels/search_
{
"query": {
"bool": {
"must": {
"match": {
"title": "la"
}
},
"must_not": {
"match": {
"title": "rabbit"
}
},
"should": {
"match": {
"author": "allende"
}
}
}
}
}
Potete inoltre espandere la vostra ricerca installando un filtro. Ciò consente di impostare criteri che limitano i risultati della ricerca:
{
"query": {
"bool": {
"must": {
"match": {
"title": "la"
}
},
"filter": {
"range": {
"year": {
"gte": "1950",
"lt": "2000"
}
}
}
}
}
}
Nell’esempio precedente abbiamo collegato il filtro a uno spettro di valori: dovevano essere visualizzate soltanto le voci comprese tra il 1950 e il 2000.
Con questo strumento avete a disposizione tutto quello che vi serve per implementare la ricerca full text nel vostro progetto. Elasticsearch, tuttavia, offre altri metodi che possono affinare la ricerca e renderla più complessa. Sul sito ufficiale di Elastic si possono trovare maggiori informazioni. Se volete estendere ulteriormente la ricerca full text, potete anche creare i vostri script con altre lingue come Groovy e Clojure.
Vantaggi e svantaggi di Elasticsearch
Elasticsearch può essere un potente strumento di ricerca full text. L’unica pecca che si può attribuire a Elasticsearch è la cattiva implementazione del concetto open source. Per il resto la ricerca full text offre numerosi vantaggi, anche rispetto al diretto concorrente Apache Solr.
Vantaggi | Svantaggi |
---|---|
Open source | Elastic come Gatekeeper |
Veloce e stabile | |
Scalabile | |
Molti moduli di programma già pronti (analyzer, ricerca full text, ecc.) | |
Facile implementazione grazie a Java, JSON e REST-API | |
Flessibile e dinamico |