Geoprostorna podrška u MongoDB-u

1. Pregled

U ovom uputstvu istražit ćemo geoprostornu podršku u MongoDB-u.

Razgovarat ćemo o načinu pohrane geoprostornih podataka, geoindeksiranju i geoprostornom pretraživanju. Također ćemo upotrijebiti više geoprostornih upita za pretraživanje poput blizu, geoUnutar, i geoIntersekti.

2. Pohranjivanje geoprostornih podataka

Prvo, pogledajmo kako pohraniti geoprostorne podatke u MongoDB.

MongoDB podržava višestruke GeoJSON vrste za pohranu geoprostornih podataka. Kroz naše primjere uglavnom ćemo koristiti Točka i Poligon vrste.

2.1. Točka

Ovo je najosnovnije i najčešće GeoJSON tip i koristi se za predstavljanje jedne određene točke na mreži.

Ovdje imamo jednostavan objekt, u našem mjesta kolekcija, to ima polje mjesto kao Točka:

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

Imajte na umu da je vrijednost zemljopisne dužine na prvom mjestu, a zatim geografska širina.

2.2. Poligon

Poligon je malo složeniji GeoJSON tip.

Možemo koristiti Poligon definirati područje s vanjskim granicama a po potrebi i unutarnje rupe.

Pogledajmo još jedan objekt kojem je mjesto definirano kao Poligon:

{"name": "Hyde Park", "location": {"koordinate": [[[-0.159381, 51.513126], [-0.189615, 51.509928], [-0.187373, 51.502442], [-0.153019, 51.503464], [ -0,159381, 51,513126]]], "type": "Poligon"}}

U ovom smo primjeru definirali niz točaka koje predstavljaju vanjske granice. Također moramo zatvoriti granicu tako da zadnja točka bude jednaka prvoj točki.

Imajte na umu da moramo definirati vanjske točke granica u smjeru suprotnom od kazaljke na satu, a granice rupa u smjeru kazaljke na satu.

Pored ovih vrsta, postoje i mnoge druge vrste poput LineString, MultiPoint, MultiPolygon, MultiLineString, i Zbirka geometrije.

3. Geoprostorno indeksiranje

Da bismo izvršavali upite za pretraživanje geoprostornih podataka koje smo pohranili, moramo stvoriti geoprostorni indeks na našem mjesto polje.

U osnovi imamo dvije mogućnosti: 2d i 2dsfera.

Ali prvo, definirajmo svoja mjesta cpropuštanje:

MongoClient mongoClient = novi MongoClient (); MongoDatabase db = mongoClient.getDatabase ("myMongoDb"); collection = db.getCollection ("mjesta");

3.1. 2d Geoprostorni indeks

The 2d indeks omogućuje nam obavljanje upita za pretraživanje koji rade na temelju izračuna 2d ravni.

Možemo stvoriti 2d indeks na mjesto polje u našoj Java aplikaciji kako slijedi:

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

Naravno, to možemo učiniti i u mongo ljuska:

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

3.2. 2dsfera Geoprostorni indeks

The 2dsfera indeks podržava upite koji rade na temelju izračuna kugle.

Slično tome, možemo stvoriti 2dsfera indeks u Javi koristeći isti Kazala razred kao gore:

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

Ili u mongo ljuska:

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

4. Pretraživanje pomoću geoprostornih upita

Sada, za uzbudljivi dio, potražimo objekte na temelju njihovog položaja pomoću geoprostornih upita.

4.1. Blizu Queryja

Krenimo od blizu. Možemo koristiti blizu upit za traženje mjesta unutar zadane udaljenosti.

The blizu upit radi s obje 2d i 2dsfera indeksi.

U sljedećem ćemo primjeru tražiti mjesta koja su udaljena manje od 1 km i više od 10 metara od zadane pozicije:

@Test javna praznina givenNearbyLocation_whenSearchNearby_thenFound () {Point currentLoc = nova točka (nova pozicija (-0.126821, 51.495885)); FindIterable rezultat = collection.find (Filters.near ("location", currentLoc, 1000.0, 10.0)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("ime")); }

I odgovarajući upit u mongo ljuska:

db.places.find ({lokacija: {$ blizu: {$ geometrija: {tip: "Točka", koordinate: [-0.126821, 51.495885]}, $ maxDistance: 1000, $ minDistance: 10}}}))

Imajte na umu da su rezultati sortirani od najbližeg do najudaljenijeg.

Slično tome, ako koristimo jako udaljeno mjesto, nećemo pronaći nijedno obližnje mjesto:

@Test javna praznina givenFarLocation_whenSearchNearby_thenNotFound () {Point currentLoc = nova točka (nova pozicija (-0.5243333, 51.4700223)); FindIterable rezultat = collection.find (Filters.near ("location", currentLoc, 5000.0, 10.0)); assertNull (result.first ()); }

Također imamo blizuSfere metoda, koja djeluje točno kao blizu, osim što izračunava udaljenost koristeći sfernu geometriju.

4.2. Unutar upita

Dalje ćemo istražiti geoUnutar upit.

The geoUnutar Upit nam omogućuje traženje mjesta koja u potpunosti postoje unutar određenog Geometrija, poput kruga, okvira ili poligona. Ovo također radi s obje 2d i 2dsfera indeksi.

U ovom primjeru tražimo mjesta koja postoje u krugu od 5 km od zadanog središnjeg položaja:

@Test javna praznina givenNearbyLocation_whenSearchWithinCircleSphere_thenFound () {double distanceInRad = 5.0 / 6371; FindIterable rezultat = collection.find (Filters.geoWithinCenterSphere ("lokacija", -0.1435083, 51.4990956, distanceInRad)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("ime")); }

Imajte na umu da moramo transformirati udaljenost od km u radijan (samo podijeliti sa Zemljinim polumjerom).

I rezultirajući upit:

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

Zatim ćemo potražiti sva mjesta koja postoje unutar pravokutnog okvira. Moramo definirati okvir prema donjem lijevom i gornjem desnom položaju:

@Test javna praznina givenNearbyLocation_whenSearchWithinBox_thenFound () {dvostruko lowerLeftX = -0,1427638; dvostruko donjiLijevoY = 51.4991288; dvostruki gornjiRightX = -0,12556209; dvostruki gornjidesniY = 51.5030272; FindIterable rezultat = collection.find (Filters.geoWithinBox ("lokacija", lowerLeftX, lowerLeftY, upperRightX, upperRightY)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("ime")); }

Evo odgovarajućeg upita u mongo ljuska:

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

Konačno, ako područje u kojem želimo pretraživati ​​nije pravokutnik ili krug, poligonom možemo definirati određenije područje:

@Test javna praznina givenNearbyLocation_whenSearchWithinPolygon_thenFound () {ArrayList bodovi = novi ArrayList(); points.add (Arrays.asList (-0.1439, 51.4952)); points.add (Arrays.asList (-0,1121, 51,4989)); points.add (Arrays.asList (-0,13, 51,5163)); points.add (Arrays.asList (-0.1439, 51.4952)); FindIterable rezultat = collection.find (Filters.geoWithinPolygon ("lokacija", bodovi)); assertNotNull (result.first ()); assertEquals ("Big Ben", result.first (). get ("ime")); }

I evo odgovarajućeg upita:

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

Poligon smo definirali samo s njegovim vanjskim granicama, ali možemo mu dodati i rupe. Svaka rupa bit će Popis od Točkas:

geoWithinPolygon ("lokacija", točke, rupa1, rupa2, ...)

4.3. Upit za presijecanje

Napokon, pogledajmo geoIntersekti upit.

The geoIntersekti upit pronalazi objekte koji se barem presijecaju s danim Geometrija. Za usporedbu, geoUnutar pronalazi predmete koji u potpunosti postoje unutar određenog Geometrija.

Ovaj upit radi sa 2dsfera samo indeks.

Pogledajmo to u praksi, s primjerom traženja bilo kojeg mjesta koje se siječe s Poligon:

@Test javna praznina givenNearbyLocation_whenSearchUsingIntersect_thenFound () {ArrayList položaji = novi ArrayList (); position.add (novi Položaj (-0.1439, 51.4952)); position.add (novi Pozicija (-0.1346, 51.4978)); position.add (novi položaj (-0,2177, 51,5135)); position.add (novi Položaj (-0,1439, 51,4952)); Geometrija poligona = novi Poligon (položaji); FindIterable rezultat = collection.find (Filters.geoIntersects ("lokacija", geometrija)); assertNotNull (result.first ()); assertEquals ("Hyde Park", result.first (). get ("name")); }

Rezultirajući upit:

db.places.find ({lokacija: {$ geoIntersects: {$ geometrija: {tip: "Poligon", koordinate: [[[-0.1439, 51.4952], [-0.1346, 51.4978], [-0.2177, 51.5135], [ -0,1439, 51,4952]]]}}}))

5. Zaključak

U ovom smo članku naučili kako pohranjivati ​​geoprostorne podatke u MongoDB i pogledali razliku između 2d i 2dsfera geoprostorni indeksi. Također smo naučili kako pretraživati ​​u MongoDB-u pomoću geoprostornih upita.

Kao i obično, puni izvorni kod za primjere dostupan je na GitHubu.