Elasticsearch 结构化搜索_filter执行原理深度剖析(bitset机制与caching机制)与过滤查询

结构化搜索_filter执行原理深度剖析(bitset机制与caching机制)
1. 在倒排索引中查找搜索串,获取document list

解析:
date举例:倒排索引列表,过滤date为2017-02-02(filter:2017-02-02)。
去倒排索引中查找,发现2017-02-02对应的document list是doc2、doc3。

worddoc1doc2doc3
2017-01-01**
2017-02-02**
2017-03-03***
2. 为每个在倒排索引中搜索到的结果,构建一个bitset,[0, 0, 0, 1, 0, 1](非常重要

解析:

  1. 使用找到的document list,构建一个bitset(二进制数组,用来表示一个document对应一个filter条件是否匹配;匹配为1,不匹配为0)
  2. 为什么使用bitset:尽可能用简单的数据结构去实现复杂的功能,可以节省内存空间、提升性能。
  3. 由上步的document list可以得出该filter条件对应的bitset为:[0, 1, 1];代表着doc1不匹配filter,doc2、doc3匹配filter。
3. 遍历每个过滤条件对应的bitset,优先从最稀疏的开始搜索,查找满足所有条件的document

解析:

  1. 多个filter组合查询时,每个filter条件都会对应一个bitset。
  2. 稀疏、密集的判断是通过匹配的多少(即bitset中元素为1的个数)[0, 0, 0, 1, 0, 0] 比较稀疏、[0, 1, 0, 1, 0, 1] 比较密集 。
  3. 先过滤稀疏的bitset,就可以先过滤掉尽可能多的数据。
  4. 遍历所有的bitset、找到匹配所有filter条件的doc。
    请求:filter,postDate=2017-01-01,userID=1;
    postDate:[0, 0, 1, 1, 0, 0]
    userID:[0, 1, 0, 1, 0, 1]
    遍历完两个bitset之后,找到的匹配所有条件的doc,就是doc4。
  5. 将得到的document作为结果返回给client。
4. caching bitset,跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset。对于小segment(<1000,或<3%),不缓存bitset

解析:

  1. 比如postDate=2017-01-01,[0, 0, 1, 1, 0, 0];可以缓存在内存中,这样下次如果再有该条件查询时,就不用重新扫描倒排索引,反复生成bitset,可以大幅提升性能。
  2. 在最近256个filter中,有某个filter超过一定次数,次数不固定,就会自动缓存该filter对应的bitset。
  3. filter针对小segment获取的结果,可以不缓存,segment记录数<1000,或者segment大小<index总大小的3%(segment数据量很小,此时哪怕是扫描也很快;segment会在后台自动合并,小segment很快就会跟其他小segment合并成大segment,此时缓存没有多大意义,因为segment很快就会消失)。
  4. filter比query的好处就在于有caching机制,实际上并不是一个filter返回的完整的doc list数据结果,而是filter bitset缓存起来便于下次不用扫描倒排索引。

segment查看Elasticsearch Java API 的使用(14)—优化索引创建之setting设置、写入优化

5. filter大部分情况下,在query之前执行,先尽量过滤尽可能多的数据
  • query:要计算doc对搜索条件的relevance score,还会根据这个score排序。
  • filter:只是简单过滤出想要的数据,不计算relevance score,也不排序。
6. 如果document有新增或修改,那么cached bitset会被自动更新

示例:postDate=2017-01-01,filter:[0, 0, 1, 0]

  • 新增document,id=5,postDate=2017-01-01;会自动更新到postDate=2017-01-01这个filter的bitset中,缓存要会进行相应的更新。postDate=2017-01-01的bitset:[0, 0, 1, 0, 1]。
  • 修改document,id=1,postDate=2016-01-31,修改为postDate=2017-01-01,此时也会自动更新bitset:[1, 0, 1, 0, 1]。
7. 以后只要是由相同的filter条件的,会直接使用该过滤条件对应的cached bitset

比如postDate=2017-01-01,[0, 0, 1, 1, 0, 0];可以缓存在内存中,这样下次如果再有该条件查询时,就不用重新扫描倒排索引,反复生成bitset,可以大幅提升性能。

Filter查询

filter是不计算相关性的,同时可以cache。因此,filter速度要比query快。

创建索引并写入数据

POST /lib4/items/_bluk
{"index": {"_id": 1}}
{"price" 40, "itemID": "ID100123"}
{"index": {"_id": 2}}
{"price" 50, "itemID": "ID100124"}
{"index": {"_id": 3}}
{"price" 25, "itemID": "ID100125"}
{"index": {"_id": 4}}
{"price" 30, "itemID": "ID100126"}
{"index": {"_id": 5}}
{"price" null, "itemID": "ID100127"}

filter查询

GET /lib4/items/_search
{
    "query": {
        "bool": {
            "filter": {
                "term": {
                    "price": 40
                }
            }
        }
    }
}

GET /lib4/items/_search
{
    "query": {
        "bool": {
            "filter": {
                "terms": {
                    "price": [25, 40]
                }
            }
        }
    }
}

将无法查出结果,因为创建索引时时选择动态生成mapping,
itemID设定的type是text类型(默认分词),因为分词的策略ID100123将会变成id100123。

  • 解决方法一:创建索引时自行设定mapping;
  • 解决方法二:将查询条件改为id100123进查询;
GET /lib4/items/_search
{
    "query": {
        "bool": {
            "filter": {
                "term": {
                    "itemID": "ID100123"
                }
            }
        }
    }
}
bool组合查询

bool 可以实现组合过滤查询,相当与将多个条件组合在一起进行查询。
格式:

{
    "bool": {
        "must": [],
        "should": [],
        "must_not": []
    }
}

must:必须满足的条件,相当于and
should:可以满足、可以不满足的条件,相当于or
must_not:不需要满足的条件

GET /lib4/items/_search
{
    "query": {
        "bool": {
            "should": [
                {
                    "term": {
                        "price": 25
                    }
                },
                {
                    "term": {
                        "itemID": "ID100123"
                    }
                }
            ],
            "must_out": {
                "term": {
                    "price": 30
                }
            }
        }
    }
}

# bool嵌套查询
GET /lib4/items/_search
{
    "query": {
        "bool": {
            "should": [
                {
                    "term": {
                        "itemID": "ID100123"
                    }
                },
                {
                    "bool": {
                        "must": [
                            {
                                "term": {
                                    "itemID": "ID100124"
                                }
                            },
                            {
                                "term": {
                                    "price": 40
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}
范围过滤

gt:表示大于,等同符号 >
lt:表示小于,等同符号 <
gte:表示大于等于,等同符号 >=
lte:表示小于等于,等同符号 <=
需要配合range进行使用

GET /lib4/items/_search
{
    "query": {
        "bool": {
            "filter": {
                "range": {
                    "price": {
                        "gt": 25,
                        "lt": 50
                    }
                }
            }
        }
    }
}
过滤非空

使用exists可以进行非空过滤

GET /lib4/items/_search
{
    "query": {
        "bool": {
            "filter": {
                "exists": {
                    "field": "price"
                }
            }
        }
    }
}

GET /lib4/items/_search
{
    "query": {
        "constant_score": {
            "filter": {
                "exists": {
                    "field": "price"
                }
            }
        }
    }
}

当我们不关心检索词频率TF(Term Frequency)对搜索结果排序的影响时,可以使用constant_score将查询语句query或者过滤语句filter包装起来。
检索词频率:检索词在该字段出现的频率。出现频率越高,相关性也越高。字段中出现过5次要比只出现过1次的相关性高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值