Spring Data Elasticsearch and GeoPoints
Some backstory... I was working on a Java app with an Angular 1.x frontend. The base project was generated by JHipster and uses PostgreSQL for the DB and Spring Boot.
The application relies heavily on being able to return a list of items that are "near" the provided location from the client. So really just a geospatial search. To accomplish this I decided to use Elasticsearch's built in geo functions. I figured the easiest way to do so would be to use my JPA entity that is annotated as a Hibernate entity could double for my search engine entity as long as I used a string to represent my geopoint. It was pretty simple to set that up, just concatenate latitude, a comma, and longitude, or the reverse depending on use cases or to conform to Elasticsearch's requirements. Now we can easily store it in the database without a serializer and deserializer, and it should work out of the box with Elasticsearch.
I wrote a couple tests with dummy data to make sure that I can do geo based searches and return exactly what I expect. I.E. I don't return a lat/lon that's in New York when I search for results within 1 kilometer of Chicago Loop. When I ran the tests, all I saw was red. I was very disheartened by this. I followed exactly what the Spring Data Elasticsearch developers did with their tests. I thought I had it set up correctly. I made sure my geopoint string with annotated with @GeoPointField
, and that my entity was annotated as a @Document
for ElasticSearch. But alas, no matter what I tried Elasticsearch could not process my string as a geopoint.
Then I took another look at the documentation and the tests on github for Spring Data Elasticsearch. You can look at the LocationMarkerEntity.java entity for their tests as an example. In their tests they are able to return items using the geo spacial queries for the geopoint String fields. The only difference between my entity and their entity was some additonal options on the @Document
annotation. I thought that since I was using the @GeoPointField
annotation on my string, it would work without a hitch, however that's not the case. As you can see below, the source for the Spring Data Elasticsearch also included this type = "geo-annotation-point-type"
option in the @Document
annotation.
package org.springframework.data.elasticsearch.core.geo;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
@Document(indexName = "test-geo-index", type = "geo-annotation-point-type", shards = 1, replicas = 0, refreshInterval = "-1")
public class LocationMarkerEntity {
// some code omitted for berevity
@GeoPointField
private String locationAsString;
@GeoPointField
private double[] locationAsArray;
// omitted
}
I searched the Spring Data Elasticsearch docs but I didn't find a reference to this type parameter. I did a cursory search of the Elasticsearch docs, but didn't turn anything up there. I also looked through the Spring Data Elasticsearch source to see if this parameter was defined in the @Document
annotation but I didn't find it. I likely missed it in the docs or in the source, but it lead to a frustrating few days as I spent time trying to find why my geo indexing wasn't working correctly.
Hopefully this will help anybody else having the same issue with the Spring Data Elasticsearch framework.