תמיכה גיאו-מרחבית ב- MongoDB

1. סקירה כללית

במדריך זה נחקור את התמיכה הגיאו-מרחבית ב- MongoDB.

נדון כיצד לאחסן נתונים גיאו-מרחביים, אינדקס גיאוגרפי וחיפוש גיאו-מרחבי. אנו נשתמש גם בשאילתות חיפוש גיאו-מרחביות כמו סמוך ל, geoWithin, ו geoIntersects.

2. אחסון נתונים גיאו-מרחביים

ראשית, בואו נראה כיצד לאחסן נתונים גיאו-מרחביים ב- MongoDB.

MongoDB תומך במספר רב GeoJSON סוגים לאחסון נתונים גיאו-מרחביים. במהלך הדוגמאות שלנו, נשתמש בעיקר ב- נְקוּדָה ו מְצוּלָע סוגים.

2.1. נְקוּדָה

זה הכי בסיסי ונפוץ GeoJSON סוג, ו הוא משמש לייצוג נקודה אחת ספציפית ברשת.

הנה, יש לנו אובייקט פשוט, שלנו מקומות אוסף, שיש לו שדה מקום כ נְקוּדָה:

{"name": "ביג בן", "מיקום": {"קואורדינטות": [-0.1268194, 51.5007292], "type": "נקודה"}}

שים לב שערך האורך מגיע קודם, ואז הרוחב.

2.2. מְצוּלָע

מְצוּלָע הוא קצת יותר מורכב GeoJSON סוּג.

אנחנו יכולים להשתמש מְצוּלָע להגדיר אזור עם גבולותיו החיצוניים וגם חורים פנימיים במידת הצורך.

בואו נראה אובייקט אחר שמיקומו מוגדר כ- מְצוּלָע:

{"name": "Hyde Park", "location": {"קואורדינטות": [[[-0.159381, 51.513126], [-0.189615, 51.509928], [-0.187373, 51.502442], [-0.153019, 51.503464], [ -0.159381, 51.513126]]], "type": "מצולע"}}

בדוגמה זו הגדרנו מערך נקודות המייצגות גבולות חיצוניים. עלינו גם לסגור את הגבול כך שהנקודה האחרונה תהיה שווה לנקודה הראשונה.

שימו לב שעלינו להגדיר את נקודות הגבול החיצוני בכיוון השעון ואת גבולות החור בכיוון השעון.

בנוסף לסוגים אלה, ישנם גם סוגים רבים אחרים כמו LineString, MultiPoint, MultiPolygon, MultiLineString, ו GeometryCollection.

3. אינדקס גיאו-מרחבי

כדי לבצע שאילתות חיפוש על הנתונים הגיאו-מרחביים שאחסנו, עלינו ליצור אינדקס גיאו-מרחבי על שלנו מקום שדה.

בעצם יש לנו שתי אפשרויות: 2d ו 2dsphere.

אבל ראשית, בואו נגדיר את המקומות שלנו גאולקשן:

MongoClient mongoClient = MongoClient חדש (); MongoDatabase db = mongoClient.getDatabase ("myMongoDb"); collection = db.getCollection ("מקומות");

3.1. 2d אינדקס גיאו-מרחבי

ה 2d אינדקס מאפשר לנו לבצע שאילתות חיפוש שעובדות על סמך חישובי מישור דו-ממדי.

אנחנו יכולים ליצור 2d אינדקס על מקום שדה ביישום Java שלנו כדלקמן:

collection.createIndex (Indexes.geo2d ("מיקום"));

כמובן, אנחנו יכולים לעשות את אותו הדבר ב מונגו צדף:

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

3.2. 2dsphere אינדקס גיאו-מרחבי

ה 2dsphere אינדקס תומך בשאילתות שעובדות על סמך חישובי כדור.

באופן דומה, אנו יכולים ליצור 2dsphere אינדקס ב- Java באמצעות אותו אינדקסים כיתה כנ"ל:

collection.createIndex (Indexes.geo2dsphere ("מיקום"));

או ב מונגו צדף:

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

4. חיפוש באמצעות שאילתות גיאו-מרחביות

עכשיו, בחלק המרגש, בואו נחפש אובייקטים על סמך מיקומם בעזרת שאילתות גיאו-מרחביות.

4.1. ליד שאילתה

בוא נתחיל עם סמוך ל. אנחנו יכולים להשתמש ב- סמוך ל שאילתה לחיפוש מקומות במרחק נתון.

ה סמוך ל שאילתה עובדת עם שניהם 2d ו 2dsphere מדדים.

בדוגמה הבאה נחפש מקומות שנמצאים במרחק של פחות מק"מ אחד ומרחק של יותר מ -10 מטרים מהמיקום הנתון:

@Test הציבור בטל givenNearbyLocation_whenSearchNearby_thenFound () {נקודה currentLoc = נקודה חדשה (מיקום חדש (-0.126821, 51.495885)); FindIterable result = collection.find (Filters.near ("מיקום", currentLoc, 1000.0, 10.0)); assertNotNull (result.first ()); assertEquals ("ביג בן", result.first (). get ("שם")); }

והשאילתה המתאימה ב- מונגו צדף:

db.places.find ({location: {$ near: {$ geometry: {type: "Point", קואורדינטות: [-0.126821, 51.495885]}, $ maxDistance: 1000, $ min מרחק: 10}}})

שים לב שהתוצאות ממוינות מהקרוב ביותר לרחוק ביותר.

באופן דומה, אם אנו משתמשים במיקום רחוק מאוד, לא נמצא מקומות קרובים:

@Test הציבור בטל givenFarLocation_whenSearchNearby_thenNotFound () {נקודה currentLoc = נקודה חדשה (מיקום חדש (-0.5243333, 51.4700223)); FindIterable result = collection.find (Filters.near ("מיקום", currentLoc, 5000.0, 10.0)); assertNull (result.first ()); }

יש לנו גם את nearSphere שיטה, שפועלת בדיוק כמו סמוך ל, אלא שהיא מחשבת את המרחק באמצעות גאומטריה כדורית.

4.2. בתוך שאילתה

לאחר מכן, נחקור את geoWithin שאילתא.

ה geoWithin שאילתה מאפשרת לנו לחפש מקומות שקיימים במלואם בתוך נתון גֵאוֹמֶטרִיָה, כמו מעגל, תיבה או מצולע. זה עובד גם עם שניהם 2d ו 2dsphere מדדים.

בדוגמה זו אנו מחפשים מקומות שקיימים ברדיוס של 5 ק"מ ממיקום המרכז הנתון:

@ Test public void givenNearbyLocation_whenSearchWithinCircleSphere_thenFound () {distance distanceInRad = 5.0 / 6371; FindIterable result = collection.find (Filters.geoWithinCenterSphere ("מיקום", -0.1435083, 51.4990956, distanceInRad)); assertNotNull (result.first ()); assertEquals ("ביג בן", result.first (). get ("שם")); }

שימו לב שעלינו להפוך את המרחק מק"מ לרדיאן (רק לחלק את הרדיוס של כדור הארץ).

והשאילתה שהתקבלה:

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

לאחר מכן, נחפש את כל המקומות הקיימים בתוך מלבן "תיבה". עלינו להגדיר את התיבה לפי המיקום השמאלי התחתון שלה ואת המיקום הימני העליון:

@ מבט הריק פומבי givenNearbyLocation_whenSearchWithinBox_thenFound () {כפול תחתון תחתון = = -0.1427638; LeftLeftY כפול כפול = 51.4991288; כפול upperRightX = -0.1256209; כפול upperRightY = 51.5030272; FindIterable result = collection.find (Filters.geoWithinBox ("location", lowerLeftX, lowerLeftY, upperRightX, upperRightY)); assertNotNull (result.first ()); assertEquals ("ביג בן", result.first (). get ("שם")); }

הנה השאילתה המתאימה ב מונגו צדף:

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

סוף כל סוף, אם האזור שאנו רוצים לחפש בתוכו אינו מלבן או עיגול, נוכל להשתמש בפוליגון כדי להגדיר אזור ספציפי יותר:

@ מבחן הריק ציבורי ניתןNearbyLocation_whenSearchWithinPolygon_thenFound () {ArrayList נקודות = 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 result = collection.find (Filters.geoWithinPolygon ("מיקום", נקודות)); assertNotNull (result.first ()); assertEquals ("ביג בן", result.first (). get ("שם")); }

והנה השאילתה המתאימה:

db.places.find ({מיקום: {$ geoWithin: {$ מצולע: [[-0.1439, 51.4952], [-0.1121, 51.4989], [-0.13, 51.5163], [-0.1439, 51.4952]]}})

הגדרנו מצולע רק עם הגבולות החיצוניים שלו, אבל אנחנו יכולים גם להוסיף לו חורים. כל חור יהיה א רשימה שֶׁל נְקוּדָהs:

geoWithinPolygon ("מיקום", נקודות, hole1, hole2, ...)

4.3. שאילתת צומת

לבסוף, בואו נסתכל על ה- geoIntersects שאילתא.

ה geoIntersects שאילתה מוצאת אובייקטים שלפחות מצטלבים עם נתון גֵאוֹמֶטרִיָה. בהשוואה, geoWithin מוצא אובייקטים שקיימים במלואם בתוך נתון גֵאוֹמֶטרִיָה.

שאילתה זו עובדת עם 2dsphere אינדקס בלבד.

בואו נראה זאת בפועל, עם דוגמה לחיפוש אחר כל מקום שמצטלב עם מְצוּלָע:

@ מבט הריק פומבי שניתן NearbyLocation_whenSearchUsingIntersect_thenFound () {עמדות ArrayList = ArrayList חדש (); positions.add (עמדה חדשה (-0.1439, 51.4952)); positions.add (עמדה חדשה (-0.1346, 51.4978)); positions.add (עמדה חדשה (-0.2177, 51.5135)); positions.add (עמדה חדשה (-0.1439, 51.4952)); גיאומטריה של מצולע = מצולע חדש (מיקומים); FindIterable result = collection.find (Filters.geoIntersects ("מיקום", גיאומטריה)); assertNotNull (result.first ()); assertEquals ("הייד פארק", result.first (). get ("שם")); }

השאילתה שהתקבלה:

db.places.find ({location: {$ geoIntersects: {$ geometry: {type: "Polygon", קואורדינטות: [[[-0.1439, 51.4952], [-0.1346, 51.4978], [-0.2177, 51.5135], [ -0.1439, 51.4952]]]}}})

5. מסקנה

במאמר זה למדנו כיצד לאחסן נתונים גיאו-מרחביים ב- MongoDB ובחנו את ההבדל בין 2d ו 2dsphere מדדים גיאו-מרחביים. למדנו גם כיצד לחפש ב- MongoDB באמצעות שאילתות גיאו-מרחביות.

כרגיל, קוד המקור המלא של הדוגמאות זמין באתר GitHub.


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