elasticsearch-dsl-rs

A strongly typed Rust DSL that maps one-to-one with the official Elasticsearch query language.

Library
Cargo
v0.4.26
214stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
49/100Fair
Development Activity44
Maintenance12
Community64
Maturity56
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
85/100Excellent
Architecture85
Code Quality90
Innovation80
Learning Curve85

elasticsearch-dsl is a Rust crate that gives you a strongly typed builder API for the Elasticsearch query DSL, covering queries, aggregations, suggesters, sorting, highlighting, and response parsing. Instead of hand-assembling raw JSON request bodies and hoping the shape is right, you compose typed structs — Query::bool(), Query::term(), Aggregation::terms() — that serialize to the exact JSON Elasticsearch expects, with empty or default fields skipped automatically.

The crate deliberately has no dependency on any particular HTTP client or on elasticsearch-rs, so it can sit in front of whatever transport you already use to talk to your cluster. It also provides typed response structures (SearchResponse, HitsMetadata, Explanation, ShardFailure, and friends) so parsing results is as strongly typed as building the request. Maintained by Vinted’s search platform team and used in production to build search functionality at scale.

What You Get

  • Typed builders for the full range of Elasticsearch query types — compound (bool, boosting, dis_max), full-text (match, multi_match, query_string), term-level (term, terms, range, wildcard), geo, span, and specialized queries
  • Typed aggregation builders (terms, top_hits, and other bucket/metric aggregations) that nest freely to build multi-level aggregation trees
  • Typed response structures for parsing search responses, including hits, shard statistics, explanations, and suggest results
  • Suggesters, highlighting, sorting, collapsing, rescoring, and runtime mappings modeled as first-class typed builders rather than ad-hoc JSON
  • Automatic skipping of empty/default fields during serialization so generated request bodies stay minimal and valid
  • No dependency on elasticsearch-rs or any specific HTTP client — plug it in front of whatever transport you already use

Common Use Cases

  • Building complex, deeply nested Elasticsearch search queries in Rust without constructing raw JSON strings
  • Composing multi-level aggregation pipelines (e.g. terms aggregations nested under other terms aggregations with top_hits) with compiler-checked structure
  • Parsing and working with Elasticsearch search responses through typed structs instead of untyped JSON values
  • Adding search functionality to a Rust service that already owns its own HTTP client and only needs typed request/response modeling for Elasticsearch

Under The Hood

Architecture The crate is organized by concern rather than by feature: src/search holds request-building types split into queries (89 files covering every query family — compound, full_text, term_level, geo, joining, shape, span, specialized), aggregations, sort, highlight, suggesters, rescoring, collapse, runtime_mappings, and response (typed deserialization structs like SearchResponse, HitsMetadata, ShardFailure); src/analyze handles the analyze API separately; src/util centralizes cross-cutting serialization helpers (ShouldSkip, KeyValuePair, join_with_pipe). A shared macros.rs (add_boost_and_name!, add_aggregate!, serialize_with_root!) generates the repeated builder methods that nearly every query and aggregation type needs, keeping ~89 query implementations consistent without duplicating boilerplate by hand. Types commonly use #[serde(remote = "Self")] plus custom serialization to control exactly how optional fields collapse or omit themselves in the output JSON, matching Elasticsearch’s DSL shape precisely.

Tech Stack Rust (2018 edition), built on serde/serde_json (with the raw_value feature) for typed serialization, chrono for typed date/time fields, and num-traits for generic numeric boost handling. It has no async runtime and no HTTP client dependency by design — it is a pure request/response modeling layer meant to sit in front of whatever client the consumer already uses. A Cargo workspace bundles runnable examples (aggregations, boolean queries, completion suggesters, handling search responses) as workspace members, and cargo doc generates the published docs.rs reference.

Code Quality The project carries 117 files with inline #[test] blocks, colocating tests next to the implementation they cover, and uses pretty_assertions for readable test-failure diffs. CI (GitHub Actions) runs cargo check, cargo fmt --check, cargo clippy -D warnings, cargo nextest run, and cargo test --doc on every push and PR — meaning the doc-comment code examples embedded throughout the query types are compiled and executed as part of the test suite, not just illustrative prose. lib.rs sets a strict #![deny(...)] lint gate covering dead code, missing docs, and unused code, with RUSTFLAGS: -D warnings turning any warning into a CI failure.

API Design The builder API mirrors the official Elasticsearch query DSL field-for-field, so someone who knows the Elasticsearch JSON DSL can predict the Rust API almost exactly (Query::bool().must(...).filter(...).should(...)). Nearly every query and aggregation type exposes the same boost()/name() methods via the shared macros, giving a consistent, low-boilerplate surface across dozens of otherwise-distinct query types. Every public type carries doc comments — many with runnable, doctested usage examples — that also link back to the relevant Elasticsearch reference documentation page.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search