Primeros pasos con Elasticsearch

9
53362

Primeros pasos con elasticsearch

0.Índice de Contenidos

1. Introducción

Elasticsearch es un producto que permite indexar y analizar en tiempo real grandes cantidades de datos de manera distribuida. Va un paso más allá de la búsqueda por texto gracias a un DSL y un Api para búsquedas más complicadas.

Elasticsearch permite almacenar documentos ( estructurados o no ) e indexar todos los campos de estos documentos en casi tiempo real.

Elasticsearch a diferencia de otros sistemas parecidos, no necesita declarar un esquema de la información que añadimos, pero para sacar mayor partido a la información tendremos que añadir los llamados mappings que funcionan más o menos como un schema.

Conceptos en los que se basa

Cluster

Un cluster es un conjunto de uno o más nodos que mantienen toda la información de manera distribuida e indexada. Cada cluster está identificado por un nombre, por defecto se llaman «elasticsearch».

Node

Un nodo es un server que forma parte de un cluster, almacena tu información y ayuda con las tareas de indexación y búsqueda del cluster. Los nodos están identificados por un nombre también, pero en este caso cada nodo está nombrado tras un personaje de Marvel.

Por defecto están configurados para ser parte de un cluster con el nombre de «elasticsearch».

Puede haber tantos nodos como quieras por cada Cluster, en caso de que no haya ningún Cluster configurado en el momento de creación este lo creará y se unirá a él.

Index

Un Index es una colección de documentos que tienen características similares. Los índices están identificados por un nombre, el cual usaremos a la hora de indexar, buscar, actualizar y borrar.

Sharding y Replicas

Cuando la información que estamos indexando sobrepasa el límite de una sola máquina, elasticsearch nos ofrece distintas maneras de saltarnos esa limitación.

El sharding nos permite dividir estos índices en distintas «piezas» ofreciéndonos la posibilidad de escalar horizontalmente (añadiendo más máquinas), además de paralelizar y distribuir las distintas operaciones que hagamos sobre esos índices.

La replicación nos ofrece un mecanismo para que en caso de fallo el usuario no se vea afectado.

Descarga e instalación

Para instalar necesitamos tener como mínimo la JDK 7 instalada en nuestro sistema.

Link de descarga

Mediante la terminal, ejecutamos el siguiente comando para iniciar elasticsearch

$   cd to/download/folder
$   bin/elasticsearch

Esperamos a que termine de iniciarse y accedemos a la URL ( http://localhost:9200/ ) para ver que todo ha ido correctamente, nos debería aparecer una respuesta en formato JSON parecida a esta:

{
  "status" : 200,
  "name" : "Captain Ultra",
  "version" : {
    "number" : "1.3.2",
    "build_hash" : "dee175dbe2f254f3f26992f5d7591939aaefd12f",
    "build_timestamp" : "2014-08-13T14:29:30Z",
    "build_snapshot" : false,
    "lucene_version" : "4.9"
  },
  "tagline" : "You Know, for Search"
}

Para ver el estado de nuestro nodo podriamos usar un plugin que nos permite ver en tiempo real el estado de elasticsearch.

El plugin se encuentra en la siguiente url, podemos seguir las instrucciones para instalar el plugin en local o acceder a través de esta url

Estado nodo

Jugando con elasticsearch

Para ver elasticsearch en funcionamiento vamos a hacer una pequeña prueba de concepto, vamos a indexar los últimos tweets que hablen del mundial de baloncesto y vamos a buscar información dentro de esos Tweets.

Para ello vamos a usar la librería Twitter4J y el cliente Java de elasticsearch.

Extraer de Twitter una serie de Tweets

Para ello vamos a usar Twitter4J que nos proporciona un wrapper sobre la API de Twitter, podemos ver cómo configurar Twitter4J para hacer las peticiones a Twitter aquí, una vez lo tengamos configurado, nos disponemos a hacer una busqueda de texto, en este caso sobre el Mundial de Baloncesto:

    public static List searchForTweets() throws TwitterException {
        Twitter twitter = new TwitterFactory().getInstance();
        Query query = new Query("mundial baloncesto");
        List tweetList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            QueryResult queryResult = twitter.search(query);
            tweetList.addAll(queryResult.getTweets());
            if (!queryResult.hasNext()) {
                break;
            }
            query = queryResult.nextQuery();
        }
        Gson gson = new Gson();

        return tweetList.stream().map(gson::toJson).collect(Collectors.toList());
    }

Con esto vamos a conseguir una lista de Tweets en un String en formato JSON, el siguiente paso sería crear un indice en el que almacenaremos los Tweets.

Usando el Api Java de elasticsearch

Elasticsearch nos ofrece diversas librerías cliente desde las cuales manejar los nodos/clusters/indices.

En nuestro caso vamos a crear un nuevo Índice para almacenar nuestros Tweets y vamos a añadirlos al indice.

Lo primero es indicarle a elasticsearch donde se encuentra instalado :

    Client client = new TransportClient()
                .addTransportAddress(new InetSocketTransportAddress("localhost", 9300));

Aunque a por HTTP nos conectemos a través del puerto 9200, el cliente se conecta a través del puerto 9300.

El siguiente paso es crear un index, en el que almacenaremos los Tweets.

	String index = "tweets";
	client.admin().indices()
		        	.create(new CreateIndexRequest(index))
		        	.actionGet();

Con este código habremos creado un index con el nombre tweets, el siguiente paso es añadir los tweets a este index para poder buscar en ellos.

    public static void indexExampleData(Client client, List tweetJsonList, String index) {


        BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();

        tweetJsonList.forEach((jsonTweet) -> {
            bulkRequestBuilder.add(new IndexRequest(index, "tweet")
                    .source(jsonTweet));
        });

        BulkResponse bulkItemResponses = bulkRequestBuilder.get();
    }

Para esto vamos a usar una Request de tipo bulk el cual se usa para realizar distintas acciones en una misma petición, en este caso todas las acciones serán de tipo add index, pero podría haber acciones de distintos tipos en la misma bulk request.

Buscando en la información indexada

Elasticsearch ofrece muchas posibilidades de búsqueda, dependiendo de las necesidades que tengas se adapta a ellas. En este caso vamos a hacer una búsqueda sencilla por texto, buscando solo en el texto del tweet.

        SearchResponse searchResponse = client.prepareSearch("tweets")
                .setQuery(QueryBuilders.termsQuery("text", "españa"))
                .setSize(25)
                .execute()
                .actionGet();

Buscamos en el index tweets aquellos tweets que contengan el texto "españa", "text" es el campo que contiene el texto del tweet, si quisiéramos buscar en otros campos como podría ser el nombre del usuario que ha posteado el tweet.

resultados busqueda

En este caso vemos que aparece demasiadas veces la palabra "apuesta", si quisiéramos realizar una query que ignorase todos aquellos resultados que contuvieran la palabra "apuesta" podríamos hacerlo de la siguiente manera:

	import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
	
	public static void searchExample(Client client) {
        BoolQueryBuilder queryBuilder = QueryBuilders
                .boolQuery()
                .must(termsQuery("text", "españa"))
                .mustNot(fuzzyQuery("text", "apuesta"));

        SearchResponse searchResponse = client.prepareSearch("tweets")
                .setQuery(queryBuilder)
                .setSize(25)
                .execute()
                .actionGet();
         }

En este caso hemos elegido la búsqueda "fuzzy" que usando algoritmos de comparación de cadenas de texto, busca términos similares al introducido, por ejemplo

Conclusiones

Elasticsearch nos ofrece la posibilidad de hacer búsquedas de texto tan complicadas como sean nuestras necesidades, visualizar el estado de nuestros nodos, y escalar sin demasiadas necesidades si se diera el caso de que necesitáramos más potencia.

9 COMENTARIOS

  1. Gracias por el vistazo, empiezo en dos días con un curro de esto 🙂

    P.t.i.:
    «El Api de Java nos permite realizar busquedas más complicadas, podemos ver un resumen del DSL que nos ofrece la query aquí.»

    El «aquí» a perdido el enlace…

    «En este caso hemos elegido la búsqueda “fuzzy” que usando algoritmos de comparación de cadenas de texto, busca términos similares al introducido, por ejemplo »

    Y no hay ningún ejemplo…

    Saludos!

  2. En el párrafo que dice:

    «Con este código habremos creado un index con el nombre tweets, el siguiente paso es añadir los tweets a este index para poder buscar en ellos», en la línea 7, el comado no debiera usar la palabra «tweets» en vez de «tweet»?

    • Si lo entendí bien, lo que hace es añadir al index «tweets» un elemento «tweet» que es cada elemento de la lista, como identificador del elemento que está guardando en el index «tweets», todos tienen el mismo identificador. Entiendo que como después la forma de recuperar esa información es a través de palabras clave (incluidas o excluidas), pues no tendría sentido meterle un identificador unívoco.

      Saludos.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad