Skip to content

ElasticSearch y Couchdb river

En este post vamos a ver como incorporar un motor de búsqueda en una aplicación (Rails) para indexar documentos almacenados en Couchdb.

ElasticSearch es un motor de búsqueda construido sobre Lucene, es Open Source (Apache 2), es distruido y presenta un interfaz Restful. ElasticSearch cuenta con una funcionalidad denominada River. River es un sistema de plugins que una vez instalado en ElasticSearch permite extraer datos (o enviarle datos) que será indexados e incoporados al cluster de ElasticSearch, para su posterior consulta. ElasticSearch cuenta con 4 diferentes rivers listos para ser instalados: Couchdb, RabbitMQ, Twitter y Wikipedia. Aquí nos centraremos en el uso del river para Couchdb.

El river para Couchdb se basa en una funcionalidad de Couchdb denominada Continuous Changes API. Una vez te conectas a este API y manteniendo la conexión abierta Couchdb te enviará las modificaciones y seguirá manteniendo la conexión abierta para enviarte las siguientes modificaciones hasta que decidas cerrar la conexión. Siempre tendremos una conexión abierta (por river definido) pero Couchdb es capaz de manejar un gran número de conexiones sin problemas.

Como instalamos ElasticSearch y el river de Couchdb:

# INSTALL ElasticSearch
curl -k -L -# -o elasticsearch-0.16.2.tar.gz \
"http://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.16.2.tar.gz"
tar -zxf elasticsearch-0.16.2.tar.gz
rm -f elasticsearch-0.16.2.tar.gz
# INSTALL Couchdb River
./elasticsearch-0.16.2/bin/plugin -install river-couchdb
# Start ElasticSearch
./elasticsearch-0.16.2/bin/elasticsearch -p #{destination_root}/tmp/pids/elasticsearch.pid
# Couchdb App Database (couchdb_myapp_development)
curl -vX PUT 'http://127.0.0.1:5984/couchdb_myapp_development'
# Create river index
curl -XPUT 'http://localhost:9200/_river/couchdb_myapp_development_river/_meta' -d '{
"type" : "couchdb",
"couchdb" : {
"host" : "localhost",
"port" : 5984,
"db" : "couchdb_myapp_development",
"filter" : null
}
}'

El propio river de Couchdb con la configuración que le hemos dado se enganchará a la siguiente url, para ir recibiendo las modificaciones que hagamos en la base de datos de couchdb e ir indexando documentos.

http://localhost:5984/couchdb_myapp_development/_changes?feed=continuous&include_docs=true&heartbeat=10000

Sin embargo con esta configuración incluimos en el mismo índice todos los documentos de Couchdb, si queremos establecer un indice para dos tipos de documentos como por ejemplo Product y Person, debemos establecer un filtro a la hora de crear el river. Este filtro debe hacer referencia al nombre de un filtro especificado a la hora de definir un design document.

# Create design documents with the filters
curl -vX PUT 'http://127.0.0.1:5984/couchdb_myapp_development/_design/Product' -d '{
"_id": "_design/Product",
"language": "javascript",
"filters": {
"product": "function(doc, req) { return doc['type'] == 'Product'; }"
}
}'
curl -vX PUT 'http://127.0.0.1:5984/couchdb_myapp_development/_design/Person' -d '{
"_id": "_design/Person",
"language": "javascript",
"filters": {
"person": "function(doc, req) { return doc['type'] == 'Person'; }"
}
}'
view raw DESIGN_DOCS hosted with ❤ by GitHub
# Create the river for each type of document
curl -XPUT 'http://localhost:9200/_river/products/_meta' -d '{
"type" : "couchdb",
"couchdb" : {
"host" : "localhost",
"port" : 5984,
"db" : "couchdb_myapp_development",
"filter" : "Product/product"
},
"index" : {
"index" : "products",
"type" : "product"
}
}'
curl -XPUT 'http://localhost:9200/_river/people/_meta' -d '{
"type" : "couchdb",
"couchdb" : {
"host" : "localhost",
"port" : 5984,
"db" : "couchdb_myapp_development",
"filter" : "Person/person"
},
"index" : {
"index" : "people",
"type" : "person"
}
}'
view raw FILTERING hosted with ❤ by GitHub

Debemos tener en cuenta que nuestros documentos de couchdb tienen especificado un atributo ‘type’ que permite realizar el filtrado.

Por último crearemos un documento de tipo ‘Product’ y realizaremos una búsqueda

# Store one document
curl -X POST 'http://127.0.0.1:5984/couchdb_myapp_development/' -d '{
"_id": "124a10f3b56882607c8f3c89cd053c4c",
"type": "Product",
"name": "Time Capsule",
"description": "La Time Capsule es una estación base Airport completa con un disco duro integrado con la que podrás hacer copias de seguridad de manera inalámbrica y crear una red Wi-Fi con un solo dispositivo."
}'
# Execute a search query
curl -X POST "http://localhost:9200/products/product/_search?pretty=true" -d '{
"query" : {
"query_string" : {
"query" : "inalámbrica"
}
}
}' =>
{
"took" : 29,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.033902764,
"hits" : [ {
"_index" : "products",
"_type" : "product",
"_id" : "124a10f3b56882607c8f3c89cd053c4c",
"_score" : 0.033902764, "_source" : {"_rev":"1-34cacc5258bbca9b83bef738a08f155d","_id":"124a10f3b56882607c8f3c89cd053c4c","description":"La Time Capsule es una estación base Airport completa con un disco duro integrado con la que podrás hacer copias de seguridad de manera inalámbrica y crear una red Wi-Fi con un solo dispositivo.","name":"Time Capsule","type":"Product"}
} ]
}
view raw EXAMPLE hosted with ❤ by GitHub