-
Notifications
You must be signed in to change notification settings - Fork 233
Geospatial Persistence and Queries
Kundera allows you to store and query on geographical data in NoSQL. (Currently only MongoDB is supported).
Different databases may have different ways and formats of storing geographical information. Kundera abstracts over this and provides a standard and cross-database interface for geographical database persistence and queries.
Since JPA doesn't include any GIS related specification, Kundera uses Simple Features Specification from Open Geospatial Consortium (OGC) which is the most popular industry standard for providing inter operable solutions that "geo-enable" the Web, wireless and location-based services and mainstream IT.
Kundera uses JTS Topology Suite, which conforms to the Simple Features Specification for SQL published by the Open GIS Consortium.
In this document, we are going to explain how to declare geolocation fields, specify geospatial indexes, perform CRUD and run Geospatial queries. MongoDB will be used as datastore.
This presentation is pretty helpful in understanding Geospatial support in MongoDB. A quick-start with writing geospatial queries in Java is a good starting point.
All geolocation fields should have data-type com.impetus.kundera.gis.geometry.Point which has following signature:
public class Point extends com.vividsolutions.jts.geom.Point
{
}
Point class encapsulates x, y and z coordinates. (z is unused as only 2D indexes are supported). Geolocation fields are allowed in entity classes as well as Embeddable classes. An entity class called Person with geolocation field named currentLocation is shown below:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import com.impetus.kundera.gis.geometry.Point;
import com.impetus.kundera.index.Index;
import com.impetus.kundera.index.IndexCollection;
@Entity
@Table(name="PERSON_LOCATION", schema = "KunderaExamples@mongoTest")
@IndexCollection(columns = { @Index(name = "currentLocation", type = "GEO2D")})
public class Person
{
@Id
@Column(name = "PERSON_ID")
private int personId;
@Column(name = "PERSON_NAME")
private String name;
@Column(name = "CURRENT_LOCATION")
private Point currentLocation;
//Constructors and getters/ setters go here
}
As shown in code above, geospatial index can be specified on geolocation field(s) using @IndexCollection and @Index annotation.
Entities containing geolocation fields are saved, retrieved and deleted in the same way as normal entities. Code snippet below demonstrates this:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("mongo_pu");
EntityManager em = null;
em = emf.createEntityManager();
Person person = new Person();
person.setPersonId(1);
person.setName("Amresh");
person.setCurrentLocation(new Point(2.6, 5.4));
em.persist();
em.close();
em = emf.createEntityManager();
Person p = em.find(Person.class, 1);
em.close();
em = emf.createEntityManager();
Person p = em.find(Person.class, 1);
p.setName("Kuldeep");
em.merge(p);
em.close();
em = emf.createEntityManager();
Person p = em.find(Person.class, 1);
em.remove(p);
em.close();
Geospatial queries in Kundera are written in JPA-QL. Following types of queries are supported currently:
Within Circle:
import com.impetus.kundera.gis.geometry.Circle;
Circle circle = new Circle(3.4, 5.4, 1.0); /x, y and radius in that order
Query q = em.createQuery("Select p from Person p where p.currentLocation IN ?1");
q.setParameter(1, circle);
List<Person> persons = q.getResultList();
Within Envelope:
import com.impetus.kundera.gis.geometry.Envelope;
Envelope envelope = new Envelope(2.0, 5.0, 2.0, 5.0);
Query q = em.createQuery("Select p from Person p where p.currentLocation IN :envelope");
q.setParameter("envelope", envelope);
List<Person> persons = q.getResultList();
Within Triangle:
import com.impetus.kundera.gis.geometry.Triangle;
Triangle triangle = new Triangle(1.0, 1.0, 5.0, 1.0, 3.0, 4.0);
Query q = em.createQuery("Select p from Person p where p.currentLocation IN :triangle");
q.setParameter("triangle", triangle);
List<Person> persons = q.getResultList();
Within polygon:
import com.impetus.kundera.gis.geometry.Polygon;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
GeometryFactory factory = new GeometryFactory();
Coordinate[] coordinates = new Coordinate[6];
coordinates[0] = new Coordinate(1.0, 1.0);
coordinates[1] = new Coordinate(1.0, 2.0);
coordinates[2] = new Coordinate(3.0, 4, 0);
coordinates[3] = new Coordinate(4.0, 3.0);
coordinates[4] = new Coordinate(4.0, 1.0);
coordinates[5] = new Coordinate(1.0, 1.0);
CoordinateSequence points = factory.getCoordinateSequenceFactory().create(coordinates);
LinearRing shell = new LinearRing(points, factory);
LinearRing[] holes = new LinearRing[0];
Polygon polygon = new Polygon(shell, holes, factory);
Query q = em.createQuery("Select p from Person p where p.currentLocation IN :polygon");
q.setParameter("polygon", polygon);
List<Person> persons = q.getResultList();
import com.impetus.kundera.gis.geometry.Point;
Point point = new Point(5.0, 6.0);
Query q = em.createQuery("Select p from Person p where p.currentLocation > :point AND p.currentLocation < :maxDistance");
q.setParameter("point", point);
q.setParameter("maxDistance", 1.0);
List<Person> persons = q.getResultList();
Near Sphere:
import com.impetus.kundera.gis.geometry.Point;
import com.impetus.kundera.gis.SurfaceType;
Point point = new Point(5.0, 6.0);
point.setSurfaceType(SurfaceType.SPHERICAL);
Query q = em.createQuery("Select p from Person p where p.currentLocation > :point AND p.currentLocation < :maxDistance");
q.setParameter("point", point);
q.setParameter("maxDistance", ((2.0 * 1.0 * 3.1416 / 360.0))); //1.0 is radius
List<Person> persons = q.getResultList();
Center Sphere:
import com.impetus.kundera.gis.geometry.Circle;
import com.impetus.kundera.gis.SurfaceType;
Circle circle = new Circle(3.4, 5.4, (2.0*2.0*3.1416/360.0)); /x, y and radius in that order
circle.setSurfaceType(SurfaceType.SPHERICAL);
Query q = em.createQuery("Select p from Person p where p.currentLocation IN ?1");
q.setParameter(1, circle);
List<Person> persons = q.getResultList();
Code example/ Test case is available at: https://github.com/impetus-opensource/Kundera/blob/trunk/kundera-mongo/src/test/java/com/impetus/client/gis/MongoGISTest.java
-
Datastores Supported
- Releases
-
Architecture
-
Concepts
-
Getting Started in 5 minutes
-
Features
- Object Mapper
- Polyglot Persistence
- Queries Support
- JPQL (JPA Query Language)
- Native Queries
- Batch insert update
- Schema Generation
- Primary Key Auto generation
- Transaction Management
- REST Based Access
- Geospatial Persistence and Queries
- Graph Database Support
-
Composite Keys
-
No hard annotation for schema
-
Support for Mapped superclass
-
Object to NoSQL Data Mapping
-
Cassandra's User Defined Types and Indexes on Collections
-
Support for aggregation
- Scalar Queries over Cassandra
- Connection pooling using Kundera Cassandra
- Configuration
-
Kundera with Couchdb
-
Kundera with Elasticsearch
-
Kundera with HBase
-
Kundera with Kudu
-
Kundera with RethinkDB
-
Kundera with MongoDB
-
Kundera with OracleNoSQL
-
Kundera with Redis
-
Kundera with Spark
-
Extend Kundera
- Sample Codes and Examples
-
Blogs and Articles
-
Tutorials
* Kundera with Openshift
* Kundera with Play Framework
* Kundera with GWT
* Kundera with JBoss
* Kundera with Spring
-
Performance
-
Troubleshooting
-
FAQ
- Production deployments
- Feedback