我对弹性搜索和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搜索与nestedQuery结合起来?
提前谢谢你, 克里斯托弗
更新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: 感谢Mohsin Husen,我能够使用嵌套搜索。按时间范围搜索现在有效。 除了Mohsin的建议,我还必须改变创建和启动本地Elasticsearch实例的方式:
elasticSearchNode = NodeBuilder.nodeBuilder().clusterName("foodtruck-test").local(true).build();
如果不给出clusterName,则不会创建嵌套文档。
我的下一个(希望是最后一个)问题是使用geo_distance搜索过滤器。如果我在Elasticsearch中得到了正确的答案,我会使用“类似”或“范围”之类的模糊搜索查询以及是/否或距离过滤器的过滤器。
所以我尝试将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]] ;
}
有没有可用的例子如何使用spring-data-elasticsearch的geo_distance(嵌套?)过滤器?
答案 0 :(得分:2)
如果没有详细阅读,我会在您的代码中发现一些问题,如下所示
1)当您使用多级嵌套文档时,您必须使用快照版本(您正在使用)作为弹簧数据弹性搜索M1版本具有已修复的错误。 (https://jira.springsource.org/browse/DATAES-53)
2)您在实体中声明嵌套类型错误,必须如下
@Field(type=FieldType.Nested)
private LocationPoint locationPoint;
@Field(type = FieldType.Nested)
private TimeRange timeRange;
3)Criteria查询不会处理嵌套对象,它是为处理简单实体而构建的,因为它使用query_string来查询数据。因此,使用elasticsearchTemplate或repository来查询嵌套对象。
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()))));
希望这能解决您的问题。
答案 1 :(得分:1)
异常是由
中的默认映射器引起的return new ElasticsearchTemplate(elasticSearchNode.client());
删除这个错误的映射器会导致spring-data-elasticsearch将正确的映射放入Elasticsearch。
如果您想为geo_distance搜索启用实体,请使用
@GeoPointField
注释,用于标记包含纬度/经度值的字段。
此外,FoodTruckServiceImpl已更改为使用过滤器,而不是查询。
GitHub中的项目已更新,是一个功能齐全的示例。尽可能使用FoodTruck示例进行spring-data-elasticsearch的第一步。