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
use crate::search::*;
use crate::util::*;
/// Matches [geo_point](https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html)
/// and [geo_shape](https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html)
/// values within a given distance of a geopoint.
///
/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-query.html>
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(remote = "Self")]
pub struct GeoDistanceQuery {
#[serde(skip)]
field: String,
#[serde(skip)]
location: GeoLocation,
distance: Distance,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
distance_type: Option<GeoDistanceType>,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
validation_method: Option<ValidationMethod>,
#[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 [`GeoDistanceQuery`]
///
/// - `field` - Field you wish to search
/// - `origin` - GeoPoint to measure distance to
/// - `distance` - Distance threshold
pub fn geo_distance<T, U, V>(field: T, origin: U, distance: V) -> GeoDistanceQuery
where
T: ToString,
U: Into<GeoLocation>,
V: Into<Distance>,
{
GeoDistanceQuery {
field: field.to_string(),
location: origin.into(),
distance: distance.into(),
distance_type: None,
validation_method: None,
boost: None,
_name: None,
}
}
}
impl GeoDistanceQuery {
/// Set to `IGNORE_MALFORMED` to accept geo points with invalid latitude or longitude, set to
/// `COERCE` to also try to infer correct latitude or longitude. (default is `STRICT`).
pub fn validation_method(mut self, validation_method: ValidationMethod) -> Self {
self.validation_method = Some(validation_method);
self
}
/// How to compute the distance. Can either be [Arc](GeoDistanceType::Arc) (default), or
/// [Plane](GeoDistanceType::Plane) (faster, but inaccurate on long distances and close to the
/// poles).
pub fn distance_type(mut self, distance_type: GeoDistanceType) -> Self {
self.distance_type = Some(distance_type);
self
}
add_boost_and_name!();
}
impl ShouldSkip for GeoDistanceQuery {}
serialize_with_root_key_value_pair!("geo_distance": GeoDistanceQuery, field, location);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialization() {
assert_serialize_query(
Query::geo_distance(
"pin.location",
GeoLocation::new(40.12, -71.34),
Distance::Kilometers(300),
),
json!({
"geo_distance": {
"distance": "300km",
"pin.location": [-71.34, 40.12],
}
}),
);
assert_serialize_query(
Query::geo_distance(
"pin.location",
GeoLocation::new(40.12, -71.34),
Distance::Kilometers(300),
)
.distance_type(GeoDistanceType::Plane)
.validation_method(ValidationMethod::Strict)
.name("test_name")
.boost(1),
json!({
"geo_distance": {
"distance": "300km",
"distance_type": "plane",
"pin.location": [-71.34, 40.12],
"validation_method": "STRICT",
"_name": "test_name",
"boost": 1.0,
}
}),
);
}
}