无法从休眠搜索中使用@Spatial查找geo_point字段

时间:2018-09-21 11:10:53

标签: elasticsearch hibernate-search hibernate-spatial

我需要实现一个旨在使用位置过滤我的搜索查询之一的解决方案。您将在这里找到我的实体以及我如何使用@Spatial注释:

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

   ...

}

索引没有发现任何错误,这是我使用elasticsearch查询找到的结果:

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
                   },
                   ...
               }
           }
       ]
   }
}

检查索引是否正常后,我尝试查询给定半径100km之内的所有Organization对象:

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

我的问题在这里,当我尝试执行此查询时,我有以下return语句:

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
}

要解决此问题,我尝试将名称设置为@Spatial记录,尝试使我的实体实现坐标,等等。但是,我总是得到相同的结果。看来hibernate-search没有将我的位置索引为geo_point,这是为什么它在查询中失败的原因...

您对我在文档中错过的内容有任何想法吗?

使用的版本::休眠:5.3;休眠搜索:5.10; elasticsearch:5.6

1 个答案:

答案 0 :(得分:0)

Elasticsearch映射错误:

    "com.supralog.lexis.model.organization.Organization" : {
        "properties" : {
            "_hibernate_default_coordinates" : {
                "properties" : {
                    "lat" : {
                        "type" : "float"
                    },
                    "lon" : {
                        "type" : "float"
                    }
                }
            },
            ...
        }
    }

“ _ hibernate_default_coordinates”下有一个“属性”属性,这意味着“ _hibernate_default_coordinates”属于“对象”类型,而应属于“ geo_point”类型。

最可能的解释是,您没有在索引编制之前生成架构,Elasticsearch尝试根据收到的文档即时自动生成它。如您所见,这是一个非常糟糕的主意,因为Elasticsearch猜测模式错误的风险非常高。

您应该看看documentation about configuration。特别是,您应该选择合适的index schema management strategy

简而言之,将以下内容放入hibernate.properties

在开发环境中:Hibernate Search会尽力而为,但是可能会失败,并且数据也不会神奇地重新索引,您必须自己动手

hibernate.search.default.elasticsearch.index_schema_management_strategy update

在生产环境中:您必须自己仔细更新架构,并在更新应用程序时计划mass reindexing

hibernate.search.default.elasticsearch.index_schema_management_strategy create