מבוא למרחב תרדמת שינה

1. הקדמה

במאמר זה נסתכל על הרחבה המרחבית של שינה, שינה-מרחבית.

החל מגרסה 5, Hibernate Spatial מספק ממשק סטנדרטי לעבודה עם נתונים גיאוגרפיים.

2. רקע על מרחב שינה

נתונים גיאוגרפיים כוללים ייצוג של ישויות כמו a נקודה, קו, מצולע. סוגי נתונים כאלה אינם חלק ממפרט ה- JDBC, ומכאן ש- JTS (JTS Topology Suite) הפך לסטנדרט לייצוג סוגי נתונים מרחביים.

מלבד JTS, מרחב שינה שינה תומך גם ב- Geolatte-geom - ספרייה עדכנית הכוללת כמה תכונות שאינן זמינות ב- JTS.

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

על אף שמרחבי Hibernate תומכים בבסיסי נתונים שונים כמו Oracle, MySQL, PostgreSQLql / PostGIS, וכמה אחרים, התמיכה בפונקציות הספציפיות למסד הנתונים אינה אחידה.

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

במאמר זה נשתמש ב- Mariadb4j בזיכרון - השומר על הפונקציונליות המלאה של MySQL.

התצורה עבור Mariadb4j ו- MySql דומה, אפילו ספריית מחברי mysql עובדת בשני מסדי הנתונים הללו.

3. תלות Maven

בואו נסתכל על התלות של Maven הנדרשת להקמת פרוייקט שינה-מרחב פשוט:

 org.hibernate hibernate-core 5.2.12.Final org.hibernate hibernate-spatial 5.2.12.Final mysql mysql-connector-java 6.0.6 ch.vorburger.mariaDB4j mariaDB4j 2.2.3 

ה שינה-מרחבית התלות היא זו שתספק תמיכה לסוגי הנתונים המרחבים. את הגרסאות העדכניות ביותר של ליבת שינה, תרדמת-מרחב, mysql-connector-java ו- mariaDB4j ניתן להשיג ב- Maven Central.

4. קביעת תצורה של מרחב שינה

הצעד הראשון הוא ליצור hibernate.properties בתוך ה אֶמְצָעִי מַדרִיך:

hibernate.dialect = org.hibernate.spatial.dialect.mysql.MySQL56SpatialDialect // ...

הדבר היחיד הספציפי למצב שינה-מרחב הוא MySQL56SpatialDialect נִיב. ניב זה מרחיב את MySQL55Dialect ניב ומספק פונקציונליות נוספת הקשורה לסוגי הנתונים המרחבים.

הקוד הספציפי לטעינת קובץ המאפיין, יצירת א SessionFactory, ואינסטינציה של מופע Mariadb4j, זהה לפרויקט שינה רגיל.

5. הבנת ה גֵאוֹמֶטרִיָה סוּג

גֵאוֹמֶטרִיָה הוא סוג הבסיס לכל הסוגים המרחבים ב- JTS. זה אומר שסוגים אחרים כמו נְקוּדָה, מְצוּלָעואחרים משתרעים על גֵאוֹמֶטרִיָה. ה גֵאוֹמֶטרִיָה הקלד java תואם את גֵאוֹמֶטרִיָה הקלד גם את MySql.

על ידי ניתוח א חוּט ייצוג מהסוג, אנו מקבלים מופע של גֵאוֹמֶטרִיָה. כיתת שירות WKTReader המסופק על ידי JTS יכול לשמש להמרת כל ייצוג טקסט ידוע ל- גֵאוֹמֶטרִיָה סוּג:

גיאומטריה ציבורית wktToGeometry (מחרוזת wellKnownText) זורק ParseException {החזר WKTReader חדש (). קרא (wellKnownText); }

עכשיו, בואו נראה את השיטה הזו בפעולה:

בטל ציבורי @Test צריךConvertWktToGeometry () {Geometry geometry = wktToGeometry ("POINT (2 5)"); assertEquals ("נקודה", geometry.getGeometryType ()); assertTrue (מופע גיאומטרי של נקודה); }

כפי שאנו רואים, גם אם סוג ההחזרה של השיטה הוא לקרוא() השיטה היא גֵאוֹמֶטרִיָה, המקרה האמיתי הוא של נְקוּדָה.

6. אחסון נקודה ב- DB

עכשיו שיש לנו מושג טוב מה גֵאוֹמֶטרִיָה סוג הוא ואיך להשיג נְקוּדָה מתוך א חוּטבואו נסתכל על PointEntity:

@Entity class class PointEntity {@Id @GeneratedValue פרטי מזהה ארוך; נקודת נקודה פרטית; // סטרים וקובעים סטנדרטיים}

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

insertpoint ריק ריק (נקודת מחרוזת) {ישות PointEntity = PointEntity חדש (); entity.setPoint ((Point) wktToGeometry (point)); session.persist (ישות); }

השיטה insertPoint () מקבל ייצוג טקסט ידוע (WKT) של א נְקוּדָה, ממיר אותו לא נְקוּדָה למשל ושומר ב- DB.

כזכור, ה- מוֹשָׁב אינו ספציפי למצב שינה-מרחבי והוא נוצר באופן דומה לפרויקט שינה אחר.

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

בואו נסתכל על כמה בדיקות:

@Test ציבורי בטל shouldInsertAndSelectPoints () {ישות PointEntity = חדש PointEntity (); entity.setPoint ((Point) wktToGeometry ("נקודה (1 1)")); session.persist (ישות); PointEntity fromDb = session .find (PointEntity.class, entity.getId ()); assertEquals ("POINT (1 1)", fromDb.getPoint (). toString ()); assertTrue (מופע גיאומטרי של נקודה); }

יִעוּד toString () על נְקוּדָה מחזיר את ייצוג ה- WKT של a נְקוּדָה. הסיבה לכך היא ש גֵאוֹמֶטרִיָה הכיתה עוקפת את toString () שיטה ושימושים פנימיים WKTWriter, שיעור חינם WKTReader שראינו קודם.

לאחר שנבצע את הבדיקה הזו, מצב שינה ייצור PointEntity שולחן עבורנו.

בואו נסתכל על הטבלה ההיא:

desc PointEntity; סוג שדה Null Key id bigint (20) NO PRI point geometry YES

כצפוי, סוּג שֶׁל שדהנְקוּדָה הוא גֵאוֹמֶטרִיָה. מסיבה זו, בעת אחזור הנתונים באמצעות עורך ה- SQL שלנו (כמו MySql workbench), עלינו להמיר את סוג GEOMETRY זה לטקסט קריא לאדם:

בחר id, astext (point) מ- PointEntity; id astext (נקודה) 1 נקודה (2 4)

עם זאת, כאשר מצב שינה כבר מחזיר ייצוג WKT כשאנחנו מתקשרים toString () שיטה ב גֵאוֹמֶטרִיָה או כל אחת משתי קבוצות המשנה שלה, איננו צריכים לטרוח להסבה זו.

7. שימוש בפונקציות מרחביות

7.1. ST_WITHIN () דוגמא

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

אחת הפונקציות הללו ב- MySQL היא ST_WITHIN () זה אומר אם אחד גֵאוֹמֶטרִיָה נמצא בתוך אחר. דוגמה טובה כאן תהיה לברר את כל הנקודות ברדיוס נתון.

נתחיל בבדיקה כיצד ליצור מעגל:

גיאומטריה ציבורית createCircle (כפול x, כפול y, רדיוס כפול) {GeometricShapeFactory shapeFactory = GeometricShapeFactory חדש (); shapeFactory.setNumPoints (32); shapeFactory.setCentre (קואורדינטות חדש (x, y)); shapeFactory.setSize (רדיוס * 2); return shapeFactory.createCircle (); }

מעגל מיוצג על ידי קבוצה סופית של נקודות שצוינה על ידי setNumPoints () שיטה. ה רַדִיוּס מוכפל לפני שהוא קורא ל- setSize () כמו שאנחנו צריכים לצייר את המעגל סביב המרכז, בשני הכיוונים.

בואו נתקדם ונראה כיצד להביא את הנקודות ברדיוס נתון:

@Test ציבורי בטל צריך SelectAllPointsWithinRadius () זורק ParseException {insertPoint ("נקודה (1 1)"); insertPoint ("נקודה (1 2)"); insertPoint ("נקודה (3 4)"); insertPoint ("נקודה (5 6)"); שאילתת שאילתה = session.createQuery ("בחר p מ- PointEntity p שם בתוך (p.point,: מעגל) = true", PointEntity.class); query.setParameter ("מעגל", createCircle (0.0, 0.0, 5)); assertThat (query.getResultList (). stream () .map (p -> ((PointEntity) p) .getPoint (). toString ())) .containsOnly ("POINT (1 1)", "POINT (1 2) "); }

מצב שינה ממפה את שלו בְּתוֹך() פונקציה ל ST_WITHIN () הפונקציה של MySql.

תצפית מעניינת כאן היא שהנקודה (3, 4) נופלת בדיוק על המעגל. ובכל זאת, השאילתה לא מחזירה את הנקודה הזו. זה בגלל ש ה בְּתוֹך() הפונקציה מחזירה אמת רק אם הנתון גֵאוֹמֶטרִיָה נמצא לגמרי בתוך אחר גֵאוֹמֶטרִיָה.

7.2. ST_TOUCHES () דוגמא

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

@Entity בכיתה ציבורית PolygonEntity {@Id @GeneratedValue פרטי מזהה ארוך; מצולע מצולע פרטי; // סטרים וקובעים סטנדרטיים}

הדבר היחיד השונה כאן מהקודם PointEntity זה שאנחנו משתמשים בסוג מְצוּלָע במקום ה נְקוּדָה.

בואו נעבור לקראת המבחן:

@Test ציבורי בטל צריךSelectAdjacentPolygons () זורק ParseException {insertPolygon ("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))"); insertPolygon ("POLYGON ((3 0, 3 5, 8 5, 8 0, 3 0))"); insertPolygon ("פוליגון ((2 2, 3 1, 2 5, 4 3, 3 3, 2 2))"); שאילתת שאילתה = session.createQuery ("בחר p מתוך PolygonEntity p שבו נגיעות (p. polygon,: polygon) = true", PolygonEntity.class); query.setParameter ("מצולע", wktToGeometry ("POLYGON ((5 5, 5 10, 10 10, 10 5, 5 5)))); assertThat (query.getResultList (). stream () .map (p -> ((PolygonEntity) p) .getPolygon (). toString ())). מכיל רק ("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0)) "," POLYGON ((3 0, 3 5, 8 5, 8 0, 3 0)) "); }

ה insertPolygon () שיטה דומה ל- insertPoint () שיטה שראינו קודם. המקור מכיל את היישום המלא של שיטה זו.

אנו משתמשים ב- נגיעות () פונקציה כדי למצוא את מְצוּלָעצמוד לנתון מְצוּלָע. ברור, השלישי מְצוּלָע אינו מוחזר בתוצאה מכיוון שאין נגיעה בקצה הנתון מְצוּלָע.

8. מסקנה

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

למרות שמאמר זה משתמש ב- Mariadb4j, אנו יכולים להחליף אותו ב- MySql מבלי לשנות תצורה כלשהי.

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


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