序号 | 内容 | 链接地址 |
---|---|---|
1 | SpringBoot整合Elasticsearch7.6.1 | https://blog.csdn.net/miaomiao19971215/article/details/105106783 |
2 | Elasticsearch Filter执行原理 | https://blog.csdn.net/miaomiao19971215/article/details/105487446 |
3 | Elasticsearch 倒排索引与重建索引 | https://blog.csdn.net/miaomiao19971215/article/details/105487532 |
4 | Elasticsearch Document写入原理 | https://blog.csdn.net/miaomiao19971215/article/details/105487574 |
5 | Elasticsearch 相关度评分算法 | https://blog.csdn.net/miaomiao19971215/article/details/105487656 |
6 | Elasticsearch Doc values | https://blog.csdn.net/miaomiao19971215/article/details/105487676 |
7 | Elasticsearch 搜索技术深入 | https://blog.csdn.net/miaomiao19971215/article/details/105487711 |
8 | Elasticsearch 聚合搜索技术深入 | https://blog.csdn.net/miaomiao19971215/article/details/105487885 |
9 | Elasticsearch 内存使用 | https://blog.csdn.net/miaomiao19971215/article/details/105605379 |
10 | Elasticsearch ES-Document数据建模详解 | https://blog.csdn.net/miaomiao19971215/article/details/105720737 |
filter底层原理涉及到两块内容: bitset机制和cache机制。
假设现在有一批数据的倒排索引如下:
Word | Docs |
---|---|
2016 | 1,4,5,6 |
2017 | 1,2,4,5,6 |
2018 | 1,2,3 |
2019 | 2,3,4,5,6 |
2020 | 5 |
搜索时,使用的filter条件如下:
GET /search
{
"query": {
"constant_score": {
"filter": {
"term": {
"field": 2016
}
}
}
}
}
首先,ES会从index的倒排索引中遍历Word,找到2016对应的符合搜索条件的Docs——“1,4,5,6”。
接着,ES会将"1,4,5,6"构造成一个bitset。bitset是一个二进制数组,数组的下标对应着document数据存储(插入)的顺序,数组的容量由document的数量来决定,在bitset中,0代表不符合搜索条件,1代表符合搜索条件。
比如本例中,ES将会构建一个容量为6的二进制数组,假设document插入的顺序为5,2,4,6,1,3,那么当前filter对应的bitset数组内的组成情况是: [1,0,1,1,1,0]
一次搜索中,可能会出现多个filter,每一个filter都会对应一个bitset。ES会从最稀疏的bitset开始遍历,以达到最佳的执行效率。
bitset的稀疏性指的是包含符合过滤条件的document的数量,可以从bitset数组内1的数量体现出来。比如[1,0,1,1,1,0] 就比[1,1,1,1,1,1,]要更稀疏。
为什么从最稀疏的bitset开始过滤?因为过滤的目的是为了筛选出符合条件的数据,丢弃无用的数据。bitset越稀疏,代表筛选条件越严格,本次过滤的垃圾数据就越多。
ES5中,query内不能直接连接filter,query和filter之间需要通过bool来间隔。ES7中,and不能写在query中,所以坦白说,目前我没有发现一次搜索中出现多个filter的写法。况且完全可以在一个filter内通过bool条件达到写多个过滤条件的目前,因此没必要写多个filter
ES会缓存bitset数据到内存中,如果后续的搜索语句中filter过滤条件在之前已经使用过,那么ES会从缓存中直接找到对应的bitset,并根据bitset数组的内容,直接通过_id搜索目标document并返回结果集。ES缓存的是bitset数组,而不是通过filter搜索出的结果。
不是所有的bitset都会被ES缓存到内存中,不进行缓存的bitset大致分为以下两种情况:
情况1: 整个index内存储document的数量不足1000条。
情况2: 索引分段后的数据不足索引中所有数据的3%。
正是因为bitset缓存,使得filter的执行效率比不使用filter时query要高。
注意: ES在缓存bitset的同时,会返回搜索结果。换句话说,"缓存"和"根据bitset的内容查询、返回结果集"这两步操作是并发执行的。
一般来说,ES会优先执行filter,,通过filter过滤掉一部分不符合搜索条件的数据,再执行query。况且query需要计算相关度分数来进行排序,因此执行效率低。如果先执行query,那么就会把那些不符合搜索条件的数据也进行了相关度分数计算,浪费性能。
ES缓存的bitset后,不会置之不理。如果有修改、新增、删除操作,导致原先fitler对应的bitset结构或内容发生变化时,ES会及时的更新内存中缓存的bitset,值得注意的是,这个更新操作由ES自动完成。
只要ES中执行的query内包含filter,那么ES首先就会在缓存中搜索该filter条件是否曾经执行过,有没有对应的bitset缓存存在,若有,则使用缓存,若没有,则创建bitset,查询、返回数据,同时缓存bitset。