PostGIS et JPA



PostGIS est un logiciel open source qui ajoute la prise en charge des fonctionnalités géographiques à la base de données relationnelle PostgreSQL.

Ce court article présentera son utilisation en Java. En particulier, la tâche de trouver des objets géographiques par leurs coordonnées.

PostGIS a été créé en 2001. C'est une bonne solution gratuite pour stocker des données cartographiques dans la base de données. Mais l'article ne parle pas entièrement de lui, mais seulement d'un cas spécial - un travail pratique avec PostGIS à l'aide des outils JPA.

Dépendances


Les bibliothèques suivantes sont importantes pour notre tâche:

  • Hibernate 5.3.7
  • hibernate-spatial - même version. Théoriquement, vous pouvez utiliser les plus anciens. À partir du cinquième, l'hibernation spatiale est identique à l'hibernation. Auparavant: Hibernate Spatial 1.1.x pour Hibernate 3.6.x, Hibernate Spatial 1.0 pour Hibernate 3.2.x - 3.5.x.
  • postgresql 42.2.4. Cette version a été prise, car les plus récentes ont renforcé les exigences SSL. Choisissez la version du pilote qui correspond à la version de la base de données.

Eh bien, tout ce dont vous avez besoin pour JPA est le printemps ou un conteneur.

Dialectes


Hibernate Spatial fournit des abstractions géométriques pour travailler avec des bases spatiales. Comme dans JPA, en première approximation, nous ne sommes pas intéressés par la base de données utilisée sur le serveur.

Officiellement pris en charge par PostgresSQL, Oracle, MySQL, MS SQLServer, GeoDB (H2), DB2. Caractéristiques du support . Le muscle peut sembler un étranger. Mais dans la version 8, la prise en charge des données spatiales est décemment améliorée .

Nous utilisons Postgres. Mais vous devez spécifier le dialecte Hibernate "org.hibernate.spatial.dialect.postgis.PostgisDialect" au lieu du post-grec standard.

Il est temps de coder


Une table dans PostGIS peut avoir n'importe quel champ. Juste standard, l'un d'eux sera de type géométrie. Et il y a la géographie (non prise en charge actuellement dans Hibernate). Si vous n'apprenez pas à Java à travailler avec ce type, il sera interprété comme un blob ou une chaîne de la forme "01010000207B7F0000188D594CC9B22541BC4E56674F2C5541".

Bien sûr, vous pouvez travailler avec PostGis sur un JBDC pur. Un exemple . Mais cela nécessite un travail minutieux séparé avec org.postgis.PGgeometry . Ce ne sont pas les cours dont parlera l'article. Et il n'y aura plus de tolérance.

Nous allons à JPA et créons une classe simple:

 @Entity public class AdressBuilding implements Serializable { @Id private Integer id; private Point geom; ... 

Les champs restants sont omis (un objet géographique peut stocker n'importe quelle information). Rien d'inhabituel ici - la classe d'entité standard. Seul un objet de classe Point est intéressant - un point d'espace tridimensionnel.

Ci-après, les classes du package com.vividsolutions.jts.geom sont utilisées.

Le STC est devenu de facto la norme pour représenter les données géospatiales. Il implémente la spécification Simple Feature Specification / Simple Feature Access créée par OpenGIS dans les années 90.

Clarification . Point hérite de la classe Geometry abstraite. Il contient les champs non statiques suivants:

  protected Envelope envelope; protected final GeometryFactory factory; protected int SRID; private Object userData; 

L'enveloppe est la zone de délimitation minimale pour cette géométrie. Mais il peut revenir sous forme de géométrie. Et puis vous aurez une tentative sans fin de sérialisation.

SRID - numéro du système de coordonnées. Il y en a beaucoup. Les principales différences: le format des coordonnées (mètres, degrés ...), le point de référence et la forme de la Terre (la Terre n'est pas ronde). PostGis connaît de nombreux systèmes de coordonnées et peut les transformer.

Comme je l'ai dit, nous avons un type de géométrie dans la base de données. J'ai immédiatement utilisé la classe Point concrète pour plus de commodité, car dans ce tableau, je n'ai que des objets point. Mais PostGIS théorique peut stocker plusieurs types de géométrie à la fois. Juste dans chaque géométrie, son type est indiqué:

 "geometry":{"type":"MultiPolygon","coordinates":... 

Selon StackOverflow, l'utilisation de plusieurs géométries dans la même table ralentit les requêtes. Les géométries peuvent également être imbriquées. Types:


Requêtes de base de données


Avec la mise en œuvre de la classe compris. il est maintenant temps de les retirer de la base. Nos points sont des maisons, ou plutôt leurs adresses. Vous pouvez faire des requêtes SQL familières: obtenir des maisons par identifiant, nombre, nombre de grand-mères ...

Nous nous intéressons maintenant aux requêtes spatiales. Par exemple, trouvez une maison par coordonnées. Soit les coordonnées souhaitées x, y et + -delta la zone de recherche souhaitée. Les requêtes principales dans STS sont effectuées sur le rapport des géométries. Par conséquent, nous devons le créer:

  Coordinate c1 = new Coordinate(x - delta, y - delta); ... Coordinate[] coordinates = new Coordinate[]{c1, c2, c3, c4, c1}; GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();//static  Polygon square_window = GEOMETRY_FACTORY.createPolygon(coordinates); square_window.setSRID(32635); 

Si nous ne spécifions pas de système de coordonnées, PostGis refusera de les comparer. Soit vous connaissez votre code système, soit vous l'obtenez de n'importe où avec le code .getGeom().getSRID() .

Ensuite, nous envoyons une demande du formulaire:

  "select a " + "from AdressBuilding a " + "where within(a.geom, :window) = true" 

Une requête à l'intérieur signifie vérifier si la géométrie est à l'intérieur d'une autre. Ne vous inquiétez pas si votre IDE dit qu'il ne peut y avoir une telle demande dans l'APP. Hibernate Spatial le convertit en:
  where st_within(adressbuil0_.geom, ?)=true 

st_within est déjà une fonction PostGis.

Il existe plusieurs options pour obtenir le même résultat - le point est tombé dans un carré. contains(:window, a.geom) / intersects(a.geom, :window)...



Une description détaillée des spécifications est ici .

Postface


Nous avons obtenu les points - faites maintenant ce que vous voulez avec eux.

J'ai testé le cas d'une petite base de données sur un serveur avec une quantité relativement importante de RAM. Si vous chargez au maximum et oubliez les index, la tâche de recherche s'exécutera dans le processeur.
Postgres possède de nombreux index différents. Et certains d'entre eux aident Postgis . L'étude a montré que seul GIST (?) Convient aux points
 CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometryfield] ); 

Mais le plus souvent, lorsque vous importez des données dans PostGis, les index sont créés automatiquement ...

Les clarifications et informations supplémentaires sont les bienvenues.

Manuel utilisé:

Pour l'hibernation 5
Pour l'hibernation 4

Source: https://habr.com/ru/post/fr440872/


All Articles