【问题标题】:Spring Data Elastic Search - Sort Geo Locations by distanceSpring Data Elastic Search - 按距离对地理位置进行排序
【发布时间】:2014-04-27 10:29:36
【问题描述】:

给定一个地理定位点,我试图在 10 公里内找到一些站点,并按最接近给定位置的位置对其进行排序。

我设法返回了 10 公里内的位置列表,但是当我尝试对其进行排序时,我得到了异常:

我正在使用以下版本:

<properties>
        <commonscollections>3.2.1</commonscollections>
        <commonslang>2.6</commonslang>
        <spring.data.elasticsearch>1.0.0.BUILD-SNAPSHOT</spring.data.elasticsearch>
        <springversion>3.2.5.RELEASE</springversion>
</properties>

java代码如下:

public List<SiteResource> findByGeoLocation(Double longitude, Double latitude, String channelKey, String distance) {

        if(StringUtils.isEmpty(distance)){
            distance = defaultRadius;           
        }       
        GeoPoint location = new GeoPoint(latitude, longitude);
        CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("location").within(location, distance+"km"));

        criteriaQuery.addIndices(channelKey);
        criteriaQuery.addTypes("site");

        criteriaQuery.addSort(new Sort(Sort.Direction.ASC, "location"));
        List<SiteResource> sites = esTemplate.queryForList(criteriaQuery, com.company.domain.site.SiteResource.class);
        return sites;
    }

如果我删除该行:

criteriaQuery.addSort(new Sort(Sort.Direction.ASC, "location"));

然后代码将返回所有位置,问题在于排序

我从 elasticsearch 日志得到的错误:

[2014-03-20 13:37:02,720][DEBUG][action.search.type       ] [Smuggler II] [210a9696a28545f2bbeecf88d64fbad8_20140318_153743][4], node[dB9dCIXMRZGmdUExquMWlQ], [P], s[STARTED]: Failed to execute [org.elasticsearch.action.search.SearchRequest@71b978fe] lastShard [true]
org.elasticsearch.search.SearchParseException: [210a9696a28545f2bbeecf88d64fbad8_20140318_153743][4]: query[ConstantScore(*:*)],from[0],size[-1]: Parse Failure [Failed to parse source [{"from":0,"query":{"match_all":{}},"post_filter":{"geo_distance":{"location":[-2.217753,53.432703],"distance":"10km"}},"sort":[{"location":{"order":"asc"}}]}]]
    at org.elasticsearch.search.SearchService.parseSource(SearchService.java:595)
    at org.elasticsearch.search.SearchService.createContext(SearchService.java:498)
    at org.elasticsearch.search.SearchService.createAndPutContext(SearchService.java:472)
    at org.elasticsearch.search.SearchService.executeDfsPhase(SearchService.java:178)
    at org.elasticsearch.search.action.SearchServiceTransportAction.sendExecuteDfs(SearchServiceTransportAction.java:168)
    at org.elasticsearch.action.search.type.TransportSearchDfsQueryThenFetchAction$AsyncAction.sendExecuteFirstPhase(TransportSearchDfsQueryThenFetchAction.java:85)
    at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction.performFirstPhase(TransportSearchTypeAction.java:216)
    at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction.performFirstPhase(TransportSearchTypeAction.java:203)
    at org.elasticsearch.action.search.type.TransportSearchTypeAction$BaseAsyncAction$2.run(TransportSearchTypeAction.java:186)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:701)
Caused by: org.elasticsearch.ElasticsearchIllegalArgumentException: can't sort on geo_point field without using specific sorting feature, like geo_distance
    at org.elasticsearch.index.fielddata.plain.AbstractGeoPointIndexFieldData.comparatorSource(AbstractGeoPointIndexFieldData.java:142)
    at org.elasticsearch.search.sort.SortParseElement.addSortField(SortParseElement.java:222)
    at org.elasticsearch.search.sort.SortParseElement.addCompoundSortField(SortParseElement.java:172)
    at org.elasticsearch.search.sort.SortParseElement.parse(SortParseElement.java:80)
    at org.elasticsearch.search.SearchService.parseSource(SearchService.java:583)
    ... 11 more
[2014-03-20 13:37:02,722][DEBUG][action.search.type       ] [Smuggler II] All shards failed for phase: [dfs]

如果有人告诉我是否可以按离我最近的位置对位置进行排序,我非常感谢。

提前致谢

【问题讨论】:

    标签: java elasticsearch spring-data


    【解决方案1】:

    以防其他人遇到同样的问题,我们已通过以下方式解决了排序问题:

    public List<SiteResource> findByGeoLocation(Double longitude, Double latitude, String channelKey, Double distance) {
    
            if(StringUtils.isEmpty(distance)){
                distance = defaultRadius;           
            }
    
            GeoDistanceFilterBuilder filter = FilterBuilders.geoDistanceFilter("location").point(latitude, longitude).distance(distance, DistanceUnit.KILOMETERS);
    
            SearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withFilter(filter)
                    .withSort(SortBuilders.geoDistanceSort("site.location").point(latitude, longitude).order(SortOrder.ASC)).build();
    
            searchQuery.addIndices(channelKey);
            searchQuery.addTypes("site");
    
            List<SiteResource> sites = esTemplate.queryForList(searchQuery, com.company.domain.site.SiteResource.class);
            return sites;
        }
    

    希望对某人有所帮助;)

    【讨论】:

    • 顺便说一下,您不需要定义 elasticsearch 版本,因为它将作为 spring data elasticsearch 的瞬态依赖。
    • 你说得对,我刚刚从问题中删除了它
    【解决方案2】:

    来自@justMe 的答案有助于找到实现地理距离搜索的最新可能性。 由于过滤器和查询已合并,我们可以改为使用 QueryBuilder。

    这是我获得结果的方式(排序和分页):

      public List<EsEntity> findByGeoLocationSorted(Double latitude, Double longitude,
          Double distance, String sort, Pageable pageable) {
    
        GeoDistanceQueryBuilder filter = QueryBuilders.geoDistanceQuery("geoPoint")
            .point(latitude, longitude).distance(distance, DistanceUnit.KILOMETERS);
    
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(filter).withPageable(pageable)
            .withSort(SortBuilders.geoDistanceSort("geoPoint", latitude, longitude).order(
                SortOrder.fromString(sort))).build();
    
        Page<EsEntity> page = elasticsearchRestTemplate
            .queryForPage(searchQuery, EsEntity.class);
        if (page.hasContent()) {
          return page.getContent();
        }
        return Collections.emptyList();
      }
    

    "geoPoint" -> elasticsearch 实体中的 GeoPoint 字段。

    【讨论】:

      【解决方案3】:

      游戏已经很晚了,但是自从上周发布的 Spring Data Elasticsearch 4.0 以来,可以选择为 Sort 定义一个 GeoDistanceOrder,它可以传递给存储库方法。

      搜索结果的距离值可以从返回的SearchHit对象中读取。

      wrote a blog post 详细展示了如何做到这一点

      【讨论】:

      • PJ,那个帖子看起来不错,让我试试 :)
      猜你喜欢
      • 1970-01-01
      • 2015-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      相关资源
      最近更新 更多