这里写自定义目录标题
Elasticsearch介绍
- ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口操作ES,也可以利用Java API。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
- Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
- Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
功能和场景
功能
- 分布式的搜索引擎和数据分析引擎
- 全文检索,结构化检索,数据分析
- 对海量数据进行近实时的处理
场景
- 搜索(百度、维基百科等)
- 数据分析(日志数据分析,logstash采集日志等)
Elasticsearch基本概念
上图为我在fat环境下随便查询到的一个文档,可以看到有_index、_type、_id、_version等字段,大家对关系型数据库理解都较为熟悉,我以mysql为例进行对照说明
– | ||||
---|---|---|---|---|
MySQL | 数据库 | 表 | 行 | 列 |
ES | 索引 | 类型 | 文档 | 段 |
- _index:soa-info-fat-error-2020.08.17 相当于数据库
- _type:logs 相当于表
- _id:AXP4An2QVy6wWtAsJml9 相当于表中唯一表示符(唯一主键)
- 上图中所有的信息构成一个文档,相当于表中一行数据,es是面向文档的数据库
- 像traceId、method等这样的相当于表中的列或者说字段。
一个 集群可以包含多个索引(数据库),也就是说其中包含了很多类型(表)。这些类型中包含了很多的文档(行),然后每个文档中又包含了很多的字段(列)。
引出倒排索引
索引一词较为出现评率较高的场景是在关系型数据库的查询中。索引的作用是加快数据查询。以MySQL为例,当一个表中出现亿量单位条数据时,如果通过全表查询时间复杂度是相当高的,因此为了提升查询效率对关键字段建立索引,MySQL中以B+Tree数据结构建立索引。我们假设某表中有10条数据,其中ID为索引字段,数据如下:
ID | name | age | sex | interests |
---|---|---|---|---|
1 | zhangsan | 18 | male | sports, music |
2 | lisi | 20 | male | football,music,movie |
3 | xiaohong | 18 | female | music,book,sports |
4 | liming | 21 | female | piano,novel |
5 | wangwu | 20 | male | game,movie |
… |
当MySQL以ID建立索引时,其结构可能如下。在查询id=?时最多查询两次即可。
现有需求如下:统计男女各有多少人数,统计兴趣有music的有谁,在没有建立索引的情况下需要全表扫描了,时间较高。如果对每个字段建立索引是不现实的,这会加大表维护的代价。因此,可以使用inverted index(倒排索引或者转置索引) 顾名思义,其以内容对数据进行索引。以性别和兴趣为例子,
age | id |
---|---|
18 | [1,3,…] |
20 | [2,5,…] |
21 | [4,…] |
… |
interests | id |
---|---|
sports | [1,3,…] |
music | [1,2,3,…] |
movie | [2,5,…] |
… |
此时统计找到age=18或者interests包含sports,是非常省时的。
以上为提升查询效率的第一步
Term查询优化
像18、20、sports、music、male、female等单个字段叫做term,所有的字段叫term dictionary 。[1,3,…]叫做posting list是一个数组。
如果有大量的term进行存储,如果通过顺序遍历,时间也是非常大的,同样为了加快Term的查询,es将二分法加入到查询term中并且为了提升查询效率引入term index查询和fst压缩技术。
Term index技术实质为trie tree(字典树),上面term没有典型性,现假设有单词abcd,abd,b,bcd,efg,hij利用字典树则建立结果如下所示,红色节点为标记(结束)节点,且有对应term dictionary的指针。这样在查找abcd所对应的id时,步骤为:
- 查询字典树
- 如果查到标记节点,则定位到term dictionary的offset
- 根据term dictionary查询到对应的posting list
注:底层还通过fst对trie tree进行了压缩,使其大小仅为原来的十几分之一
Posting list
上面讲了对term优化,下面对posting list进行优化。如果ID数组较长,则也需要一定内存,为了尽可能的减少使用
Frame Of Reference
增量编码压缩,将大数变小数,按字节存储。首先posting list是有序的,假设有如下id:73,300,302,332,343,372。采用增量压缩结果如下:可以看到在step2中第n(n>1)个数实际值为前n项相加。在step3中将值按照一定大小分组,在第一组中最大227,用8bit即可,因此3*8bit=3byte,只需要3字节,第二组最大29用5bit,因此只用2字节。这样操作不用每个数字用integer(4字节)存储,大大减少了空间。其实还可以对空间进行压缩。
bitmap
位图,1byte即可表示8个数字,比如有1,2,3,4,5,6,7,8假如用3bit表示每一位数字,8*3=3byte。而用bitmap可表示为[1,1,1,1,1,1,1,1]。如果是大数可节省更多空间。1亿个连续正整数大约需要12.5m空间(100000000/8/1024/1024)
Roaring bitmaps
bitmap的升级版,上面说了1亿个数字还需要12.5m,随着数据的增长id也在增长,势必带来空间的使用,roaring bitmaps进一步设定规则,它将每个数字除65535,这样将会变成(商,余数)。将商一样的分组,每组的余数作为id,这样每组的id就不会超过65536,而且每组中数字存储也会进行分组,如果数字大于4096就用bitset存储,小于4096就用short存储。如图
注1 为什么用65536,2^16-1=65535正好为short存储字节数,占用空间少。
注2 为什么每块用4096个数区分阈值,因为每块中最大值为65536,假设里面全部用bit set存储,65536bit/8/1024=8kb,那么假设有4096个数,每个数用short存储 2byte*4096/1024=8k,下面用图对比一下使用空间情况
转载/参考
https://www.elastic.co/guide/cn/elasticsearch/guide/2.x/index.html
https://www.cnblogs.com/dreamroute/p/8484457.html
https://www.elastic.co/cn/blog/frame-of-reference-and-roaring-bitmaps
es操作官方文档 这是2.x 虽然有些语法变了 但是问题不大
https://www.elastic.co/guide/cn/elasticsearch/guide/2.x/index.html