use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Serialize, Deserialize, Debug)] pub struct ApiRequest { pub method: String, pub path_and_query: String, pub body: Option<SearchBody>, } #[derive(Serialize, Deserialize, Debug, Default)] #[serde(deny_unknown_fields)] pub struct UrlQueryParams { #[serde(skip_serializing_if = "Option::is_none")] pub allow_no_indices: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub allow_partial_search_results: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub batched_reduce_size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub ccs_minimize_roundtrips: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub docvalue_fields: Option<String>, // array of strings, comma-separated #[serde(skip_serializing_if = "Option::is_none")] pub expand_wildcards: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub explain: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub from: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub ignore_throttled: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub ignore_unavailable: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub max_concurrent_shard_requests: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub pre_filter_shard_size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub preference: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub q: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub request_cache: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub rest_total_hits_as_int: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub routing: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub scroll: Option<String>, // string is "time value" #[serde(skip_serializing_if = "Option::is_none")] pub search_type: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub seq_no_primary_term: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub sort: Option<String>, // array of strings, comma-separated #[serde(skip_serializing_if = "Option::is_none")] pub _source: Option<bool>, // TODO: bool or string #[serde(skip_serializing_if = "Option::is_none")] pub _source_excludes: Option<String>, // array of strings, comma-separated #[serde(skip_serializing_if = "Option::is_none")] pub _source_includes: Option<String>, // array of strings, comma-separated #[serde(skip_serializing_if = "Option::is_none")] pub stats: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub stored_fields: Option<String>, // array of strings, comma-separated #[serde(skip_serializing_if = "Option::is_none")] pub suggest_field: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub suggest_text: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub terminate_after: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub timeout: Option<String>, // string is "time units" #[serde(skip_serializing_if = "Option::is_none")] pub track_scores: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub track_total_hits: Option<bool>, // XXX: bool or integer #[serde(skip_serializing_if = "Option::is_none")] pub typed_keys: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub version: Option<bool>, // additional generic params #[serde(skip_serializing_if = "Option::is_none")] pub human: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub pretty: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub filter_path: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub error_trace: Option<bool>, } // https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct SearchBody { #[serde(skip_serializing_if = "Option::is_none")] pub query: Option<ApiQuery>, #[serde(skip_serializing_if = "Option::is_none")] pub highlight: Option<ApiHighlight>, #[serde(skip_serializing_if = "Option::is_none")] pub collapse: Option<ApiCollapse>, #[serde(skip_serializing_if = "Option::is_none")] pub post_filter: Option<ApiQuery>, // TODO: leaf query only? #[serde(skip_serializing_if = "Option::is_none")] pub rescore: Option<ApiRescore>, // TODO: single or an array of rescore objects // script_fields disabled #[serde(skip_serializing_if = "Option::is_none")] pub aggs: Option<HashMap<String, ApiAggregation>>, #[serde(skip_serializing_if = "Option::is_none")] pub aggregations: Option<HashMap<String, ApiAggregation>>, // https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html #[serde(skip_serializing_if = "Option::is_none")] pub sort: Option<Vec<SortElement>>, #[serde(skip_serializing_if = "Option::is_none")] pub slice: Option<ApiSlice>, #[serde(skip_serializing_if = "Option::is_none")] pub stored_fields: Option<String>, // array of strings, or "_none_" // overlap with URL query parameters #[serde(skip_serializing_if = "Option::is_none")] pub docvalue_fields: Option<Vec<DocValOrString>>, #[serde(skip_serializing_if = "Option::is_none")] pub explain: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub from: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub min_score: Option<Num>, #[serde(skip_serializing_if = "Option::is_none")] pub seq_no_primary_term: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] pub size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub _source: Option<bool>, // XXX: bool, string, or object #[serde(skip_serializing_if = "Option::is_none")] pub terminate_after: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pub timeout: Option<String>, // string is "time units" } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ScrollBody { pub scroll_id: StringOrArray, #[serde(skip_serializing_if = "Option::is_none")] pub scroll: Option<String>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ApiSlice { id: u32, max: u32, #[serde(skip_serializing_if = "Option::is_none")] field: Option<String>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ApiRescore { #[serde(skip_serializing_if = "Option::is_none")] pub query: Option<ApiQuery>, #[serde(skip_serializing_if = "Option::is_none")] pub window_size: Option<u32>, } // TODO: could revert to having query types as an enum, with flattening #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ApiQuery { // compound queries #[serde(rename = "bool")] #[serde(skip_serializing_if = "Option::is_none")] bool_query: Option<BoolQuery>, #[serde(skip_serializing_if = "Option::is_none")] boosting: Option<BoostingQuery>, #[serde(skip_serializing_if = "Option::is_none")] constant_score: Option<ConstantScoreQuery>, // fulltext (leaf) queries #[serde(rename = "match")] #[serde(skip_serializing_if = "Option::is_none")] match_query: Option<HashMap<String, MatchQueryOrString>>, #[serde(skip_serializing_if = "Option::is_none")] match_phrase: Option<HashMap<String, QueryFieldOrString>>, #[serde(skip_serializing_if = "Option::is_none")] multi_match: Option<MultiMatchQuery>, #[serde(skip_serializing_if = "Option::is_none")] query_string: Option<QueryStringQuery>, #[serde(skip_serializing_if = "Option::is_none")] simple_query_string: Option<QueryStringQuery>, // term-level (leaf) queries #[serde(skip_serializing_if = "Option::is_none")] exists: Option<SimpleFieldOrString>, #[serde(skip_serializing_if = "Option::is_none")] match_all: Option<SimpleBoost>, #[serde(skip_serializing_if = "Option::is_none")] match_none: Option<SimpleBoost>, #[serde(skip_serializing_if = "Option::is_none")] ids: Option<IdsQuery>, #[serde(skip_serializing_if = "Option::is_none")] wildcard: Option<HashMap<String, TermQueryOrString>>, // also works for wildcard #[serde(skip_serializing_if = "Option::is_none")] prefix: Option<HashMap<String, TermQueryOrString>>, // also works for prefix query #[serde(skip_serializing_if = "Option::is_none")] range: Option<HashMap<String, RangeQuery>>, #[serde(skip_serializing_if = "Option::is_none")] term: Option<HashMap<String, TermQueryOrString>>, #[serde(skip_serializing_if = "Option::is_none")] // TODO: boost in terms query terms: Option<HashMap<String, Vec<String>>>, // other #[serde(skip_serializing_if = "Option::is_none")] nested: Option<NestedQuery>, #[serde(skip_serializing_if = "Option::is_none")] rescore_query: Option<Box<ApiQuery>>, // fields as part of a rescore query #[serde(skip_serializing_if = "Option::is_none")] score_mode: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] query_weight: Option<Num>, #[serde(skip_serializing_if = "Option::is_none")] rescore_query_weight: Option<Num>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ApiHighlight { // TODO: fields could also be an array of strings? fields: HashMap<String, HighlightField>, #[serde(flatten)] settings: HighlightField, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum SortMapValue { String(String), Object { order: String, #[serde(skip_serializing_if = "Option::is_none")] mode: Option<String>, }, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum SortElement { String(String), Object(HashMap<String, SortMapValue>), } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum DocValOrString { String(String), Object { field: String, #[serde(skip_serializing_if = "Option::is_none")] format: Option<String>, }, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum MatchQueryOrString { Object(MatchQuery), String(String), } // https://www.elastic.co/guide/en/elasticsearch/reference/7.9/query-dsl-match-query.html #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct MatchQuery { query: String, #[serde(flatten)] options: MatchOptions, } // https://www.elastic.co/guide/en/elasticsearch/reference/7.9/query-dsl-multi-match-query.html #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct MultiMatchQuery { query: String, fields: Vec<String>, #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "type")] query_type: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] tie_breaker: Option<Num>, #[serde(flatten)] options: MatchOptions, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct MatchOptions { #[serde(skip_serializing_if = "Option::is_none")] analyzer: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] auto_generate_synonyms_phrase_query: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] fuzziness: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] max_expansions: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] prefix_length: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] fuzzy_transpositions: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] fuzzy_rewrite: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] lenient: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] operator: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] minimum_should_match: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] zero_terms_query: Option<String>, } // https://www.elastic.co/guide/en/elasticsearch/reference/7.9/query-dsl-query-string-query.html #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct QueryStringQuery { query: String, #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "type")] query_type: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] default_field: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] allow_leading_wildcard: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] analyze_wildcard: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] analyzer: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] auto_generate_synonyms_phrase_query: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] boost: Option<Num>, #[serde(skip_serializing_if = "Option::is_none")] default_operator: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] enable_position_increments: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] fields: Option<Vec<String>>, #[serde(skip_serializing_if = "Option::is_none")] fuzziness: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] fuzzy_max_expansions: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] fuzzy_prefix_length: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] fuzzy_transpositions: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] lenient: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] max_determinized_states: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] minimum_should_match: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] quote_analyzer: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] phrase_slop: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] quote_field_suffix: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] rewrite: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] time_zone: Option<String>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct SimpleBoost { #[serde(skip_serializing_if = "Option::is_none")] boost: Option<Num>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct IdsQuery { values: Vec<String>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum TermQueryOrString { String(String), Object(TermQuery), } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct TermQuery { value: String, #[serde(skip_serializing_if = "Option::is_none")] rewrite: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] boost: Option<Num>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum StringOrNum { String(String), Int(u64), Float(f64), } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum Num { Int(u64), Float(f64), } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum StringOrArray { String(String), Array(Vec<String>), } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct RangeQuery { #[serde(skip_serializing_if = "Option::is_none")] gt: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] gte: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] lt: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] lte: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] format: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] relation: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] timezone: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] boost: Option<Num>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum QueryFieldOrString { Object(QueryField), String(String), } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct QueryField { query: String, #[serde(skip_serializing_if = "Option::is_none")] fuzziness: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] slop: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] boost: Option<Num>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct BoolQuery { #[serde(skip_serializing_if = "Option::is_none")] must: Option<Box<ApiQuery>>, #[serde(skip_serializing_if = "Option::is_none")] filter: Option<Box<ApiQuery>>, #[serde(skip_serializing_if = "Option::is_none")] should: Option<Box<ApiQuery>>, #[serde(skip_serializing_if = "Option::is_none")] must_not: Option<Box<ApiQuery>>, #[serde(skip_serializing_if = "Option::is_none")] minimum_should_match: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] boost: Option<Num>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct NestedQuery { path: String, query: Box<ApiQuery>, #[serde(skip_serializing_if = "Option::is_none")] score_mode: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] ignore_unmapped: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] inner_hits: Option<InnerHitsOneOrMore>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct BoostingQuery { positive: Box<ApiQuery>, negative: Box<ApiQuery>, negative_boost: Num, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ConstantScoreQuery { filter: Box<ApiQuery>, #[serde(skip_serializing_if = "Option::is_none")] boost: Option<Num>, } // https://www.elastic.co/guide/en/elasticsearch/reference/current/highlighting.html #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct HighlightField { #[serde(skip_serializing_if = "Option::is_none")] boundary_chars: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] boundary_max_scan: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] boundary_scanner: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] boundary_scanner_locale: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] encoder: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] force_source: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] fragmenter: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] fragment_offset: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] fragment_size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] highlight_query: Option<ApiQuery>, #[serde(skip_serializing_if = "Option::is_none")] matched_fields: Option<Vec<String>>, #[serde(skip_serializing_if = "Option::is_none")] no_match_size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] number_of_fragments: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] order: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] phrase_limit: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] pre_tags: Option<Vec<String>>, #[serde(skip_serializing_if = "Option::is_none")] post_tags: Option<Vec<String>>, #[serde(skip_serializing_if = "Option::is_none")] require_field_match: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] tags_schema: Option<String>, #[serde(rename = "type")] #[serde(skip_serializing_if = "Option::is_none")] highlight_type: Option<String>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum SimpleFieldOrString { String(String), Object { field: String }, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ApiCollapse { field: String, #[serde(skip_serializing_if = "Option::is_none")] inner_hits: Option<InnerHitsOneOrMore>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] #[serde(untagged)] pub enum InnerHitsOneOrMore { Single(InnerHits), Multiple(Vec<InnerHits>), } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct InnerHits { #[serde(skip_serializing_if = "Option::is_none")] from: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] sort: Option<Vec<SortElement>>, #[serde(skip_serializing_if = "Option::is_none")] name: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] collapse: Option<Box<ApiCollapse>>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct ApiAggregation { // bucket type aggregations #[serde(skip_serializing_if = "Option::is_none")] nested: Option<NestedAggregation>, #[serde(skip_serializing_if = "Option::is_none")] filter: Option<ApiQuery>, #[serde(skip_serializing_if = "Option::is_none")] histogram: Option<SimpleAggregation>, #[serde(skip_serializing_if = "Option::is_none")] terms: Option<TermsAggregation>, #[serde(skip_serializing_if = "Option::is_none")] significant_terms: Option<SimpleAggregation>, // metrics type aggregations #[serde(skip_serializing_if = "Option::is_none")] avg: Option<SimpleAggregation>, #[serde(skip_serializing_if = "Option::is_none")] min: Option<SimpleAggregation>, #[serde(skip_serializing_if = "Option::is_none")] max: Option<SimpleAggregation>, #[serde(skip_serializing_if = "Option::is_none")] sum: Option<SimpleAggregation>, #[serde(skip_serializing_if = "Option::is_none")] value_count: Option<SimpleAggregation>, #[serde(skip_serializing_if = "Option::is_none")] stats: Option<SimpleAggregation>, #[serde(skip_serializing_if = "Option::is_none")] percentiles: Option<SimpleAggregation>, // nested aggregations #[serde(skip_serializing_if = "Option::is_none")] aggs: Option<HashMap<String, Box<ApiAggregation>>>, #[serde(skip_serializing_if = "Option::is_none")] aggregations: Option<HashMap<String, Box<ApiAggregation>>>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct NestedAggregation { path: String, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct SimpleAggregation { field: String, #[serde(skip_serializing_if = "Option::is_none")] interval: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] missing: Option<StringOrNum>, #[serde(skip_serializing_if = "Option::is_none")] keyed: Option<bool>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct DateHistogramAggregation { field: String, #[serde(skip_serializing_if = "Option::is_none")] fixed_interval: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] calendar_interval: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] format: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] time_zone: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] offset: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] order: Option<HashMap<String, String>>, #[serde(skip_serializing_if = "Option::is_none")] keyed: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] missing: Option<StringOrNum>, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct TermsAggregation { field: String, #[serde(skip_serializing_if = "Option::is_none")] size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] shard_size: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] min_doc_count: Option<u32>, #[serde(skip_serializing_if = "Option::is_none")] show_term_doc_count_error: Option<bool>, #[serde(skip_serializing_if = "Option::is_none")] order: Option<HashMap<String, String>>, #[serde(skip_serializing_if = "Option::is_none")] include: Option<StringOrArray>, #[serde(skip_serializing_if = "Option::is_none")] exclude: Option<StringOrArray>, #[serde(skip_serializing_if = "Option::is_none")] execution_hint: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] missing: Option<StringOrNum>, }