2014-02-14 58 views
4

我對elasticsearch和spring-data-elasticsearch是一個相當新的東西,並且我在查詢嵌套對象時遇到了一些問題。使用標準嵌套對象的spring-data-elasticsearch

我使用ElasticSearch存儲庫在elasticsearch中保存嵌套的模型實例。因此,在包含所有數據的elasticsearch中只有一個條目,據我的理解,這意味着我有一個嵌套文檔。

我需要使用Criteria實現一個相對複雜的查詢來迭代建立查詢。 當我嘗試訪問使用點符號的嵌套屬性像

startPoint.providingTimeRange.startTime 

我沒有得到任何搜索結果(但匹配的數據存在於elasticsearch)。

Spring Data Elastic Search with Nested Fields and mapping我發現了spring-data-elasticsearch使用nestedQuery查詢嵌套對象的能力。

有什麼方法可以將Criteria搜索與嵌套查詢結合起來嗎?

謝謝你在前進, 克里斯托夫

更新1: 提供我創建包含在我真正的項目像類似的嵌套對象演示項目的一些示例代碼:https://github.com/empulse-gmbh/elasticsearchtest

的例子是即將找到在某個特定時間位於特定位置的FoodTrucks。

在這個例子中,我使用了一個Repository來保存我的嵌套實體。

我用了兩個(兩者不工作)的方法來查詢嵌套對象:

 /* 
     * add search criteria by timerange. it is assumed in timerange from 
     * is always before to. 
     */ 
     TimeRange searchTimeRange = foodTruckSearch.getSearchTimeRange(); 
     if (searchTimeRange != null) { 

      String startTimePath = "locationPoint.timeRange.from"; 
      String endTimePath = "locationPoint.timeRange.to"; 

      searchCriteria = searchCriteria.and(
        new Criteria(startTimePath).between(searchTimeRange 
          .getFrom().getTime(), searchTimeRange.getTo() 
          .getTime())).or(
        new Criteria(endTimePath).between(searchTimeRange 
          .getFrom().getTime(), searchTimeRange.getTo() 
          .getTime())); 
     } 

和:

TimeRange searchTimeRange = foodTruckSearch.getSearchTimeRange(); 
    if (searchTimeRange != null) { 

     String startTimePath = "locationPoint.timeRange.from"; 
     String endTimePath = "locationPoint.timeRange.to"; 

     searchQuery.must(nestedQuery(
       "locationPoint", 
       boolQuery().should(
         rangeQuery(startTimePath).from(
           searchTimeRange.getFrom().getTime()).to(
           searchTimeRange.getTo().getTime())).should(
         rangeQuery(endTimePath).from(
           searchTimeRange.getFrom()).to(
           searchTimeRange.getTo())))); 

    } 

UPDATE2: 感謝穆赫辛·胡森我能夠使用嵌套搜索。時間範圍的搜索現在可用。 此外,以穆赫辛的建議,我不得不改變創建和啓動本地Elasticsearch實例的方式:

elasticSearchNode = NodeBuilder.nodeBuilder().clusterName("foodtruck-test").local(true).build(); 

沒有給人不創建中的羣集文件嵌套。

我的下一個(希望是最後一個)問題是使用geo_distance搜索過濾器。如果我在Elasticsearch中正確使用了查詢,我會使用像'like'或'range'這樣的模糊搜索查詢以及yes/no或distance過濾器的過濾器。

所以我嘗試使用QueryBuilder和FilterBuilder與spring-data-elasticsearch一起失敗。

根據文檔中的示例,我重構了我的模型,因此Location類使用spring-data-elasticsearch對象GeoPoint。

搜索我用這個:

/* 
    * add search criteria for radius search 
    */ 
    FilterBuilder searchFilter = null; 
    if (foodTruckSearch.getLatitude() != null 
      && foodTruckSearch.getLongitude() != null) { 

     if (foodTruckSearch.getSearchRadiusInKilometers() == null) { 
      foodTruckSearch.setSearchRadiusInKilometers(5); 
     } 

     searchFilter = geoDistanceFilter("location.point") 
       .distance(
         foodTruckSearch.getSearchRadiusInKilometers() 
           + "km").lat(foodTruckSearch.getLatitude()) 
       .lon(foodTruckSearch.getLongitude()); 

    } 

    if (searchFilter != null) { 
     NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(
       searchQuery, searchFilter); 
     return IteratorUtils.toList(foodTruckRepository.search(
       nativeSearchQuery).iterator()); 
    } else { 
     return IteratorUtils.toList(foodTruckRepository.search(searchQuery) 
       .iterator()); 
    } 

我得到的例外是:(?嵌套)

org.elasticsearch.action.search.SearchPhaseExecutionException: Failedtoexecutephase[query_fetch], 
allshardsfailed;shardFailures{ 
    [1][searchexample][0]: SearchParseException[[searchexample][0]: query[MatchNoDocsQuery], 
    from[0], 
    size[10]: ParseFailure[Failedtoparsesource[{ 
    "from": 0, 
    "size": 10, 
    "query": { 
     "bool": { 

     } 
    }, 
    "post_filter": { 
     "geo_distance": { 
      "location.point": [6.9599115, 
      50.9406645], 
      "distance": "10km" 
     } 
    } 
}]]];nested: QueryParsingException[[searchexample]failedtofindgeo_pointfield[location.point]] ; 
} 

是否有可用的如何使用geo_distance任何例如過濾器與彈簧數據elasticsearch ?

+0

請分享一些代碼,以便我們可以幫助您解決問題。即實體和搜索請求等 –

+0

@MohsinHusen請參閱我的Update1,一個完整的演示項目現在可用 – flexguse

回答

1

異常被賦予一個默認的映射器在

return new ElasticsearchTemplate(elasticSearchNode.client()); 

導致刪除此錯誤映射造成彈簧數據elasticsearch把正確映射到Elasticsearch。

如果你想有一個啓用實體geo_distance搜索使用

@GeoPointField 

註釋標記包含經/緯度值的字段。

此外,FoodTruckServiceImpl更改爲使用過濾器,而不是查詢。

GitHub中的項目已更新,是一個功能完整的示例。隨意使用FoodTruck示例來進行spring-data-elasticsearch的第一步。

2

沒有詳細閱讀中,我抓住了一些問題,在您的代碼如下

1)當你正在使用多級嵌套的文件,你必須使用快照版本(您正在使用)彈簧數據elasticsearch M1版本有bug修復。 (https://jira.springsource.org/browse/DATAES-53

2)您聲明嵌套類型錯在你的實體,它必須作爲跟隨

@Field(type=FieldType.Nested) 
    private LocationPoint locationPoint; 

    @Field(type = FieldType.Nested) 
    private TimeRange timeRange; 

3)標準的查詢不會處理嵌套的對象,它是專爲處理簡單的實體因爲它使用query_string來查詢數據。因此請使用elasticsearchTemplate或存儲庫來查詢嵌套對象。

4)您必須指定爲嵌套對象

例如完整路徑,而尋找locationPoint.timeRange.from和locationPoint.timeRange.to你必須使用如下

String startTimePath = "locationPoint.timeRange.from"; 
    String endTimePath = "locationPoint.timeRange.to"; 

    searchQuery.must(nestedQuery(
      "locationPoint.timeRange", 
      boolQuery().should(
        rangeQuery(startTimePath).from(
          searchTimeRange.getFrom().getTime()).to(
          searchTimeRange.getTo().getTime())).should(
        rangeQuery(endTimePath).from(
          searchTimeRange.getFrom()).to(
          searchTimeRange.getTo())))); 

希望這將解決你的問題。

+0

非常感謝,工作。請看看我的更新2 – flexguse