I need to implement a solution that aims to filter one of my search query using location. You will find here my entity and how I used @Spatial annotation :
@Entity
@Indexed
@Spatial(spatialMode = SpatialMode.RANGE)
@Table(name = "ORGANIZATION", uniqueConstraints = { @UniqueConstraint(columnNames = { "CODE" }) })
public class Organization implements Serializable, FileEntity {
...
@Latitude
@Column(name = "LATITUDE")
private Double latitude;
@Longitude
@Column(name = "LONGITUDE")
private Double longitude;
...
}
Indexing does not figure any errors, here's the result I found using elasticsearch querying :
GET http://localhost:9201/com.supralog.lexis.model.organization.organization
{
"com.supralog.lexis.model.organization.organization" : {
"aliases" : { },
"mappings" : {
"com.supralog.lexis.model.organization.Organization" : {
"properties" : {
"_hibernate_default_coordinates" : {
"properties" : {
"lat" : {
"type" : "float"
},
"lon" : {
"type" : "float"
}
}
},
...
}
}
}
}
GET http://localhost:9201/com.supralog.lexis.model.organization.organization/_search?from=0&size=1
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 15628,
"max_score" : 1.0,
"hits" : [
{
"_index" : "com.supralog.lexis.model.organization.organization",
"_type" : "com.supralog.lexis.model.organization.Organization",
"_id" : "...",
"_score" : 1.0,
"_source" : {
...
"_hibernate_default_coordinates" : {
"lat" : 49.1886203,
"lon" : -0.38740259999997306
},
...
}
}
]
}
}
After checking indexation looks OK, I tried to query all Organization objects within a given radius of 100km :
final Coordinates coordinates = Point.fromDegrees(form.getLatitude(), form.getLongitude());
final String search = StringUtils.join(terms, " ");
final FullTextSession fullTextSession = Search.getFullTextSession(sessionFactory.getCurrentSession());
final QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder()
.forEntity(Organization.class).get();
final org.apache.lucene.search.Query elasticQuery = queryBuilder.spatial().within(100,Unit.KM).ofCoordinates(coordinates).createQuery();
final FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(elasticQuery, Organization.class);
fullTextQuery.setMaxResults(form.getMaximumNumberOfResult());
fullTextQuery.setProjection(FullTextQuery.THIS, FullTextQuery.SCORE);
And my problem is here, when I try to execute this query, I'm having the following return statement :
Request: POST /com.supralog.lexis.model.organization.organization/_search with parameters {from=0, size=50}
Response: 400 'Bad Request' with body
{
"error": {
"root_cause": [
{
"type": "query_shard_exception",
"reason": "failed to find geo_point field [_hibernate_default_coordinates]",
"index_uuid": "phOfJTOyRvetHyZrfeUmrA",
"index": "com.supralog.lexis.model.organization.organization"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "com.supralog.lexis.model.organization.organization",
"node": "9DCzSp6kS5KGtMq6tzywzg",
"reason": {
"type": "query_shard_exception",
"reason": "failed to find geo_point field [_hibernate_default_coordinates]",
"index_uuid": "phOfJTOyRvetHyZrfeUmrA",
"index": "com.supralog.lexis.model.organization.organization"
}
}
]
},
"status": 400
}
To fix it, I tried to set a name to @Spatial record, I tried to make my entity implements Coordinates, etc. However I'm always having the same result. It looks like hibernate-search is not indexing my location as a geo_point, reason why it's failing on querying...
Do you have any idea on what I missed in documentation ?
Versions used :: hibernate : 5.3 ; hibernate-search : 5.10 ; elasticsearch : 5.6
The Elasticsearch mapping is wrong:
"com.supralog.lexis.model.organization.Organization" : {
"properties" : {
"_hibernate_default_coordinates" : {
"properties" : {
"lat" : {
"type" : "float"
},
"lon" : {
"type" : "float"
}
}
},
...
}
}
The fact that there's a "properties" attribute under "_hibernate_default_coordinates" means that "_hibernate_default_coordinates" is of type "object", whereas it should be of type "geo_point".
The most likely explanation is that you didn't generate the schema before indexing, and Elasticsearch tried to automatically generate it on the fly based on the documents it received. As you can see it's a very bad idea, since the risk of Elasticsearch guessing the schema wrong is quite high.
You should have a look at the documentation about configuration. In particular, you should pick a suitable index schema management strategy.
In short, put the following into hibernate.properties
In development environment: Hibernate Search will try its best, but may fail, and data won't be reindexed magically, you'll have to do it yourself
hibernate.search.default.elasticsearch.index_schema_management_strategy update
In production environment: you'll have to update the schema carefully yourself, and plan a mass reindexing when updating your application.
hibernate.search.default.elasticsearch.index_schema_management_strategy create