1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! rustlavel-search: Elasticsearch and OpenSearch.
//!
//! **One package serves both.** OpenSearch was forked from Elasticsearch 7.10
//! and the two have not diverged on anything this crate touches: `_search`,
//! `_bulk`, `_doc`, `_mapping`, `_refresh` and `_cluster/health` take the same
//! bodies and answer with the same shapes on either. Nothing here prefers one.
//! [`ClusterInfo::distribution`] says which one answered, for the rare caller
//! that has to branch on it.
//!
//! There is no protocol to write here — the cluster speaks HTTP and JSON, and
//! the framework already has both. What this crate is actually for is the
//! things that go wrong:
//!
//! - **`_bulk` answers 200 when documents were lost.** Per-item failures live
//! in the body, and a caller that checks the status writes a loader that
//! silently drops rows. See [`BulkReport`].
//! - **The total on a search is a floor, not a count.** Counting stops at
//! 10,000 by default. See [`TotalHits`].
//! - **A search can succeed on some shards and fail on others**, answering 200
//! with fewer results and no other sign. See [`SearchResults::is_partial`].
//! - **A document is not searchable the moment it is written.** See
//! [`SearchClient::refresh`].
//! - **Failures need telling apart.** A rejected write is worth repeating; a
//! document that does not fit the mapping never is. See [`SearchError`].
//!
//! ```ignore
//! let client = SearchClient::new("http://localhost:9200").basic_auth("elastic", &password);
//!
//! client
//! .create_index_if_missing(
//! "posts",
//! &IndexDefinition::new()
//! .field("title", Field::text().with_keyword())
//! .field("tags", Field::keyword())
//! .field("views", Field::long())
//! .dynamic_strict(),
//! )
//! .await?;
//!
//! client.bulk("posts", &operations).await?.ok_or_error()?;
//! client.refresh("posts").await?;
//!
//! let results = client
//! .search(
//! "posts",
//! &Search::new()
//! .query(
//! Query::bool()
//! .must(Query::matching("title", "rust").and())
//! .filter(Query::range("views").gte(100)),
//! )
//! .aggregate("by_tag", Aggregation::terms("tags").size(10))
//! .track_total_hits(true),
//! )
//! .await?;
//!
//! println!("{} matches", results.total);
//! ```
//!
//! Tests need no cluster: [`SearchClient::faking`] is `Http::fake()`, and the
//! integration tests under `tests/` run against a real server only when
//! `ELASTICSEARCH_URL` is set.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
/// Everything an application normally needs, in one import.