Cliente Elasticsearch para Rust: elasticsearch-rs
Elasticsearch es un potente sistema distribuido de búsqueda y análisis basado en Apache Lucene. Para interactuar con él desde aplicaciones en Rust, existe el cliente oficial: elasticsearch-rs. Esta biblioteca ofrece un conjunto completo de herramientas para trabajar con la API REST de Elasticsearch, incluyendo indexación, búsqueda, agregaciones y administración del clúster. En este artículo, analizaremos en detalle la instalación, configuración y las principales funcionalidades de elasticsearch-rs con ejemplos de código.
¿Qué es elasticsearch-rs?
elasticsearch-rs es el cliente asíncrono oficial de Elasticsearch para el lenguaje Rust, desarrollado por la empresa Elastic. Está basado en la popular biblioteca de cliente HTTP asíncrono reqwest y proporciona una API con tipos seguros para todos los endpoints de Elasticsearch. Sus principales ventajas son:
- Soporte completo para Elasticsearch 7.x y 8.x — todas las operaciones principales: CRUD, búsqueda, agregaciones, administración de índices.
- Asincronía — utiliza async/await, lo que permite procesar múltiples solicitudes de manera eficiente.
- Seguridad de tipos — las estructuras de solicitudes y respuestas están fuertemente tipadas, lo que reduce errores en tiempo de ejecución.
- Serialización/deserialización automática — a través de
serdeyserde_json. - Soporte de autenticación — Basic Auth, claves API, SSL/TLS.
Instalación
Agrega la dependencia en tu Cargo.toml:
[dependencies]
elasticsearch = "8.14.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
Conexión básica
Creemos un cliente que se conecte a una instancia local de Elasticsearch:
use elasticsearch::Elasticsearch;
use elasticsearch::http::transport::Transport;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let transport = Transport::single_node("http://localhost:9200")?;
let client = Elasticsearch::new(transport);
// Verificar conexión
let response = client.ping().send().await?;
println!("Elasticsearch disponible: {}", response.status_code());
Ok(())
}
Operaciones principales: CRUD
1. Indexar un documento
Agreguemos un documento con información de un libro en el índice books:
#[derive(Serialize, Deserialize, Debug)]
struct Book {
title: String,
author: String,
year: u16,
isbn: String,
}
let book = Book {
title: "Rust en acción".into(),
author: "Tim McNamara".into(),
year: 2023,
isbn: "978-5-4461-2345-6".into(),
};
let response = client
.index(IndexParts::IndexId("books", "1"))
.body(json!(book))
.send()
.await?;
println!("Documento indexado: {:?}", response.body());
2. Obtener un documento
let response = client
.get(GetParts::IndexId("books", "1"))
.send()
.await?;
if response.status_code().is_success() {
let book: Book = response.json().await?;
println!("Documento encontrado: {:?}", book);
}
3. Actualizar un documento
let response = client
.update(UpdateParts::IndexId("books", "1"))
.body(json!({
"doc": { "year": 2024 }
}))
.send()
.await?;
println!("Actualizado: {:?}", response.body());
4. Eliminar un documento
let response = client
.delete(DeleteParts::IndexId("books", "1"))
.send()
.await?;
println!("Eliminado: {:?}", response.body());
Búsqueda con Query DSL
Realicemos una búsqueda de texto completo en el campo title:
use elasticsearch::SearchParts;
let response = client
.search(SearchParts::Index(&["books"]))
.body(json!({
"query": {
"match": {
"title": "Rust"
}
}
}))
.send()
.await?;
let search_result = response.json::<serde_json::Value>().await?;
println!("Resultados de búsqueda: {:?}", search_result);
Agregaciones
Ejemplo de una agregación para contar libros por año:
let response = client
.search(SearchParts::Index(&["books"]))
.body(json!({
"aggs": {
"por_año": {
"terms": { "field": "year" }
}
}
}))
.send()
.await?;
let aggs_result = response.json::<serde_json::Value>().await?;
println!("Agregaciones: {:?}", aggs_result);
Conclusión
elasticsearch-rs es una biblioteca robusta y completa para integrar Elasticsearch en aplicaciones Rust. Su diseño asíncrono, seguridad de tipos y soporte para todas las funcionalidades de Elasticsearch la convierten en la opción ideal para proyectos que requieren búsqueda y análisis de datos a gran escala. Con los ejemplos mostrados, ya puedes empezar a construir tus propias soluciones de búsqueda en Rust.