Geospatial support i MongoDB

1. Oversigt

I denne vejledning udforsker vi geospatial support i MongoDB.

Vi diskuterer, hvordan du gemmer geospatiale data, geoindeksering og geospatial søgning. Vi bruger også flere geospatiale søgeforespørgsler som f.eks nær ved, geoWithinog geoIntersects.

2. Lagring af geospatiale data

Lad os først se, hvordan du gemmer geospatiale data i MongoDB.

MongoDB understøtter flere GeoJSON typer til lagring af geospatiale data. I vores eksempler bruger vi hovedsageligt Punkt og Polygon typer.

2.1. Punkt

Dette er det mest basale og almindelige GeoJSON type og det bruges til at repræsentere et bestemt punkt på gitteret.

Her har vi et simpelt objekt i vores steder kollektion, der har felt Beliggenhed som en Punkt:

{"name": "Big Ben", "location": {"coordinates": [-0.1268194, 51.5007292], "type": "Point"}}

Bemærk, at længdegradsværdien kommer først, derefter breddegraden.

2.2. Polygon

Polygon er lidt mere kompleks GeoJSON type.

Vi kan bruge Polygon at definere et område med dets ydre grænser og også indvendige huller, hvis det er nødvendigt.

Lad os se et andet objekt, der har sin placering defineret som en Polygon:

{"name": "Hyde Park", "location": {"koordinater": [[[-0.159381, 51.513126], [-0.189615, 51.509928], [-0.187373, 51.502442], [-0.153019, 51.503464], [ -0.159381, 51.513126]]], "type": "Polygon"}}

I dette eksempel definerede vi en række punkter, der repræsenterer ydre grænser. Vi er også nødt til at lukke grænsen, så det sidste punkt svarer til det første punkt.

Bemærk, at vi skal definere de ydre grænsepunkter i retning mod uret og hulgrænser i retning med uret.

Ud over disse typer er der også mange andre typer som LineString, MultiPoint, MultiPolygon, MultiLineString, og Geometri Samling.

3. Geospatial indeksering

For at udføre søgeforespørgsler på de geospatiale data, vi har gemt, skal vi oprette et geospatialt indeks på vores Beliggenhed Mark.

Vi har stort set to muligheder: 2d og 2dsphere.

Men lad os først definere vores steder cvalg:

MongoClient mongoClient = ny MongoClient (); MongoDatabase db = mongoClient.getDatabase ("myMongoDb"); collection = db.getCollection ("steder");

3.1. 2d Geospatial Index

Det 2d indeks giver os mulighed for at udføre søgeforespørgsler, der fungerer ud fra 2d-planberegninger.

Vi kan oprette en 2d indeks på Beliggenhed felt i vores Java-applikation som følger:

collection.createIndex (Indexes.geo2d ("placering"));

Selvfølgelig kan vi gøre det samme i mongo skal:

db.places.createIndex ({placering: "2d"})

3.2. 2dsphere Geospatial Index

Det 2dsphere indeks understøtter forespørgsler, der fungerer baseret på kugleberegninger.

På samme måde kan vi oprette en 2dsphere indeks i Java ved hjælp af det samme Indekser klasse som ovenfor:

collection.createIndex (Indexes.geo2dsphere ("placering"));

Eller i mongo skal:

db.places.createIndex ({location: "2dsphere"})

4. Søgning ved hjælp af geospatiale forespørgsler

Lad os nu, for den spændende del, søge efter objekter baseret på deres placering ved hjælp af geospatiale forespørgsler.

4.1. I nærheden af ​​forespørgsel

Lad os starte med nær ved. Vi kan bruge nær ved forespørgsel for at søge efter steder inden for en given afstand.

Det nær ved forespørgsel fungerer med begge 2d og 2dsphere indekser.

I det næste eksempel søger vi efter steder, der er mindre end 1 km og mere end 10 meter væk fra den givne position:

@Test offentlig ugyldighed givenNearbyLocation_whenSearchNearby_thenFound () {Point currentLoc = nyt punkt (ny position (-0.126821, 51.495885)); FindIterable result = collection.find (Filters.near ("location", currentLoc, 1000.0, 10.0)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("name")); }

Og den tilsvarende forespørgsel i mongo skal:

db.places.find ({location: {$ near: {$ geometry: {type: "Point", coordinates: [-0.126821, 51.495885]}, $ maxDistance: 1000, $ min Distance: 10}}})

Bemærk, at resultaterne er sorteret fra nærmeste til længst.

Tilsvarende, hvis vi bruger et meget langt sted, finder vi ingen steder i nærheden:

@Test offentlig ugyldighed givenFarLocation_whenSearchNearby_thenNotFound () {Point currentLoc = nyt punkt (ny position (-0.5243333, 51.4700223)); FindIterable result = collection.find (Filters.near ("location", currentLoc, 5000.0, 10.0)); assertNull (result.first ()); }

Vi har også nearSphere metode, der fungerer nøjagtigt som nær ved, bortset fra at det beregner afstanden ved hjælp af sfærisk geometri.

4.2. Inden for forespørgsel

Dernæst undersøger vi geoWithin forespørgsel.

Det geoWithin forespørgsel giver os mulighed for at søge efter steder, der fuldt ud eksisterer inden for en given Geometri, som en cirkel, kasse eller polygon. Dette fungerer også med begge dele 2d og 2dsphere indekser.

I dette eksempel leder vi efter steder, der findes inden for en radius på 5 km fra den givne centerposition:

@Test offentlig ugyldighed givenNearbyLocation_whenSearchWithinCircleSphere_thenFound () {dobbelt distanceInRad = 5.0 / 6371; FindIterable result = collection.find (Filters.geoWithinCenterSphere ("location", -0.1435083, 51.4990956, distanceInRad)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("name")); }

Bemærk, at vi er nødt til at omdanne afstanden fra km til radian (bare divider med jordens radius).

Og den resulterende forespørgsel:

db.places.find ({location: {$ geoWithin: {$ centerSphere: [[-0.1435083, 51.4990956], 0.0007848061528802386]}}}

Dernæst søger vi efter alle steder, der findes inden for et rektangel "felt". Vi er nødt til at definere boksen ved dens nederste venstre position og øverste højre position:

@Test offentlig ugyldighed givenNearbyLocation_whenSearchWithinBox_thenFound () {double lowerLeftX = -0.1427638; dobbelt lavere Venstre = 51.4991288; dobbelt upperRightX = -0,12256209; dobbelt upperRightY = 51.5030272; FindIterable result = collection.find (Filters.geoWithinBox ("location", lowerLeftX, lowerLeftY, upperRightX, upperRightY)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("name")); }

Her er den tilsvarende forespørgsel i mongo skal:

db.places.find ({location: {$ geoWithin: {$ box: [[-0.1427638, 51.4991288], [-0.1256209, 51.5030272]]}})

Langt om længe, hvis det område, vi vil søge i, ikke er et rektangel eller en cirkel, kan vi bruge en polygon til at definere et mere specifikt område:

@Test offentlig ugyldighed givetNearbyLocation_whenSearchWithinPolygon_thenFound () {ArrayList point = ny ArrayList(); point.add (Arrays.asList (-0.1439, 51.4952)); point.add (Arrays.asList (-0.1121, 51.4989)); point.add (Arrays.asList (-0.13, 51.5163)); point.add (Arrays.asList (-0.1439, 51.4952)); FindIterable resultat = collection.find (Filters.geoWithinPolygon ("placering", point)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("name")); }

Og her er den tilsvarende forespørgsel:

db.places.find ({placering: {$ geoWithin: {$ polygon: [[-0.1439, 51.4952], [-0.1121, 51.4989], [-0.13, 51.5163], [-0.1439, 51.4952]]}})

Vi definerede kun en polygon med dens ydre grænser, men vi kan også tilføje huller til den. Hvert hul vil være en Liste af Punkts:

geoWithinPolygon ("placering", punkter, hul1, hul2, ...)

4.3. Kryds forespørgsel

Lad os endelig se på geoIntersects forespørgsel.

Det geoIntersects forespørgsel finder objekter, der i det mindste skærer hinanden med en given Geometri. Til sammenligning geoWithin finder objekter, der fuldt ud eksisterer inden for et givet Geometri.

Denne forespørgsel fungerer med 2dsphere kun indeks.

Lad os se dette i praksis med et eksempel på at lede efter ethvert sted, der krydser et Polygon:

@Test offentlig ugyldighed givenNearbyLocation_whenSearchUsingIntersect_thenFound () {ArrayList positioner = ny ArrayList (); positions.add (ny position (-0.1439, 51.4952)); positions.add (ny position (-0.1346, 51.4978)); positions.add (ny position (-0.2177, 51.5135)); positions.add (ny position (-0.1439, 51.4952)); Polygon geometri = ny polygon (positioner); FindIterable resultat = collection.find (Filters.geoIntersects ("placering", geometri)); assertNotNull (result.first ()); assertEquals ("Hyde Park", result.first (). get ("name")); }

Den resulterende forespørgsel:

db.places.find ({location: {$ geoIntersects: {$ geometry: {type: "Polygon", koordinater: [[[-0.1439, 51.4952], [-0.1346, 51.4978], [-0.2177, 51.5135], [ -0.1439, 51.4952]]]}}})

5. Konklusion

I denne artikel lærte vi, hvordan man gemmer geospatiale data i MongoDB og så på forskellen mellem 2d og 2dsphere geospatiale indekser. Vi lærte også, hvordan man søger i MongoDB ved hjælp af geospatiale forespørgsler.

Som sædvanlig er den fulde kildekode til eksemplerne tilgængelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found