Provide integrations to real-world spatial libraries

Description

Real-world applications are likely to rely on dedicated libraries to model their spatial types (points, polygons, ...).

Hibernate ORM already provides integration to JTS and geolatte-geom: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#spatial-overview
We should probably start with that.

Engine and backend

  • Keep the `GeoPoint` and related spatial types, but move them to the utils-common module, in a `spatial` package.

  • In that same package, add an interface that defines conversion logic:

    public interface GeoPointModel<T> { double getGeoPointLatitude(T point); double getGeoPointLongitude(T point); T createGeoPoint(double latitude, double longitude); Class<T> getGeoPointType(); }
  • Implement this for our own GeoPoint type, with a static GeoPointModel<GeoPoint> get() method.

  • In `IndexFieldTypeFactory`, add a method <T> StandardIndexFieldTypeOptionsStep<?, T> asGeoPoint(GeoPointModel<T> model);

  • Add a default implementation for asGeoPoint which just uses the GeoPointModel for our own GeoPoint type.

  • Do the same for GeoPolygon and GeoBoundingBox if relevant, with separate GeoPolygonModel and GeoBoundingBoxModel interfaces.

  • Implement `asGeoPoint(GeoPointModel<T> model)` by changing all backend code: do not work with GeoPoint directly anymore, but work with a generic T and a GeoPointModel

  • In the DSLs, add variants of spatial-related methods taking a GeoPointModel in parameter. For example we'll add org.hibernate.search.engine.search.dsl.predicate.SpatialPredicateInitialStep#within(GeoPointModel<T>) and make sure the following steps are generic, we'll add org.hibernate.search.engine.search.dsl.projection.SearchProjectionFactory#distance(String, GeoPointModel<T>, T>, we'll add org.hibernate.search.engine.search.dsl.sort.SearchSortFactory#byDistance(String, GeoPointModel<T>, T). Make sure to always keep the old method, but implement it as a default method which just uses our own GeoPointModel.

  • Run tests, check everything still works

  • Add optional dependencies to JTS

  • Implement a JTSGeoPointModel

  • Adapt existing tests so that they can also be run with JTS

  • Add tests to check that mixing spatial models triggers clear exceptions.

  • Do the same with geolatte-geom?

POJO mapper: value bridges

  • Add a way to auto-detect available GeoPointModel et al. implementations on the classpath. Maybe use a GeoPointModelProvider Java service? If so, use org.hibernate.search.engine.environment.classpath.spi.ClassResolver#loadJavaServices.

  • Use this auto-detection to automatically add value bridges in org.hibernate.search.mapper.pojo.bridge.mapping.impl.BridgeResolver.

  • Add appropriate tests

  • Make sure everything will work fine even when JTS is not on the classpath (the model should just be ignored)! We may want a dedicated test for that, perhaps in a separate module that explicitly excludes the dependency.

  • Convert org.hibernate.search.integrationtest.showcase.library.model.Library to use JTS or geolatte-geom, and to use a @GenericField on a location property instead of a @GeoPointBinding on two latitude/longitude properties.

Alternatives

Alternatively, we could make the spatial models a global setting, and change the signatures of our APIs to accept Object instead of GeoPoint et al.
Not sure this would be much better, though...

We could also avoid changing the backends too much by using the spatial models to convert from user APIs to our own representation (our own GeoPoint type), and only ever work with a GeoPoint in the backends.

Document

We will need to document clearly this feature, including in particular the versions of JTS and geolatte-geom we support.

Activity

Details

Assignee

Reporter

Priority

Created July 16, 2019 at 7:44 AM
Updated August 9, 2024 at 9:13 AM