Guida a Elasticsearch in Java

1. Panoramica

In questo articolo, ci immergeremo in alcuni concetti chiave relativi ai motori di ricerca full-text, con un focus speciale su Elasticsearch.

Poiché si tratta di un articolo orientato a Java, non forniremo un tutorial dettagliato passo passo su come configurare Elasticsearch e mostreremo come funziona sotto il cofano. Invece, mireremo al client Java e come utilizzare le funzionalità principali come index , delete , get e search .

2. Configurazione

Per semplicità, useremo un'immagine docker per la nostra istanza Elasticsearch, anche se andrà bene qualsiasi istanza Elasticsearch in ascolto sulla porta 9200 .

Iniziamo attivando la nostra istanza Elasticsearch:

docker run -d --name es762 -p 9200:9200 -e "discovery.type=single-node" elasticsearch:7.6.2

Per impostazione predefinita, Elasticsearch ascolta sulla porta 9200 per le prossime query HTTP. Possiamo verificare che sia stato avviato con successo aprendo // localhost: 9200 / URL nel tuo browser preferito:

{ "name" : "M4ojISw", "cluster_name" : "docker-cluster", "cluster_uuid" : "CNnjvDZzRqeVP-B04D3CmA", "version" : { "number" : "7.6.2", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "2f4c224", "build_date" : "2020-03-18T23:22:18.622755Z", "build_snapshot" : false, "lucene_version" : "8.4.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.8.0-beta1" }, "tagline" : "You Know, for Search" }

3. Configurazione Maven

Ora che abbiamo il nostro cluster Elasticsearch di base attivo e funzionante, passiamo direttamente al client Java. Prima di tutto, dobbiamo avere la seguente dipendenza Maven dichiarata nel nostro file pom.xml :

 org.elasticsearch elasticsearch 7.6.2 

Puoi sempre controllare le ultime versioni ospitate da Maven Central con il link fornito in precedenza.

4. API Java

Prima di passare direttamente a come utilizzare le principali funzionalità dell'API Java, è necessario avviare RestHighLevelClient :

ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo("localhost:9200").build(); RestHighLevelClient client = RestClients.create(clientConfiguration).rest();

4.1. Indicizzazione dei documenti

La funzione index () consente di memorizzare un documento JSON arbitrario e renderlo ricercabile:

@Test public void givenJsonString_whenJavaObject_thenIndexDocument() { String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564," +"\"fullName\":\"John Doe\"}"; IndexRequest request = new IndexRequest("people"); request.source(jsonObject, XContentType.JSON); IndexResponse response = client.index(request, RequestOptions.DEFAULT); String index = response.getIndex(); long version = response.getVersion(); assertEquals(Result.CREATED, response.getResult()); assertEquals(1, version); assertEquals("people", index); }

Tieni presente che è possibile utilizzare qualsiasi libreria Java JSON per creare ed elaborare i tuoi documenti. Se non hai familiarità con nessuno di questi, puoi utilizzare gli helper di Elasticsearch per generare i tuoi documenti JSON :

XContentBuilder builder = XContentFactory.jsonBuilder() .startObject() .field("fullName", "Test") .field("dateOfBirth", new Date()) .field("age", "10") .endObject(); IndexRequest indexRequest = new IndexRequest("people"); indexRequest.source(builder); IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); assertEquals(Result.CREATED, response.getResult());

4.2. Interrogazione di documenti indicizzati

Ora che abbiamo un documento JSON ricercabile digitato indicizzato, possiamo procedere e cercare utilizzando il metodo search () :

SearchRequest searchRequest = new SearchRequest(); SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); SearchHit[] searchHits = response.getHits().getHits(); List results = Arrays.stream(searchHits) .map(hit -> JSON.parseObject(hit.getSourceAsString(), Person.class)) .collect(Collectors.toList());

I risultati restituiti dal metodo search () sono chiamati Hits , ogni Hit si riferisce a un documento JSON che corrisponde a una richiesta di ricerca.

In questo caso, l' elenco dei risultati contiene tutti i dati memorizzati nel cluster. Nota che in questo esempio stiamo usando la libreria FastJson per convertire le stringhe JSON in oggetti Java.

Possiamo migliorare la richiesta aggiungendo parametri aggiuntivi per personalizzare la query utilizzando i metodi QueryBuilders :

SearchSourceBuilder builder = new SearchSourceBuilder() .postFilter(QueryBuilders.rangeQuery("age").from(5).to(15)); SearchRequest searchRequest = new SearchRequest(); searchRequest.searchType(SearchType.DFS_QUERY_THEN_FETCH); searchRequest.source(builder); SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

4.3. Recupero ed eliminazione di documenti

I metodi get () e delete () consentono di ottenere o eliminare un documento JSON dal cluster utilizzando il suo id:

GetRequest getRequest = new GetRequest("people"); getRequest.id(id); GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT); // process fields DeleteRequest deleteRequest = new DeleteRequest("people"); deleteRequest.id(id); DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);

La sintassi è piuttosto semplice, devi solo specificare l'indice accanto all'id dell'oggetto.

5. Esempi di QueryBuilders

La classe QueryBuilders fornisce una varietà di metodi statici utilizzati come abbinamenti dinamici per trovare voci specifiche nel cluster. Durante l'utilizzo del metodo search () per cercare documenti JSON specifici nel cluster, possiamo utilizzare i generatori di query per personalizzare i risultati della ricerca.

Di seguito è riportato un elenco degli utilizzi più comuni dell'API QueryBuilders .

Il metodo matchAllQuery () restituisce un oggetto QueryBuilder che corrisponde a tutti i documenti nel cluster:

QueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();

Il rangeQuery () corrisponde documenti in cui il valore di un campo è entro un certo intervallo:

QueryBuilder matchDocumentsWithinRange = QueryBuilders .rangeQuery("price").from(15).to(100)

Fornendo un nome di campo - ad es. FullName , e il valore corrispondente - ad es. John Doe , Il metodo matchQuery () corrisponde a tutti i documenti con il valore di questo campo esatto:

QueryBuilder matchSpecificFieldQuery= QueryBuilders .matchQuery("fullName", "John Doe");

Possiamo anche utilizzare il metodo multiMatchQuery () per creare una versione multi-campo della query di corrispondenza:

QueryBuilder matchSpecificFieldQuery= QueryBuilders.matchQuery( "Text I am looking for", "field_1", "field_2^3", "*_field_wildcard");

Possiamo usare il simbolo del cursore (^) per potenziare campi specifici .

Nel nostro esempio il campo_2 ha un valore di boost impostato su tre, rendendolo più importante degli altri campi. Nota che è possibile utilizzare caratteri jolly e query regex, ma dal punto di vista delle prestazioni, fai attenzione al consumo di memoria e al ritardo del tempo di risposta quando si tratta di caratteri jolly, perché qualcosa come * _apples può causare un enorme impatto sulle prestazioni.

Il coefficiente di importanza viene utilizzato per ordinare il set di risultati degli hit restituiti dopo l'esecuzione del metodo s earch () .

Se hai più familiarità con la sintassi delle query Lucene, puoi utilizzare il metodo simpleQueryStringQuery () per personalizzare le query di ricerca:

QueryBuilder simpleStringQuery = QueryBuilders .simpleQueryStringQuery("+John -Doe OR Janette");

Come probabilmente puoi intuire, possiamo usare la sintassi Query Parser di Lucene per costruire query semplici ma potenti . Ecco alcuni operatori di base che possono essere utilizzati insieme agli operatori AND / OR / NOT per creare query di ricerca:

  • L'operatore richiesto ( + ): richiede che una parte di testo specifica esista da qualche parte nei campi di un documento.
  • L'operatore di proibizione ( - ): esclude tutti i documenti che contengono una parola chiave dichiarata dopo il simbolo ( - ).

6. Conclusione

In questo breve articolo, abbiamo visto come utilizzare l'API Java di ElasticSearch per eseguire alcune delle funzionalità comuni relative ai motori di ricerca full-text.

Puoi controllare l'esempio fornito in questo articolo nel progetto GitHub.