提示:这里简述项目相关背景:
最近在解决一个工作中关于elasticsearch查询的一个问题,改造点是由原来的十几个字段条件的模糊查询改为7个字段的精确查找,在进行自测的时候发现一个问题如下:
当我设置两个查询条件,字段A和字段B,然后编写DSL语句用于查询脚本如下:
GET test_index/_search
{
"from":0,
"size":30,
"query": {
"bool": {
"should": [
{
"bool": {
"should": [
{
"term": {
"name.keyword": {
"value": "测试名称01",
"boost": 1
}
}
},
{
"nested": {
"query": {
"term": {
"prins.hone": {
"value": "13000000001",
"boost": 1
}
}
},
"path": "prins",
"ignore_unmapped": false,
"score_mode": "sum",
"boost": 1
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
}
}
但是我使用java 的sdk使用相同的查询条件后得到的结果和kibana查询的数据有一些差别(查询出来的30条数据中有一些数据是相同的,但是有一些是不同),为什么会得到这样的结果呢,很奇怪。
在网上也找了一些资料,然后发现没什么有价值的东西,于是就在想,怎么能将sdk产生的dsl打印出来进行比较,于是配置了spring data elasticsearch的日志级别,如下:
# 日志配置
logging:
level:
#es日志
org.springframework.data.elasticsearch.client.WIRE:trace
打印出来的DSL如下:
经过逐个排查发现在增加了search_type=dfs_query_then_fetch 后和sdk查询的一致了,那么这个参数是干什么用的呢,源码中有SearchType这么一个枚举,就简单百度了一下:
1、query and fetch
向索引的所有分片(shard)都发出查询请求,各分片返回的时候把元素文档(document)和计算后的排名信息一起返回。这种搜索方式是最快的。因为相比下面的几种搜索方式,这种查询方法只需要去shard查询一次。但是各个shard返回的结果的数量之和可能是用户要求的size的n倍。
2、query then fetch(默认的搜索方式)
如果你搜索时,没有指定搜索方式,就是使用的这种搜索方式。这种搜索方式,大概分两个步骤,第一步,先向所有的shard发出请求,各分片只返回排序和排名相关的信息(注意,不包括文档document),然后按照各分片返回的分数进行重新排序和排名,取前size个文档。然后进行第二步,去相关的shard取document。这种方式返回的document与用户要求的size是相等的。
3、DFS query and fetch
这种方式比第一种方式多了一个初始化散发(initial scatter)计算全局词频(term frequencies)步骤,有这一步,据说可以更精确控制搜索打分和排名。先对所有分片发送请求, 把所有分片中的词频和文档频率等打分依据全部汇总到一块, 再执行后面的操作。优点很明显,数据量是准确并且排名也准确,但性能是最差的。
4、DFS query then fetch
比第2种方式多了一个初始化散发(initial scatter)计算全局词频(term frequencies)步骤,过程与上一种类似,优点是排名准确,但返回的数据量不准确,可能返回(N*分片数量)的数据。
有一点疑惑的是,那么默认是query then fetch,但是我用api确为什么是DFS query then fetch呢?看了一下代码没有地方设置这玩意
经过查看源码发现在NativeSearchQueryBuilder中会判断是否有SearchType参数,如果没有就不设置,不设置则实际使用了NativeSearchQuery父类AbstractQuery中的SearchType的默认值:DFS_QUERY_THEN_FETCH
在查询语句中添加参数search_type=dfs_query_then_fetch, 最后语句如下:
GET test_index/_search?search_type=dfs_query_then_fetch
{
"from":0,
"size":30,
"query": {
"bool": {
"should": [
{
"bool": {
"should": [
{
"term": {
"name.keyword": {
"value": "测试名称01",
"boost": 1
}
}
},
{
"nested": {
"query": {
"term": {
"prins.hone": {
"value": "13000000001",
"boost": 1
}
}
},
"path": "prins",
"ignore_unmapped": false,
"score_mode": "sum",
"boost": 1
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
}
}