Elasticsearch клиент для Rust: официальная библиотека elasticsearch-rs

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

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

Начать курс

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

elasticsearch-rs — это официальный асинхронный клиент для взаимодействия с Elasticsearch из экосистемы Rust. Библиотека предоставляет полный набор инструментов для работы с поисковым движком: от простых CRUD операций до сложных агрегаций и bulk-запросов. Разрабатывается и поддерживается командой Elastic, что гарантирует актуальность API и совместимость с последними версиями Elasticsearch.

Ключевые возможности

  • Полная поддержка Elasticsearch API — индексация, поиск, агрегации, управление индексами, маппингом и настройками кластера.
  • Асинхронность — построена на базе tokio и reqwest, что позволяет обрабатывать тысячи запросов без блокировки потоков.
  • Типобезопасность — все запросы и ответы строго типизированы, ошибки валидации отлавливаются на этапе компиляции.
  • Поддержка bulk-операций — массовая загрузка и обновление документов с автоматической обработкой ошибок.
  • SSL/TLS и аутентификация — встроенная поддержка HTTPS, Basic Auth, API-ключей и токенов.
  • Сериализация через serde — документы автоматически преобразуются в/из JSON с помощью крейта serde.

Установка и настройка

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

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

Базовое подключение к локальному экземпляру Elasticsearch:

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

Работа с документами

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

Определим структуру для сериализации:

use serde::{Serialize, Deserialize};

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

Индексация нового документа:

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!("Документ проиндексирован: {:?}", response);
    Ok(())
}

Поиск по индексу

Пример полнотекстового поиска:

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-операции для массовой загрузки

Эффективная загрузка тысяч документов:

use elasticsearch::BulkParts;
use elasticsearch::http::request::BulkBody;

async fn bulk_index_books(client: &Elasticsearch, books: &[Book]) -> Result<(), Error> {
    let mut body: Vec> = Vec::new();
    
    for book in books {
        body.push(BulkBody::index(book));
    }
    
    let response = client
        .bulk(BulkParts::Index("books"))
        .body(body)
        .send()
        .await?;
    
    let response_body = response.json::().await?;
    if response_body["errors"].as_bool().unwrap_or(true) {
        eprintln!("Обнаружены ошибки при массовой загрузке");
    }
    
    Ok(())
}

Работа с агрегациями

Пример агрегации для получения статистики по авторам:

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