Elasticsearch client for Rust: elasticsearch-rs
elasticsearch-rs is the official asynchronous client for interacting with Elasticsearch from the Rust ecosystem. The library provides a complete set of tools for working with the search engine: from simple CRUD operations to complex aggregations and bulk requests. It is developed and maintained by the Elastic team, guaranteeing API relevance and compatibility with the latest versions of Elasticsearch.
Key Features
- Full Elasticsearch API support — indexing, search, aggregations, index management, mapping, and cluster settings.
- Asynchronous — built on top of tokio and reqwest, allowing thousands of requests to be processed without blocking threads.
- Type safety — all requests and responses are strictly typed, validation errors are caught at compile time.
- Bulk operations support — mass document loading and updating with automatic error handling.
- SSL/TLS and authentication — built-in support for HTTPS, Basic Auth, API keys, and tokens.
- Serialization via serde — documents are automatically converted to/from JSON using the serde crate.
Installation and Setup
Add the dependency to Cargo.toml:
[dependencies]elasticsearch = "8.14.0"serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"tokio = { version = "1.0", features = ["full"] }Basic connection to a local Elasticsearch instance:
use elasticsearch::{Elasticsearch, Error};use url::Url;
#[tokio::main]async fn main() -> Result<(), Error> { let client = Elasticsearch::new( elasticsearch::http::transport::Transport::single_node( Url::parse("http://localhost:9200")? )? ); // Connection check let response = client.ping().send().await?; println!("Elasticsearch available: {}", response.status_code()); Ok(())}Working with Documents
Indexing a Document
Define a structure for serialization:
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]struct Book { title: String, author: String, year: u16, isbn: String,}Indexing a new document:
use elasticsearch::{IndexParts, SearchParts};use serde_json::json;
async fn index_book(client: &Elasticsearch, book: &Book) -> Result<(), Error> { let response = client .index(IndexParts::IndexId("books", &book.isbn)) .body(book) .send() .await?; println!("Document indexed: {:?}", response); Ok(())}Searching an Index
Full-text search example:
async fn search_books(client: &Elasticsearch, query: &str) -> Result, Error> { let response = client .search(SearchParts::Index(&["books"])) .body(json!({ "query": { "multi_match": { "query": query, "fields": ["title^2", "author"] } } })) .send() .await?; let response_body = response.json::().await?; let hits = response_body["hits"]["hits"] .as_array() .unwrap_or(&vec![]); let books: Vec = hits .iter() .filter_map(|hit| { let source = hit["_source"].clone(); serde_json::from_value(source).ok() }) .collect(); Ok(books)} Bulk Operations for Mass Loading
Efficient loading of thousands of documents:
use elasticsear