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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
use crate::search::*;
use crate::util::*;
/// Returns parent documents whose joined child documents match a provided query. You can create
/// parent-child relationships between documents in the same index using a join field mapping.
///
/// To create has_child query:
/// ```
/// # use elasticsearch_dsl::queries::*;
/// # use elasticsearch_dsl::queries::params::*;
/// # let query =
/// Query::has_child("child", Query::term("tag", "elasticsearch"));
/// ```
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html>
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(remote = "Self")]
pub struct HasChildQuery {
r#type: String,
query: Box<Query>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
ignore_unmapped: Option<bool>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
max_children: Option<u32>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
min_children: Option<u32>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
score_mode: Option<HasChildScoreMode>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
inner_hits: Option<Box<InnerHits>>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
boost: Option<f32>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
_name: Option<String>,
}
impl Query {
/// Creates an instance of [`HasChildQuery`]
///
/// - `type` - Name of the child relationship mapped for the join field.
/// - `query` - Query you wish to run on child documents of the `type` field. If a child
/// document matches the search, the query returns the parent document.
pub fn has_child<T, U>(r#type: T, query: U) -> HasChildQuery
where
T: ToString,
U: Into<Query>,
{
HasChildQuery {
r#type: r#type.to_string(),
query: Box::new(query.into()),
ignore_unmapped: None,
max_children: None,
min_children: None,
score_mode: None,
inner_hits: None,
boost: None,
_name: None,
}
}
}
impl HasChildQuery {
/// Indicates whether to ignore an unmapped `type` and not return any documents instead of an
/// error. Defaults to `false`.
///
/// If `false`, Elasticsearch returns an error if the `type` is unmapped.
///
/// You can use this parameter to query multiple indices that may not contain the `type`.
pub fn ignore_unmapped(mut self, ignore_unmapped: bool) -> Self {
self.ignore_unmapped = Some(ignore_unmapped);
self
}
/// Maximum number of child documents that match the `query` allowed for a returned parent
/// document. If the parent document exceeds this limit, it is excluded from the search results.
pub fn max_children(mut self, max_children: u32) -> Self {
self.max_children = Some(max_children);
self
}
/// Minimum number of child documents that match the `query` required to match the query for a
/// returned parent document. If the parent document does not meet this limit, it is excluded
/// from the search results.
pub fn min_children(mut self, min_children: u32) -> Self {
self.min_children = Some(min_children);
self
}
/// Indicates how scores for matching child documents affect the root parent document’s
/// relevance score.
pub fn score_mode(mut self, score_mode: HasChildScoreMode) -> Self {
self.score_mode = Some(score_mode);
self
}
/// The [parent-join](https://www.elastic.co/guide/en/elasticsearch/reference/current/parent-join.html)
/// and [nested](https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html)
/// features allow the return of documents that have matches in a different scope. In the
/// parent/child case, parent documents are returned based on matches in child documents or
/// child documents are returned based on matches in parent documents. In the nested case,
/// documents are returned based on matches in nested inner objects.
///
/// In both cases, the actual matches in the different scopes that caused a document to be
/// returned are hidden. In many cases, it’s very useful to know which inner nested objects
/// (in the case of nested) or children/parent documents (in the case of parent/child) caused
/// certain information to be returned. The inner hits feature can be used for this. This
/// feature returns per search hit in the search response additional nested hits that caused a
/// search hit to match in a different scope.
///
/// Inner hits can be used by defining an `inner_hits` definition on a `nested`, `has_child`
/// or `has_parent` query and filter.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/inner-hits.html>
pub fn inner_hits(mut self, inner_hits: InnerHits) -> Self {
self.inner_hits = Some(Box::new(inner_hits));
self
}
add_boost_and_name!();
}
impl ShouldSkip for HasChildQuery {
fn should_skip(&self) -> bool {
self.r#type.should_skip() || self.query.should_skip()
}
}
serialize_with_root!("has_child": HasChildQuery);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialization() {
assert_serialize_query(
Query::has_child("child", Query::term("tag", "elasticsearch")),
json!({
"has_child": {
"type": "child",
"query": {
"term": {
"tag": {
"value": "elasticsearch"
}
}
}
}
}),
);
assert_serialize_query(
Query::has_child("child", Query::term("tag", "elasticsearch"))
.boost(2)
.name("test")
.ignore_unmapped(true)
.max_children(3)
.min_children(2)
.inner_hits(InnerHits::new())
.score_mode(HasChildScoreMode::Max),
json!({
"has_child": {
"type": "child",
"ignore_unmapped": true,
"max_children": 3,
"min_children": 2,
"score_mode": "max",
"query": {
"term": {
"tag": {
"value": "elasticsearch"
}
}
},
"inner_hits": {},
"boost": 2.0,
"_name": "test"
}
}),
);
}
}