es分享

一. 建立倒排索引认识

倒排索引是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射

1
2
3
4
1问: 说出带"前"字的古诗词
2问: 背一下李白的静夜思
`窗前明月光,疑是地上霜`
3问: 背诗的方式?按照书中排列顺序,先记诗名再记内容
1
4问: 具象化到关系库模型也就是如下
1
5问: 在脑子中形成的索引是这样的
1
2
3
4
5
6
7
8
6问: 在脑子里建立了name的索引, 关系库的表现方式就变成了如下
当问到根据name找content的时候就会很快
(sql: `select * from 古诗 where name = "静夜思";`)
但反过来问的时候就变成如下的查询
(sql: `select name from 古诗 where content like "%前%";`)
(这里不考虑覆盖索引)

7问: 如上所述,如果建立以"前"字作为索引查询,是不是解决了这个问题?(如下图)
1
2
3
4
8问: 上面所说索引建立模式解决了寻找慢的问题,那么新的问题来了,
`说出包含床字的古诗`
9问: 会发现整首古诗20字都适合做索引,光是唐诗就有5万多首,这样建立起索引脑子怕是会炸
10问: 但是既然已经可以通过诗名想起一首诗,那就没必要索引到content(诗词内容)了,直接索引到诗名就可以了(如下)
1
11问: 多首诗的可以这样

如上就是倒排索引的一个入门讲解

补充:

  1. ES 默认会对全部字段进行索引,如上面的古诗表,name也可以是个索引,author也可以是个索引
  2. 倒排索引的概念源自搜索引擎,最开始在lucene中被广泛认知和使用,而es则是在lucene的基础之上进行了包装和使用

二. 倒排索引的入门讲解完事儿,再来细究下这个倒排索引究竟啥样的,怎么存储的

  • es内部结构前置概念

term

1
如上面的古诗事例中,key所代表的就是一个term

postings list

1
2
3
4
还是用上面的例子,{静夜思, 望庐山瀑布}是 "前" 这个 term 所对应列表。
由于整型数字可以被高效压缩的特质(mysql也更推荐数字作为id,也是同样的道理),integer 是最适合放在 postings list 作为文档的唯一标识的,ES 会对这些存入的文档进行处理,转化成一个唯一的整型 id。
简而言之,Posting list就是一个int的数组,存储了所有符合某个term的文档id。
那上面的存储结构就变成下面这个样子

Term Dictionary

1
2
3
理解成一本新华字典,存上述所有term的新华字典
然后Elasticsearch为了能快速找到某个term,将所有的term排个序,
二分法查找term,就像通过字典查找一样,这就是Term Dictionary。

问题来了.Term Dictionary 存在哪?硬盘?io效率太慢了.肯定内存更合适
但是如果term太多,term dictionary也会很大,上面也说到了,es会对所有字段默认建立索引,直接存放在内存不现实,于是有了Term Index

Term Index

1
2
3
4
5
6
7
8
就像字典里的索引页一样,A开头的有哪些term,分别在哪页,可以理解term index是一颗树:

这棵树不会包含所有的term,它包含的是term的一些前缀。
通过term index可以快速地定位到term dictionary的某个offset,然后从这个位置再往后顺序查找。

所以term index不需要存下所有的term,而仅仅是他们的一些前缀与Term Dictionary的block之间的映射关系,
再结合FST(Finite State Transducers)的压缩技术,可以使term index缓存到内存中。
从term index查到对应的term dictionary的block位置之后,再去磁盘上找term,大大减少了磁盘随机读的次数。

三. 使用,结合生产讲使用

  1. es就是一个分布式存储的搜索和分析引擎
  2. es对外提供了一堆api,所有api都玩明白了,就相当于"会用"es了
  3. 如下是es7之后数据类型支持
  1. es和mysql的概念对比(type在8.0中将完全删除,目前处于待舍弃状态)
  1. ES支持两种基本方式检索;query dsl 和rest

  2. 以生产日志告警举例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    # 查询过去10分钟的错误日志
    es:(querydsl语法)
    GET prod-sopei-20211007/_search
    {
    "size": 100,
    "query": {
    "bool": {
    "must": [
    {
    "range": {
    "@timestamp": {
    "gte": "now-10m",
    "lte": "now"
    }
    }
    },
    {
    "match": {
    "logtype.keyword": "error"
    }
    }
    ]
    }
    }
    }
    mysql:
    `select * from prod-sopei-20211007 where @timestamp > DATE_SUB(NOW(),INTERVAL 10 MINUTE)and logtype = "error" limit 100`
  3. 其他的增删改查由于es的内容很多,这里不一一概述

四. 优化

不建议使用嵌套模型和父子模型-这两种方式是用来处理join

Elasticsearch性能优化总结-引自知乎