Marie
Marie

Reputation: 51

Hibernate Search : The field () used for the spatial query is not configured as spatial field

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)


Edit 1

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;
    }
}

Edit 2

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

Answers (1)

yrodiere
yrodiere

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

Related Questions