Support géospatial dans ElasticSearch

Support géospatial dans ElasticSearch

1. introduction

Elasticsearch est mieux connu pour ses capacités de recherche en texte intégral, mais il offre également une prise en charge géospatiale complète.

Nous pouvons en savoir plus sur la configuration d'Elasticsearch et la mise en route dans ceprevious article.

Voyons comment nous pouvons enregistrer des données géographiques dans Elasticsearch et comment nous pouvons rechercher ces données à l'aide de requêtes géographiques.

2. Type de données géographiques

Pour activer les requêtes géographiques, nous devons créer le mappage de l'index manuellement et définir explicitement le mappage du champ.

Le mappage dynamique ne fonctionnera pas lors de la configuration du mappage pour les types géographiques.

Elasticsearch propose deux manières de représenter des géodonnées:

  1. Couples latitude-longitude utilisant un type de champ de point géographique

  2. Forme complexe définie enGeoJSON à l'aide du type de champ Geo-shape

Examinons plus en détail chacune des catégories ci-dessus:

2.1. Type de données Geo Point

Le type de champ de point géographique accepte des paires latitude-longitude qui peuvent être utilisées pour:

  • Trouver des points à une certaine distance du point central

  • Trouver des points dans une boîte ou un polygone

  • Regroupez les documents géographiquement ou par rapport au point central

  • Trier les documents par distance

Vous trouverez ci-dessous un exemple de mappage pour le champ afin de sauvegarder des données de point géographique:

PUT /index_name
{
    "mappings": {
        "TYPE_NAME": {
            "properties": {
                "location": {
                    "type": "geo_point"
                }
            }
        }
    }
}

Comme nous pouvons le voir dans l'exemple ci-dessus,type pour le champlocation estgeo_point. Ainsi, nous pouvons maintenant fournir la paire latitude-longitude dans leslocation dans le champ de localisation.

2.2. Type de données Geo Shape

Contrairement àgeo-point,geo shape fournit la fonctionnalité pour enregistrer et rechercher des formes complexes comme le polygone et le rectangle. Le type de donnéesGeo shape doit être utilisé lorsque nous voulons rechercher des documents contenant des formes autres que des points géographiques.

Jetons un coup d’œil à la cartographie pour le type de données de forme géographique:

PUT /index_name
{
    "mappings": {
        "TYPE_NAME": {
            "properties": {
                "location": {
                    "type": "geo_shape",
                    "tree": "quadtree",
                    "precision": "1m"
                }
            }
        }
    }
}

Le mappage ci-dessus indexera le champ de localisation avec l'implémentation dequadtree avec une précision d'un mètre.

Elasticsearch breaks down the provided geo shape into series of geo hashes consisting of small grid-like squares called raster.

En fonction de nos besoins, nous pouvons contrôler l'indexation des champsgeo shape. Par exemple, lorsque nous recherchons des documents pour la navigation, une précision jusqu'à un mètre devient très critique car elle peut conduire à un chemin incorrect.

Alors que si nous recherchons des sites touristiques, une précision allant jusqu'à 10 à 50 mètres peut être acceptable.

Une chose que nous devons garder à l'esprit lors de l'indexation des données degeo shape est que nous compromettons toujours les performances avec la précision. Avec une précision supérieure, Elasticsearch génère plus de termes, ce qui entraîne une utilisation accrue de la mémoire. Par conséquent, nous devons être très prudents lors de la sélection de la cartographie pour la forme géographique.

Nous pouvons trouver plus d'options de mappage pour le type de donnéesgeo-shape dans lesES site officiels.

3. Différentes façons d'enregistrer des données de point géographique

3.1. Objet Latitude Longitude

PUT index_name/index_type/1
{
    "location": {
        "lat": 23.02,
        "lon": 72.57
    }
}

Ici, le point géographiquelocation est enregistré en tant qu'objet aveclatitude etlongitude comme clés.

3.2. Paire de latitude longitude

{
    "location": "23.02,72.57"
}

Ici,location est exprimé sous la forme d'une paire latitude-longitude dans un format de chaîne simple. Veuillez noter la séquence de latitude et de longitude en format chaîne.

3.3. Geo Hash

{
    "location": "tsj4bys"
}

Nous pouvons également fournir des données de point géographique sous la forme de hachage géographique, comme indiqué dans l'exemple ci-dessus. Nous pouvons utiliser lesonline tool pour convertir la latitude-longitude en hachage géographique.

3.4. Tableau de latitude longitude

{
    "location": [72.57, 23.02]
}

La séquence latitude-longitude est inversée lorsque la latitude et la longitude sont fournies sous forme de tableau. Initialement, la paire latitude-longitude était utilisée à la fois dans la chaîne et dans un tableau, mais plus tard, elle a été inversée afin de correspondre au format utilisé parGeoJSON.

4. Différentes façons d'enregistrer des données de forme géographique

4.1. Point

POST /index/type
{
    "location" : {
        "type" : "point",
        "coordinates" : [72.57, 23.02]
    }
}

Ici, le type de forme géographique que nous essayons d'insérer est unpoint. Veuillez jeter un œil au champlocation, nous avons un objet imbriqué composé des champstype etcoordinates. Ces méta-champs aident Elasticsearch à identifier la forme géographique et ses données réelles.

4.2. LineString

POST /index/type
{
    "location" : {
        "type" : "linestring",
        "coordinates" : [[Here, we're inserting _linestring_ geo shape. The coordinates for _linestring_ consists of two points i.e. start and endpoint. _LineString_ geo shape is very helpful for navigation use case.

=== *4.3. _Polygon_*

[source,java,gutter:,true]

POST / index / type {"location": {"type": "polygone", "coordonnées": [[10.0, 0.0], [11.0, 0.0], [11.0, 1.0], [10.0, 1.0], [ 10.0, 0.0]]]}}

Here, we're inserting _polygon_ geo shape. Please take a look at the _coordinates_ in above example, _first_ and _last_ coordinates in polygon should always match i.e a closed polygon.

*Elasticsearch also supports other GeoJSON structures as well. A complete list of other supported formats is as below:*

* *_MultiPoint_*
* *_MultiLineString_*
* *_MultiPolygon_*
* *_GeometryCollection_*
* *_Envelope_*
* *_Circle_*

We can find examples of above-supported formats on the official https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html#input-structure[ES site].

For all structures, the inner _type_ and _coordinates_ are mandatory fields. Also, sorting and retrieving geo shape fields are currently not possible in Elasticsearch due to their complex structure. Thus, the only way to retrieve geo fields is from the source field.

== *5. ElasticSearch Geo Query*

Now, that we know how to insert documents containing geo shapes, let's dive into fetching those records using geo shape queries. But before we start using Geo Queries, we'll need following maven dependencies to support Java API for Geo Queries:

[source,java,gutter:,true]

org.locationtech.spatial4j spatial4j 0.7 com.vividsolutions < artifactId> jts 1.13 xerces xercesImpl

We can search for above dependencies in https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.locationtech.spatial4j%22%20AND%20a%3A%22spatial4j%22[Maven Central repository] as well.

Elasticsearch supports different types of geo queries and they are as follow:

=== *5.1. Geo Shape Query*

This requires the _geo_shape_ mapping.

Similar to _geo_shape_ type, _geo_shape_ uses GeoJSON structure to query documents.

Below is sample query to fetch all documents that fall _within_ given top-left and bottom-right coordinates:

[source,java,gutter:,true]

{"query": {"bool": {"must": {"match_all": {}}, "filter": {"geo_shape": {"region": {"shape": {"type": "enveloppe "," coordonnées ": [[relation": "dans"}}}}}}

Here, _relation_ determines *spatial relation operators* used at search time.

Below is the list of supported operators:

* *_INTERSECTS_* – (default) returns all documents whose _geo_shape_ field intersects the query geometry
* *_DISJOINT_* – retrieves all documents whose _geo_shape_ field has nothing in common with the query geometry
* *_WITHIN_* – gets all documents whose _geo_shape_ field is within the query geometry
* *_CONTAINS_* – returns all documents whose _geo_shape_ field contains the query geometry

Similarly, we can query using different GeoJSON shapes.

Java code for above query is as below:

[source,java,gutter:,true]

QueryBuilders .geoShapeQuery ("région", ShapeBuilders.newEnvelope (nouvelle coordonnée (75.00, 25.0), nouvelle coordonnée (80.1, 30.2))) .relation (ShapeRelation.WITHIN);

=== *5.2. Geo Bounding Box Query*

Geo Bounding Box query is used to fetch all the documents based on point location. Below is a sample bounding box query:

[source,java,gutter:,true]

{"query": {"bool": {"must": {"match_all": {}}, "filter": {"geo_bounding_box": {"location": {"bottom_left": [28.3, 30.5], " top_right ": [31.8, 32.12]}}}}}}

Java code for above bounding box query is as below:

[source,java,gutter:,true]

QueryBuilders .geoBoundingBoxQuery ("location"). SetCorners (31.8, 30.5, 28.3, 32.12);

Geo Bounding Box query supports similar formats like we have in _geo_point_ data type. Sample queries for supported formats can be found on the https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-bounding-box-query.html#_accepted_formats[official site].

=== *5.3. Geo Distance Query*

Geo distance query is used to filter all documents that come with the specified range of the point.

Here's a sample _geo_distance_ query:

[source,java,gutter:,true]

{"query": {"bool": {"must": {"match_all": {}}, "filter": {"geo_distance": {"distance": "10 milles", "localisation": [31.131,29.976 ]}}}}}

And here's the Java code for above query:

[source,java,gutter:,true]

QueryBuilders .geoDistanceQuery ("location") .point (29.976, 31.131) .distance (10, DistanceUnit.MILES);

Similar to _geo_point,_ geo distance query also supports multiple formats for passing location coordinates. More details on supported formats can be found at the https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-query.html#_accepted_formats_2[official site].

=== *5.4. Geo _Polygon_ Query*

A query to filter all records that have points that fall within the given polygon of points.

Let's have a quick look at a sample query:

[source,java,gutter:,true]

{"query": {"bool": {"must": {"match_all": {}}, "filter": {"geo_polygon": {"location": {"points": [{"lat": 22.733 , "lon": 68,859}, {"lat": 24,733, "lon": 68,859}, {"lat": 23, "lon": 70,859}]}}}}}}

And at the Java code for this query:

[source,java,gutter:,true]

List allPoints = new ArrayList (); allPoints.add (nouveau GeoPoint (22.733, 68.859)); allPoints.add (nouveau GeoPoint (24.733, 68.859)); allPoints.add (nouveau GeoPoint (23, 70.859));

QueryBuilders.geoPolygonQuery("location", allPoints);

Geo Polygon Query also supports formats mentioned below:

* lat-long as an array: [lon, lat]
* lat-long as a string: “lat, lon”
* geo hash

_geo_point_ data type is mandatory in order to use this query.

== *6. Conclusion*

In this article, we discussed different mapping options for indexing geo data i.e _geo_point_ and _geo_shape_.

We also went through different ways to store _geo-data_ and finally, we observed geo-queries and Java API to filter results using geo queries.

As always, the code is available https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-elasticsearch[in this GitHub project].