Geodatenunterstützung in ElasticSearch

1. Einleitung

Elasticsearch ist am besten für seine Volltextsuchfunktionen bekannt, bietet jedoch auch vollständige Unterstützung für die Geodaten.

Weitere Informationen zum Einrichten von Elasticsearch und zu den ersten Schritten finden Sie in diesem vorherigen Artikel.

Lassen Sie uns einen Blick darauf werfen, wie wir Geodaten in Elasticsearch speichern und wie wir diese Daten mithilfe von Geoabfragen durchsuchen können.

2. Geodatentyp

Um Geo-Abfragen zu aktivieren, müssen wir die Zuordnung des Index manuell erstellen und die Feldzuordnung explizit festlegen.

Die dynamische Zuordnung funktioniert beim Festlegen der Zuordnung für Geotypen nicht.

Elasticsearch bietet zwei Möglichkeiten zur Darstellung von Geodaten:

  1. Breiten- und Längengrade unter Verwendung des Geopunktfeldtyps
  2. Komplexe Form, die in GeoJSON mithilfe des Geo-Form- Feldtyps definiert wurde

Schauen wir uns die oben genannten Kategorien genauer an:

2.1. Geopunktdatentyp

Der Geopunktfeldtyp akzeptiert Breiten- und Längengrade, die verwendet werden können, um:

  • Finden Sie Punkte in einem bestimmten Abstand vom Mittelpunkt
  • Suchen Sie Punkte in einem Feld oder einem Polygon
  • Aggregieren Sie Dokumente geografisch oder nach Entfernung vom Mittelpunkt
  • Dokumente nach Entfernung sortieren

Unten finden Sie eine Beispielzuordnung für das Feld zum Speichern von Geopunktdaten:

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

Wie wir aus obigem Beispiel sehen Typ für Standort - Feld ist geo_point . Somit können wir jetzt ein Längen- und Breitengradpaar an der Position im Standortfeld bereitstellen .

2.2. Geoform-Datentyp

Im Gegensatz zu Geo-Punkt , geo Form bietet die Funktionalität zu speichern und komplexe Formen wie Polygon und Rechteck zu suchen. Der Datentyp "Geoform" muss verwendet werden, wenn Dokumente durchsucht werden sollen, die andere Formen als Geopunkte enthalten.

Werfen wir einen Blick auf die Zuordnung für den Geoform-Datentyp:

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

Neuere Versionen von Elasticsearch zerlegen die bereitgestellte Geoform in ein dreieckiges Netz . Laut offizieller Dokumentation bietet dies eine nahezu perfekte räumliche Auflösung.

3. Verschiedene Möglichkeiten zum Speichern von Geopunktdaten

3.1. Latitude Longitude-Objekt

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

Hier Geo-Punkt - Position als ein Objekt mit gespeicherten Breitengrad und Längengrad als Schlüssel.

3.2. Latitude Longitude Pair

{ "location": "23.02,72.57" }

Hier wird die Position als Breiten- und Längengradpaar in einem einfachen Zeichenfolgenformat ausgedrückt. Bitte beachten Sie die Reihenfolge von Längen- und Breitengrad im String-Format.

3.3. Geo Hash

{ "location": "tsj4bys" }

Wir können auch Geopunktdaten in Form von Geo-Hash bereitstellen, wie im obigen Beispiel gezeigt. Wir können das Online-Tool verwenden, um Längen- und Breitengrade in Geo-Hash umzuwandeln.

3.4. Longitude Latitude Array

{ "location": [72.57, 23.02] }

Die Reihenfolge von Längen- und Breitengrad wird umgekehrt, wenn Breiten- und Längengrad als Array angegeben werden. Ursprünglich wurde das Längen- und Breitengradpaar sowohl in einer Zeichenfolge als auch in einem Array verwendet, später jedoch umgekehrt, um dem von GeoJSON verwendeten Format zu entsprechen.

4. Verschiedene Möglichkeiten zum Speichern von Geoformdaten

4.1. Punkt

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

Hier ist der Geoformformtyp, den wir einfügen möchten, ein Punkt . Bitte einen Blick auf die nehmen Lage Bereich haben wir ein verschachteltes Objekt , bestehend aus Feldern Typ und Koordinaten . Diese Metafelder helfen Elasticsearch bei der Identifizierung der Geoform und ihrer tatsächlichen Daten.

4.2. LineString

POST /index/type { "location" : { "type" : "linestring", "coordinates" : [[77.57, 23.02], [77.59, 23.05]] } }

Hier fügen wir eine lineare Geoform ein . Die Koordinaten für den Linestring bestehen aus zwei Punkten, dh Start- und Endpunkt. Die LineString-Geoform ist für Anwendungsfälle der Navigation sehr hilfreich.

4.3. Polygon

POST /index/type { "location" : { "type" : "polygon", "coordinates" : [ [ [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 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:

 org.locationtech.spatial4j spatial4j 0.7   com.vividsolutions jts 1.13   xerces xercesImpl   

We can search for the above dependencies in 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 a sample query to fetch all documents that fall within given top-left and bottom-right coordinates:

{ "query":{ "bool": { "must": { "match_all": {} }, "filter": { "geo_shape": { "region": { "shape": { "type": "envelope", "coordinates" : [[75.00, 25.0], [80.1, 30.2]] }, "relation": "within" } } } } } }

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:

Coordinate topLeft = new Coordinate(74, 31.2); Coordinate bottomRight = new Coordinate(81.1, 24); GeoShapeQueryBuilder qb = QueryBuilders.geoShapeQuery("region", new EnvelopeBuilder(topLeft, bottomRight).buildGeometry()); qb.relation(ShapeRelation.INTERSECTS);

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:

{ "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:

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

Geo Bounding Box query supports similar formats as we have in geo_point data type. Sample queries for supported formats can be found on the 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:

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

And here's the Java code for above query:

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 official site.

5.4. Geo Polygon Query

Eine Abfrage zum Filtern aller Datensätze mit Punkten, die in das angegebene Punktepolygon fallen.

Lassen Sie uns einen kurzen Blick auf eine Beispielabfrage werfen:

{ "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} ] } } } } } }

Und beim Java-Code für diese Abfrage:

List allPoints = new ArrayList(); allPoints.add(new GeoPoint(22.733, 68.859)); allPoints.add(new GeoPoint(24.733, 68.859)); allPoints.add(new GeoPoint(23, 70.859)); QueryBuilders.geoPolygonQuery("location", allPoints);

Geo Polygon Query unterstützt auch die unten genannten Formate:

  • lat-long als Array: [lon, lat]
  • lat-lang wie eine Schnur: "lat, lon"
  • Geo-Hash

Der Datentyp geo_point ist obligatorisch, um diese Abfrage verwenden zu können.

6. Fazit

In diesem Artikel haben wir verschiedene Zuordnungsoptionen für die Indizierung von Geodaten erläutert, z . B. geo_point und geo_shape .

Wir haben auch verschiedene Methoden zum Speichern von Geodaten durchlaufen und schließlich Geoabfragen und die Java-API beobachtet, um Ergebnisse mithilfe von Geoabfragen zu filtern.

Wie immer ist der Code in diesem GitHub-Projekt verfügbar.