Reputation: 51
I have the classes Organization and Coordinates. Coordinates is as follow :
@Entity
@Table(name = "COORDINATES")
@Indexed
@Spatial
public class Coordinates implements Serializable {
private static final long serialVersionUID = 1L;
public Coordinates() {}
@Id
@Column(name = "id", nullable = false)
@SequenceGenerator(name = "generator", sequenceName = "COORDINATES_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
private Long id;
@Field
@Latitude
@Column(name = "LATITUDE", nullable = false)
private Double latitude;
@Field
@Longitude
@Column(name = "LONGITUDE", nullable = false)
private Double longitude;
I put the annotation @IndexedEmbedded in the coordinates field in the Organization (which is @Indexed + @Entity + @Table). How come the spatial feature is not recognized in my query ? I have the following exception :
org.hibernate.search.exception.SearchException: HSEARCH000131: The field 'organization.Organization#coordinates' used for the spatial query is not configured as spatial field. Check the proper use of @Spatial respectively SpatialFieldBridge at org.hibernate.search.query.dsl.impl.ConnectedSpatialQueryBuilder.createSpatialQuery(ConnectedSpatialQueryBuilder.java:63) at org.hibernate.search.query.dsl.impl.ConnectedSpatialQueryBuilder.createQuery(ConnectedSpatialQueryBuilder.java:38)
I tried adding a name to the Spatial annotation but I got the error saying @Latitude and @Longitude couldn't be found.
So I tried implementing Hibernate's Coordinates, changing @Entity to @Embeddable, changing @IndexedEmbedded for @Spatial in Organization class on the
coordinates
attribute, removing @Latitude + @Longitude in my Coordinates class, overriding getLatitude()
and getLongitude()
. Now I have the following exception :
org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.(...).model.organization.Organization.coordinates references an unknown entity: com.(...).model.localization.Coordinates
I am using :
I talked with the other devs and it seems like they need features that changed in the more recent versions so we don't want to change for the moment.
Here is the interesting part in Organization class :
@Entity
@Table(name = "ORGANIZATION", uniqueConstraints = {@UniqueConstraint(columnNames = { "CODE" }) })
@Indexed
public class Organization implements Serializable, FileEntity {
// lots of attributes, getters, setters, constructor
@Spatial(name = "location", spatialMode = SpatialMode.RANGE)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "COORDINATES_ID")
private Coordinates coordinates;
}
And the modified Coordinates class :
@Embeddable
@Table(name = "COORDINATES")
@Indexed
public class Coordinates implements org.hibernate.search.spatial.Coordinates, Serializable {
// serial, constructor, id get+set
@Field
@Column(name = "LATITUDE", nullable = false)
private Double latitude;
@Field
@Column(name = "LONGITUDE", nullable = false)
private Double longitude;
@Override
public Double getLatitude() {
return this.latitude;
}
@Override
public Double getLongitude() {
return this.longitude;
}
}
I added the "(of = "location")" in @Latitude and @Longitude. I still have the error :
Error message: {"root_cause":[{"type":"query_shard_exception","reason":"failed to find geo_point field [coordinates.location]" (...)
Maybe it comes from the query ? Query :
final BooleanJunction bool = queryBuilder.bool().must(queryBuilder.bool()
.should(...)
.should(...)
.should(queryBuilder
.spatial()
.onField("coordinates.location")
.within(12, Unit.KM)
.ofLatitude(form.getLatitude())
.andLongitude(form.getLongitude())
.createQuery())
.createQuery())
.must(...)
.must(...)
.must(...);
final FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(bool.createQuery(), Organization.class);
fullTextQuery.setMaxResults(form.getMaximumNumberOfResult());
fullTextQuery.setProjection(FullTextQuery.SPATIAL_DISTANCE, FullTextQuery.THIS);
fullTextQuery.setSpatialParameters(form.getLatitude(), form.getLongitude(), "coordinates.location");
fullTextQuery.setProjection(FullTextQuery.THIS, FullTextQuery.SCORE);
The field "coordinates" in Organization is @IndexedEmbedded and the Coordinates class is as you wrote it.
Upvotes: 1
Views: 515
Reputation: 9977
So, first, it's a bit odd that Hibernate Search managed to start up to begin with, because your mapping contains a mistake: you should set the name
attribute on the @Spatial
annotation. Then Hibernate Search will create a field in the Coordinates
type with that name (let's say "location").
Once that is done, you will be able to query that field from the Organization
type using the coordinates.location
name.
I know, it sounds a bit silly in this case, but generally the entity you put the @Spatial
annotation on is a business type, not something representing coordinates, so it makes more sense.
Another option would be to turn your Coordinates
type into an embeddable instead of an entity, make it implement org.hibernate.search.spatial.Coordinates
, and put the @Spatial
annotation on the Organization#coordinates
property instead of putting it on the Coordinates
type. Then you wouldn't need the @IndexedEmbedded
anymore nor the @Latitude
/@Longitude
, and you could actually just use the coordinates
field name when querying.
If the above doesn't work, please add the versions of Hibernate Search and Hibernate ORM you are using, and the code of the Organization
class.
EDIT: In answer to your edit...
About the @Latitude
/@Longitude
annotations not being found: you need to use the of
attribute of these annotations to match the name of your field.
If you do not switch to @Embeddable
, this would lead to something like this:
@Entity
@Table(name = "COORDINATES")
@Indexed
@Spatial(name = "location")
public class Coordinates implements Serializable {
private static final long serialVersionUID = 1L;
public Coordinates() {}
@Id
@Column(name = "id", nullable = false)
@SequenceGenerator(name = "generator", sequenceName = "COORDINATES_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
private Long id;
@Field
@Latitude(of = "location")
@Column(name = "LATITUDE", nullable = false)
private Double latitude;
@Field
@Longitude(of = "location")
@Column(name = "LONGITUDE", nullable = false)
private Double longitude;
}
About your "org.hibernate.AnnotationException" after switching to an embeddable: you need to remove the @ManyToOne
on the coordinates
attribute and replace it with @Embedded
. Embedded attributes are very different from associations, please have a look at the Hibernate ORM documentation.
Upvotes: 0