Elasticsearch клиент для Rust: обзор библиотеки elasticsearch-rs

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Elasticsearch клиент для Rust: elasticsearch-rs

Elasticsearch — мощная распределённая поисковая и аналитическая система, построенная на Apache Lucene. Для взаимодействия с ней из приложений на Rust существует официальный клиент — elasticsearch-rs. Эта библиотека предоставляет полный набор инструментов для работы с REST API Elasticsearch, включая индексацию, поиск, агрегации и управление кластером. В этой статье мы подробно разберём установку, настройку и основные возможности elasticsearch-rs с примерами кода.

Что такое elasticsearch-rs?

elasticsearch-rs — это официальный асинхронный клиент Elasticsearch для языка Rust, разрабатываемый компанией Elastic. Он основан на популярной библиотеке асинхронного HTTP-клиента reqwest и предоставляет типобезопасный API для всех эндпоинтов Elasticsearch. Основные преимущества:

  • Полная поддержка Elasticsearch 7.x и 8.x — все основные операции: CRUD, поиск, агрегации, управление индексами.
  • Асинхронность — использует async/await, что позволяет эффективно обрабатывать множество запросов.
  • Типобезопасность — структуры запросов и ответов строго типизированы, что снижает количество ошибок времени выполнения.
  • Автоматическая сериализация/десериализация — через serde и serde_json.
  • Поддержка аутентификации — Basic Auth, API ключи, SSL/TLS.

Установка

Добавьте зависимость в Cargo.toml:

[dependencies]
elasticsearch = "8.14.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }

Базовое подключение

Создадим клиент, подключающийся к локальному экземпляру 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);
    // Проверка соединения
    let response = client.ping().send().await?;
    println!("Elasticsearch доступен: {}", response.status_code());
    Ok(())
}

Основные операции: CRUD

1. Индексация документа

Добавим документ с информацией о книге в индекс books:

#[derive(Serialize, Deserialize, Debug)]
struct Book {
    title: String,
    author: String,
    year: u16,
    isbn: String,
}

let book = Book {
    title: "Rust в действии".into(),
    author: "Тим Макнамара".into(),
    year: 2023,
    isbn: "978-5-4461-2345-6".into(),
};

let response = client
    .index(IndexParts::IndexId("books", "1"))
    .body(json!(book))
    .send()
    .await?;

println!("Документ проиндексирован: {:?}", response.body());

2. Получение документа

let response = client
    .get(GetParts::IndexId("books", "1"))
    .send()
    .await?;

if response.status_code().is_success() {
    let book: Book = response.json().await?;
    println!("Найден документ: {:?}", book);
}

3. Обновление документа

let response = client
    .update(UpdateParts::IndexId("books", "1"))
    .body(json!({
        "doc": { "year": 2024 }
    }))
    .send()
    .await?;

println!("Обновлён: {:?}", response.body());

4. Удаление документа

let response = client
    .delete(DeleteParts::IndexId("books", "1"))
    .send()
    .await?;

println!("Удалён: {:?}", response.body());

Поиск с использованием Query DSL

Выполним полнотекстовый поиск по полю title:

use elasticsearch::SearchParts;

let response = client
    .search(SearchParts::Index(&["books"]))
    .body(json!({
        "query": {
            "match": {
                "title": "Rust"
            }
        }
    }))
    .send()
    .await?;

let body = response.json::<serde_json::Value>().await?;
let hits = body["hits"]["hits"].as_array().unwrap();

for hit in hits {
    let source = &hit["_source"];
    println!("Найдена книга: {}", source["title"]);
}

Агрегации

Рекомендаций