要完成上述图片上的查询条件,也即需要同时符合多种过滤条件。
由于公司的服务器中安装的elasticsearch版本很老,升级不是很方便,所以是基于老版本,新版本相应的语句做一些改变也可以。
实现:(具体条件需要更改)(elasticsearch版本:2.3.2)
潜在优化:
1. "should": [
{"match_phrase": {"termID": "00:23:A5:30:45:AD"}},
{"match_phrase": {"material_id": "1520"}},
{"match_phrase": {"material_id": "1521"}}
],
"minimum_should_match": 2,
这个匹配可能是比较耗时的,采用match_phrase主要是因为低版本string类型,且创建index时,没有设置为not_anlyzed。
改成not_anlyzed(新版本用keyword类型,index=true),用filter - terms也许效率会提升;
2. 按项目而不是日期来定义索引,这样搜索范围将会大大缩小;
3. 采用最新版本elasticsearch,采用painless语言。
补充:
1. version:6.3(改良优化后)的实现代码:
2. 日期范围限定、字符串排序还可以通过keyword属性来很方便地实现:
curl -XGET 'localhost:9200/doc.default.terminal_crash/_search?pretty' -H 'Content-Type: application/json' -d'
{
"sort": {
"level.keyword": {
"order": "desc"
}
},
"query" : {
"bool" : {
"filter": {
"range" : {
"when.keyword" : {
"from" : "2019-12-29 00:00:00", "to" : "2019-12-31 00:00:00"
}
}
}
}
}
}
'
3. Java版本的示例(由于业务不一样,所以与本例的查询条件不一样,但是可以参考):
public MyResponse searchPlayRecords(Date startDate, Date endDate, String mac, String keyword, MyPage page) throws Exception {
// 排序条件
FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("end_time.keyword").order(SortOrder.DESC);
// 查询条件
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchPhraseQuery("device_id", mac));
if (keyword != null && !keyword.trim().isEmpty()) {
keyword = "*" + keyword.trim().toLowerCase() + "*";
queryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.wildcardQuery("name", keyword))
.should(QueryBuilders.wildcardQuery("channel_name", keyword)));
}
// 执行条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().sort(fieldSortBuilder).from((page.getNumber() - 1) * page.getSize())
.size(page.getSize()).query(queryBuilder);
if (startDate.compareTo(endDate) >= 0) return new MyResponse(MyStatusCode.DATE_SRART_EXCEED_END, "");
String[] indice = esService.buildDateIndice(startDate, endDate);
return new MyResponse(esService.searchRecords(indice, searchSourceBuilder));
}
说明:在startDate到endDate日期区间内,按照end_time逆序排序,对name和channel_name两个字段模糊查询关键字(两者中有一个包含keyword)。
public MyResponse searchOperationRecords(String startDate, String endDate, String operator, String operand, MyPage page) throws Exception {
// 排序条件
FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("time").order(SortOrder.DESC);
// 查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.rangeQuery("time").gt(DateUtils.parseDate(startDate, "yyyy-MM-dd HH:mm:ss").getTime())
.lt(DateUtils.parseDate(endDate, "yyyy-MM-dd HH:mm:ss").getTime()));
if (operator != null) boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("operator", operator));
if (operand != null) boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("operand", operand));
// 执行条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().sort(fieldSortBuilder).from((page.getNumber() - 1) * page.getSize())
.size(page.getSize()).query(boolQueryBuilder);
String[] indice = { "doc." + springService.getHeader("PROJECT") + ".terminal_operation" };
return new MyResponse(esService.searchRecords(indice, searchSourceBuilder));
}
说明:在startDate到endDate日期区间内,按照time逆序,不分词匹配词语operator,operand。
public MyResponse searchCrashDates(String mac, String dateString) throws Exception {
String monthDateString = dateString.substring(0, 8);
// 查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("device_id", mac)).must(QueryBuilders.matchPhraseQuery("date", monthDateString));
// 执行条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().size(0).query(boolQueryBuilder)
.aggregation(AggregationBuilders.terms("DateAggs").field("day.keyword"));
String[] indice = { "doc." + springService.getHeader("PROJECT") + ".terminal_crash" };
JSONObject aggregation = esService.aggregateRecords(indice, searchSourceBuilder, "DateAggs");
return new MyResponse(aggregation.keySet());
}
说明:根据day聚合,不分词匹配词语device_id,date。