PostGIS e JPA



O PostGIS é um software de código aberto que adiciona suporte a recursos geográficos ao banco de dados relacional do PostgreSQL.

Este breve artigo discutirá seu uso em Java. Em particular, a tarefa de encontrar objetos geográficos por suas coordenadas.

O PostGIS foi criado em 2001. É uma boa solução gratuita para armazenar dados de mapas no banco de dados. Mas o artigo não é inteiramente sobre ele, mas apenas sobre um caso especial - trabalho conveniente com o PostGIS usando ferramentas JPA.

Dependências


As seguintes bibliotecas são importantes para nossa tarefa:

  • Hibernate 5.3.7
  • hibernate-space - mesma versão. Teoricamente, você pode usar os mais antigos. A partir do quinto, hibernar-espacial é o mesmo que hibernar. Anteriormente: Hibernate Spatial 1.1.x para o Hibernate 3.6.x, Hibernate Spatial 1.0 para o Hibernate 3.2.x - 3.5.x.
  • postgresql 42.2.4. Esta versão foi adotada, porque as mais novas reforçavam os requisitos de SSL. Escolha a versão do driver que corresponde à versão do banco de dados.

Bem, tudo que você precisa para o JPA é Spring ou um contêiner.

Dialetos


O Hibernate Spatial fornece abstrações geométricas para trabalhar com bases espaciais. Como no JPA, como primeira aproximação, não estamos interessados ​​em qual banco de dados é usado no servidor.

Oficialmente suportado pelo PostgresSQL, Oracle, MySQL, MS SQLServer, GeoDB (H2), DB2. Apresenta detalhes de suporte . Músculo pode parecer um estranho. Mas na versão 8, o suporte a dados espaciais é decentemente aprimorado .

Nós usamos o Postgres. Mas você precisa especificar o dialeto Hibernate "org.hibernate.spatial.dialect.postgis.PostgisDialect" vez do padrão pós-grego.

Está na hora de codificar


Uma tabela no PostGIS pode ter qualquer campo. Apenas padrão, um deles será do tipo geometria. E há geografia (não suportada agora no Hibernate). Se você não ensinar Java a trabalhar com esse tipo, ele será interpretado como um blob ou String no formato "01010000207B7F0000188D594CC9B22541BC4E56674F2C5541".

Obviamente, você pode trabalhar com o PostGis em um JBDC puro. Um exemplo Mas isso requer um trabalho minucioso separado com org.postgis.PGgeometry . Essas não são as classes que o artigo tratará. E não haverá mais tolerância.

Vamos ao JPA e criamos uma classe simples:

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

Os campos restantes são omitidos (um objeto geográfico pode armazenar qualquer informação). Nada incomum aqui - a classe de entidade padrão. Apenas um objeto da classe Point é interessante - um ponto do espaço tridimensional.

A seguir, as classes do pacote com.vividsolutions.jts.geom são usadas.

O JTS se tornou o padrão de fato para representar dados geoespaciais. Ele implementa a especificação Simple Feature Specification / Simple Feature Access criada pelo OpenGIS nos anos 90.

Esclarecimento . O ponto é herdado da classe Geometry abstrata. Ele contém os seguintes campos não estáticos:

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

Envelope é a caixa delimitadora mínima para essa geometria. Mas pode voltar na forma de geometria. E então você terá uma tentativa interminável de serialização.

SRID - número do sistema de coordenadas. Existem muitos deles. As principais diferenças: o formato das coordenadas (metros, graus ...), o ponto de referência e a forma da Terra (a Terra não é redonda). O PostGis conhece muitos sistemas de coordenadas e pode transformá-los.

Como eu disse, temos um tipo de geometria no banco de dados. Eu imediatamente usei a classe Point concreta por conveniência, porque nesta tabela eu tenho apenas objetos point. Mas o PostGIS teórico pode armazenar vários tipos de geometria ao mesmo tempo. Apenas em cada geometria, seu tipo é indicado:

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

De acordo com o StackOverflow, o uso de várias geometrias na mesma tabela reduz a velocidade das consultas. Geometrias também podem ser aninhadas. Tipos:


Consultas de banco de dados


Com a implementação da classe resolvida. agora é hora de tirá-los da base. Nossos pontos são casas, ou melhor, seus endereços. Você pode fazer consultas SQL familiares: obter casas por ID, número, número de avós ...

Agora estamos interessados ​​em consultas espaciais. Por exemplo, encontre uma casa por coordenadas. Deixe as coordenadas desejadas x, ye + + delta ser a área de pesquisa desejada. As principais consultas no STS são realizadas na proporção de geometrias. Portanto, precisamos criá-lo:

  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); 

Se não especificarmos um sistema de coordenadas, o PostGis se recusará a compará-los. Você conhece o código do sistema ou o obtém de qualquer lugar com o código .getGeom().getSRID() .

Em seguida, enviamos uma solicitação do formulário:

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

Uma consulta dentro significa verificar se a geometria está dentro de outra. Não se assuste se o seu IDE disser que não pode haver tal solicitação na JPA. O Hibernate Spatial o converte em:
  where st_within(adressbuil0_.geom, ?)=true 

Onde st_within já é uma função PostGis.

Existem várias opções para obter o mesmo resultado - o ponto caiu em um quadrado. contains(:window, a.geom) / intersects(a.geom, :window)...



Uma descrição detalhada das especificações está aqui .

Posfácio


Temos os pontos - agora faça o que quiser com eles.

Testei o caso de um pequeno banco de dados em um servidor com uma quantidade relativamente grande de RAM. Se você carregar ao máximo e esquecer os índices, a tarefa de pesquisa será executada no processador.
O Postgres possui muitos índices diferentes. E alguns deles ajudam o Postgis . O estudo mostrou que apenas GIST (?) É adequado para pontos
 CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometryfield] ); 

Porém, na maioria das vezes, quando você importa dados para o PostGis, os índices são criados automaticamente ...

Esclarecimentos e informações adicionais são bem-vindos.

Manual utilizado:

For hibernate 5
For hibernate 4

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


All Articles