Cliente REST de alto nivel para ElasticSearch

En un artículo anterior hablábamos sobre ElasticSearch & Spring Boot, esta combinación nos facilitó crear un CRUD de forma sencilla. En esta entrada hablaremos de Java High-Level REST Client, un cliente de alto nivel desarrollado por los creadores de ElasticSearch.

¿Qué es Java High-Level REST Client?

El cliente de alto nivel de ElasticSearch es un solución construida sobre el cliente de bajo nivel, con cierto grado de compatibilidad entre las distintas versiones de ES. El cliente permite abrir una conexión con ES y realizar operaciones sobre el cluster (llamadas request/response). Como una característica relevante destaca la posibilidad de realizar operaciones síncronas y asíncronas; además de soporte completo para el poderoso lenguaje DSL de ES.

Dependencias

Para usar esta librería solo requerimos añadir la dependencia a nuestro proyecto maven o gradle en dependencia de como estemos trabajando.

     <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.4.3</version>
        </dependency>
compile "org.elasticsearch.client:elasticsearch-rest-high-level-client:6.4.3"

La versión a utilizar debe estar de acuerdo con la versión de ElasticSearch que se emplea, aunque en muchos casos el cliente soporta varias versiones, para una mayor seguridad se recomienda tener ambas versiones al mismo nivel.

Realizando la conexión

Para crear la conexión debemos crear un objeto de tipo RestHighLevelClient, este nos devolverá un handler de conexión al cliente con el que podremos invocar todas las funcionalidad y operaciones.

  RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http"),
                        new HttpHost("localhost", 9201, "http")));

Al terminar de trabajar, debemos liberar la conexión.

client.close();

Verificar la salud de ES

El cliente de alto nivel nos permite verificar el estado de salud del cluster, para ello podemos usar la siguiente instrucción.

boolean response = client.ping(RequestOptions.DEFAULT);

Esto nos devolverá verdadero si la conexión y el cluster están en buen estado.

Guardando documentos en ES

Una vez creada la conexión, pasamos a realizar las operaciones de escritura y/o lectura sobre ES, veamos como escribir un documento JSON.

// ....
ActionListener listener = new ActionListener<IndexResponse>() {
        @Override
        public void onResponse(IndexResponse indexResponse) {
// Podemos hacer cosas con la respuesta.
        }
        @Override
        public void onFailure(Exception e) {
// Podemos hacer cosas con la excepción si falla.
        }
    };
    public void save(String json) {
        IndexRequest request = new IndexRequest("news");
        request.id("theId");
        request.source(json, XContentType.JSON);
        client.indexAsync(request, RequestOptions.DEFAULT.DEFAULT, listener);
    }

Explicando el código arriba:

La función save(json) es una función que hemos creado pero que no tiene que ver con la API de la librería, lo de adentro de ella sí. El objeto de tipo IndexRequest lo usamos para seleccionar el índice en ES sobre el que vamos a escribir, le establecemos un id, le pasamos el source y el tipo del source (En un documento JSON de ES el source ser refiere al documento en sí a guardar sin los metadatos propios que incorpora ES).

La operación de guardado la podemos hacer síncrona o asíncrona, en este caso indicamos al cliente que guarde asincronamente nuestro request y le dejamos un listener en el callback para que nos notifique del resultado. El listener implementa OnResponse(IndexResponse) para si todo fue bien, y OnFailure(Exception) para notificarnos de posible errores.

Es importante recordar que ES tiene entre sus características el versionado de documentos, por lo que si al guardar un documento le ponemos varias veces el mismo Id este se actualizará y la versión del documento se incrementará, genial verdad ?

Leyendo datos de ES

De la lectura de datos no vamos a hablar mucho, puesto que el API es muy amplia y esta muy bien documentada acá. Es importante que a la hora de ver la documentación te fijes estés en la versión de la librería que estas usando.

Los pasos para realizar una lectura son:

  • Crear un objeto de tipo SearchRequest, un objeto SearchSourceBuilder y un objeto particular de acuerdo al tipo de búsqueda que deseamos hacer (como pueder MatchQueryBuilder, BoolQueryBuilder, etc).
  • Asignar al searchSourceBuilder la Query que hemos creado de acuerdo al tipo de búsqueda elegido.
  • Asignarle al searchRequest el searchSourceBuilder.
  • Usar la conexión del cliente creada y ejecutar la búsqueda, el resultado asignarlo a un objeto de tipo SearchResponse.
  • Extraer del SearchResponse los SearchHits (Objetos que tienen los resultados de la búsqueda)

Ejemplo:

SearchRequest searchRequest = new SearchRequest("news");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// Ejemplo de Map para si queremos pasar un Map al método que realizará la búsqueda.
Map<String, String> fields = new HashMap<>();
       fields.put("baseLink","https://blog.sacavix.com/feed/");
       fields.put("topic", "tech");
       fields.put("author", "Yoandy");
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        for (Map.Entry<String, String> entry : fields.entrySet()){
            boolQuery.must(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
        }
        searchSourceBuilder.query(boolQuery);
        searchSourceBuilder.size(matchQueryBuilder.maxExpansions());
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;
        try {
            searchResponse = eSconfig.getConnection().search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            System.out.println(searchHits.getTotalHits());
            for (SearchHit searchHit: searchHits) {
//SearchHit tiene el objeto resultado de la búsqueda.
                System.out.println(searchHit.getSourceAsString());
            }
            System.out.println();
        } catch (Exception e) {
            System.out.println("Error");
        }
     

El objeto SearchHit tiene el resultado de la búsqueda, específicamente getSourceAsString nos devuelve lo que hemos insertado y que coincide claramente con el patrón de búsqueda.

El lenguaje DSL es muy amplio y poderoso, si no has visto la presentación en ES en idioma español, te animo a que le des una revisada y aprendas más sobre este excelente motor de búsqueda.

Espero te haya sido útil el artículo, si fue así podemos tomarnos un café.

1 thought on “Cliente REST de alto nivel para ElasticSearch

Leave a Reply

Your email address will not be published. Required fields are marked *