Georuimtelijke ondersteuning in ElasticSearch

1.Invoering

Elasticsearch is vooral bekend om zijn volledige tekstzoekmogelijkheden, maar het biedt ook volledige georuimtelijke ondersteuning.

We kunnen meer vinden over het opzetten van Elasticsearch en aan de slag gaan in dit vorige artikel.

Laten we eens kijken hoe we geodata kunnen opslaan in Elasticsearch en hoe we die data kunnen doorzoeken met behulp van geoquery's.

2. Geo-gegevenstype

Om geo-queries mogelijk te maken, moeten we de toewijzing van de index handmatig maken en de veldtoewijzing expliciet instellen.

Dynamische toewijzing werkt niet bij het instellen van toewijzingen voor geotypen.

Elasticsearch biedt twee manieren om geodata weer te geven:

  1. Breedtegraad-lengtegraadparen met behulp van het veldtype geo-punt
  2. Complexe vorm gedefinieerd in GeoJSON met behulp van het veldtype geovorm

Laten we elk van de bovenstaande categorieën eens nader bekijken:

2.1. Geo-puntgegevenstype

Het veldtype geo-punt accepteert paren van breedtegraad en lengtegraad die kunnen worden gebruikt om:

  • Vind punten binnen een bepaalde afstand van het centrale punt
  • Vind punten in een kader of een veelhoek
  • Voeg documenten geografisch of op afstand van het centrale punt samen
  • Sorteer documenten op afstand

Hieronder ziet u een voorbeeldtoewijzing voor het veld om geo-puntgegevens op te slaan:

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

Zoals we kunnen zien in het bovenstaande voorbeeld, type voor plaats veld is geo_point . We kunnen nu dus een breedtegraad-lengtegraadpaar leveren in de plaats in het locatieveld.

2.2. Gegevenstype Geo Shape

in tegenstelling tot geo-punt, geovorm biedt de functionaliteit om complexe vormen zoals polygoon en rechthoek op te slaan en te doorzoeken. Geo-vorm het gegevenstype moet worden gebruikt als we documenten willen doorzoeken die andere vormen dan geografische punten bevatten.

Laten we eens kijken naar de toewijzing voor het gegevenstype geovorm:

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

Recente versies van Elasticsearch splitsen de verstrekte geografische vorm op in een driehoekig gaas. Volgens de officiële documentatie levert dit een bijna perfecte ruimtelijke resolutie op.

3. Verschillende manieren om geo-puntgegevens op te slaan

3.1. Breedtegraad Lengtegraad-object

PUT index_naam / index_type / 1 {"locatie": {"lat": 23.02, "lon": 72.57}}

Hier, geo-punt plaats wordt opgeslagen als een object met breedtegraad en Lengtegraad als sleutels.

3.2. Breedtegraad Lengtegraadpaar

{"location": "23.02,72.57"}

Hier, plaats wordt uitgedrukt als een breedtegraad-lengtegraadpaar in een gewone tekenreeksindeling. Let op: de volgorde van de lengte- en breedtegraad in tekenreeksindeling.

3.3. Geo-hash

{"location": "tsj4bys"}

We kunnen ook geo-puntgegevens leveren in de vorm van geo-hash, zoals weergegeven in het bovenstaande voorbeeld. We kunnen de online tool gebruiken om breedtegraad-lengtegraad om te zetten in geo-hash.

3.4. Lengtegraad Latitude Array

{"locatie": [72.57, 23.02]}

De volgorde van lengte- en breedtegraad wordt omgekeerd wanneer de lengte- en breedtegraad als een array worden aangeleverd. Aanvankelijk werd het latitude-longitude-paar gebruikt in zowel string als in een array, maar later werd het omgekeerd om overeen te komen met het formaat dat door GeoJSON wordt gebruikt.

4. Verschillende manieren om Geo Shape-gegevens op te slaan

4.1. Punt

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

Hier is het type geovorm dat we proberen in te voegen een punt. Neem een ​​kijkje op de plaats veld, hebben we een genest object dat uit velden bestaat type en coördinaten. Deze metavelden helpen Elasticsearch bij het identificeren van de geovorm en de feitelijke gegevens.

4.2. LineString

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

Hier voegen we in linestring geovorm. De coördinaten voor linestring bestaat uit twee punten, namelijk start- en eindpunt. LineString geovorm is erg handig voor gebruiksscenario's voor navigatie.

4.3. Veelhoek

POST / index / typ {"locatie": {"type": "polygoon", "coördinaten": [[[10,0, 0,0], [11,0, 0,0], [11,0, 1,0], [10,0, 1,0], [ 10,0, 0,0]]]}}

Hier voegen we in veelhoek geovorm. Kijk eens naar de coördinaten in bovenstaand voorbeeld, eerste en laatste coördinaten in polygoon moeten altijd overeenkomen, d.w.z. een gesloten polygoon.

Elasticsearch ondersteunt ook andere GeoJSON-structuren. Een volledige lijst met andere ondersteunde formaten is als volgt:

  • MultiPoint
  • MultiLineString
  • MultiPolygon
  • GeometryCollection
  • Envelop
  • Cirkel

We kunnen voorbeelden van hierboven ondersteunde formaten vinden op de officiële ES-site.

Voor alle structuren, het innerlijke type en coördinaten zijn verplichte velden. Ook is het sorteren en ophalen van velden met geovorm momenteel niet mogelijk in Elasticsearch vanwege hun complexe structuur. De enige manier om geografische velden op te halen, is dus vanuit het bronveld.

5. ElasticSearch Geo Query

Nu we weten hoe we documenten met geografische vormen moeten invoegen, gaan we die records ophalen met behulp van geo-vormquery's. Maar voordat we Geo Queries gaan gebruiken, hebben we de volgende maven-afhankelijkheden nodig om Java API voor Geo Queries te ondersteunen:

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

We kunnen ook zoeken naar de bovenstaande afhankelijkheden in de Maven Central-repository.

Elasticsearch ondersteunt verschillende soorten geoquery's en ze zijn als volgt:

5.1. Geo Shape Query

Dit vereist de geo_shape in kaart brengen.

Gelijkwaardig aan geo_shape type, geo_shape gebruikt GeoJSON-structuur om documenten op te vragen.

Hieronder ziet u een voorbeeldquery om alle documenten die vallen op te halen binnen gegeven coördinaten linksboven en rechtsonder:

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

Hier, relatie bepaalt operatoren voor ruimtelijke relaties gebruikt tijdens het zoeken.

Hieronder vindt u de lijst met ondersteunde operators:

  • INTERSECTEN - (standaard) retourneert alle documenten waarvan geo_shape veld snijdt de geometrie van de query
  • ONTREKKEN - haalt alle documenten op waarvan geo_shape veld heeft niets gemeen met de geometrie van de query
  • BINNEN - krijgt alle documenten waarvan geo_shape veld is binnen de geometrie van de query
  • BEVAT - geeft alle documenten terug waarvan geo_shape veld bevat de geometrie van de vraag

Evenzo kunnen we query's uitvoeren met behulp van verschillende GeoJSON-vormen.

Java-code voor bovenstaande zoekopdracht is als volgt:

Coördinaat topLeft = nieuwe coördinaat (74, 31.2); Coördinaat bottomRight = nieuwe coördinaat (81.1, 24); GeoShapeQueryBuilder qb = QueryBuilders.geoShapeQuery ("regio", nieuwe EnvelopeBuilder (topLeft, bottomRight) .buildGeometry ()); qb.relation (ShapeRelation.INTERSECTS);

5.2. Geo Bounding Box Query

Geo Bounding Box-query wordt gebruikt om alle documenten op te halen op basis van puntlocatie. Hieronder ziet u een voorbeeld van een selectiekaderquery:

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

Java-code voor bovenstaande bounding box-query is als volgt:

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

Geo Bounding Box-query ondersteunt vergelijkbare formaten als we hebben in geo_point data type. Voorbeeldvragen voor ondersteunde formaten zijn te vinden op de officiële site.

5.3. Geo-afstandsquery

Geo-afstandsquery wordt gebruikt om alle documenten te filteren die binnen het opgegeven bereik van het punt vallen.

Hier is een voorbeeld geo_distance vraag:

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

En hier is de Java-code voor bovenstaande vraag:

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

Gelijkwaardig aan geo_point, Geo-afstandsquery ondersteunt ook meerdere formaten voor het doorgeven van locatiecoördinaten. Meer details over ondersteunde formaten zijn te vinden op de officiële site.

5.4. Geo Veelhoek Vraag

Een query om alle records te filteren die punten hebben die binnen de gegeven polygoon van punten vallen.

Laten we even een voorbeeldquery bekijken:

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

En bij de Java-code voor deze vraag:

Lijst allPoints = nieuwe ArrayList (); allPoints.add (nieuwe GeoPoint (22.733, 68.859)); allPoints.add (nieuwe GeoPoint (24.733, 68.859)); allPoints.add (nieuwe GeoPoint (23, 70.859)); QueryBuilders.geoPolygonQuery ("locatie", allPoints);

Geo Polygon Query ondersteunt ook onderstaande formaten:

  • lat-long als een array: [lon, lat]
  • lat-long als een string: "lat, lon"
  • geo hash

geo_point datatype is verplicht om deze query te gebruiken.

6. Conclusie

In dit artikel hebben we verschillende toewijzingsopties besproken voor het indexeren van geografische gegevens, d.w.z. geo_point en geo_shape.

We hebben ook verschillende manieren doorlopen om op te slaan geo-data en tot slot hebben we geo-queries en Java API geobserveerd om resultaten te filteren met behulp van geografische queries.

Zoals altijd is de code beschikbaar in dit GitHub-project.