sábado, diciembre 12, 2015

ElasticSearch: Algunos conceptos básicos

Estas últimas semanas estoy trabajando con el buscador Elasticsearch. Quiero recopilar algunas notas de los conceptos, terminología y uso básico del mismo.

Elasticsearch es un motor de almacenamiento y búsqueda de documentos en formato JSON. Estos documentos se organizan índices de acuerdo a nuestros requerimientos. Los índices internamente se dividen en shards los cuales pueden residir en diferentes nodos. Un esquema sencillo de esta relación es el siguiente:

La primera decisión importante cuando se despliega un proyecto sobre Elasticsearch es decidir cual va a ser el número de shards que va a tener cada uno de los índices que usemos. Esta es una de la primeras preguntas que nos debemos hacer. El número de shards determina como podemos distribuir el índice entre los diferentes nodos que forman el cluster. Además, cada shard es un índice de Lucene que ocupa los correspondientes recursos en el sistema. Además está el inconveniente de que no se puede cambiar los shards de un índice sin reindexar de nuevo todos los datos y es un parámetro fundamental a la hora de evaluar el rendimiento del cluster y los problemas de escalado que pudiera haber. Como todo, el número que se use es un conjunto de compromisos entre nuestra escalabidad y rendimiento

Otro concepto importante a la hora de manejar los índices de elasticsearch son aquellos shards que son réplicas. Estás se usan para implementar la redundacia a fallos. Si un nodo que tiene un shard primario cae, la réplica pasa a ser el shard primario y así el cluster puede seguir funcionando.

Los shards, tanto primarios como réplicas se distribuyen entre los diferenes nodos del cluster que forman Elasticsearch para conseguir un escalado horizontal entre varias máquinas. Un cluster lo forman varios nodos que tienen el mismo nombre. Éste se fija en el fichero de configuración elasticsearch.yml con la propiedad cluster.name:. En la arquitectura de Elasticsearch un nodo siempre es el master encargado de la gestión de los índices y coordinación de los diferentes nodos. Las peticiones de indexado y búsqueda que reciben los nodos son rutadas de manera adecuada a donde están los datos.

Para interactuar con Elasticsearch lo más sencillo es usar su interfaz REST que por defecto escucha en el puerto 9200 de la máquina donde se está ejectuando Elasticsearch. Es muy fácil usar software como curl para realizar dichas peticiones. Aparte del verbo http (GET, PUT, POST, DELETE) la información que necesita Elasticsearch viaja en el cuerpo de las peticiones codificado en formato JSON. La mayoría de las respuestas que da el servidor de Elasticsearch son también en este formato. Existe otro método para interactuar con el cluster de Elasticsearch y es el llamado API de transporte, donde el sistema cliente simula ser otro nodo del cluster. Hay multitud de librerías que encapsulan este acceso al servidor como Python Elasticsearch Client para Python. Para algunas cosas que hago en Python he usado bastante Requests montando las peticiones directamente.

Intereactuar con el API rest es bastante sencillo. Por ejemplo, esta simple petición nos devuelve un JSON con las propiedades del server. A continuación unos ejemplos de como crear un índice, introducir datos, devolverlos y borrar el índice.

baldurgate:~ terron$curl -XGET http://localhost:9200
{
  "name" : "Krang",
  "cluster_name" : "avos",
  "version" : {
    "number" : "2.0.0",
    "build_hash" : "de54438d6af8f9340d50c5c786151783ce7d6be5",
    "build_timestamp" : "2015-10-22T08:09:48Z",
    "build_snapshot" : false,
    "lucene_version" : "5.2.1"
  },
  "tagline" : "You Know, for Search"
}

Crear un índice y ver las propiedades del índice es muy sencillo. Se añade el parámetro pretty para que nos devuelva el JSON formateado para que su lectura sea sencilla

baldurgate:~ terron$curl -XPUT http://localhost:9200/prueba?pretty
{
  "acknowledged" : true
}
baldurgate:~ terron$curl -XGET http://localhost:9200/prueba?pretty
{
  "prueba" : {
    "aliases" : { },
    "mappings" : { },
    "settings" : {
      "index" : {
        "creation_date" : "1449933189870",
        "number_of_shards" : "1",
        "number_of_replicas" : "1",
        "uuid" : "wFT1ymODQCqsXIOkeCakVw",
        "version" : {
          "created" : "2000099"
        }
      }
    },
    "warmers" : { }
  }
}

Introducir datos en el índice se puede hacer con curl de manera sencilla. Voy a dejar, de momento el fundamental tema de los mapeos, dejando que sea el propio servidor el encargado de generarlos automáticamente. Por ejemplo, para crear dentro del índice prueba un tipo de datos llamado libro, introducimos un

baldurgate:~ terron$curl -XPOST http://localhost:9200/prueba/libro/?pretty \
  -d '{"autor": "Julio verne","titulo": "Veinte mil lenguas de viaje submarino"}'
{
  "_index" : "prueba",
  "_type" : "libro",
  "_id" : "AVGWzzLD6jhN-gT8oefN",
  "_version" : 1,
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "created" : true
}

Y una búsqueda rápida que devuelva todo lo que tiene el índice

baldurgate:~ terron$curl -XGET http://localhost:9200/prueba/_search
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "prueba",
      "_type" : "libro",
      "_id" : "AVGWztnY6jhN-gT8oefM",
      "_score" : 1.0,
      "_source":{"autor": "Julio verne","titulo": "Veinte mil lenguas de viaje submarino"}
    }]
  }
}

Por último, se puede borrar todo el índice como un simple:

baldurgate:~ terron$curl -XDELETE http://localhost:9200/prueba {
  "acknowledged":true
}

No hay comentarios: