1、说说 Elasticsearch 的搜索与聚合在数据存储结构方面的理解。
1)Elasticsearch 在搜索时,采用的是倒排索引(也称反向索引)。即将文档的所有内容通过分析、过滤、转化等操作抽取关键字,然后建立一个按字符顺序排列的关键字列表。
假设有两篇文章:
文章1的内容是: Tom lives in Guangzhou, I live in Guangzhou too.
文章2的内容是: He once lived in Shanghai.
文章内容经过 Elasticsearch 的分析器处理后,得到如下的关键词:
文章1的关键词是: tom live guangzhou i live guagnzhou
文章2的关键词是: he live shanghai
得到上述文章的关键字之后,可以构造出如下的索引表
term | 文章1 | 文章2 |
---|---|---|
guangzhou | * | |
he | * | |
i | * | |
live | * | * |
shanghai | * | |
tom | * |
当然,仅仅知道关键词出现在那些文章还是不够的,我们希望还能够得到文章的关键词出现的次数和出现频率。而 lucene 中采用的索引结构类似为:
term | 文章号[出现频率] | 出现位 |
---|---|---|
guangzhou | 1[2] | 3、6 |
he | 2[1] | 1 |
i | 1[1] | 4 |
live | 1[2]、2[1] | 2、5、2 |
shanghai | 2[1] | 3 |
tom | 1[1] | 1 |
我们以 live 这样说明该结构。live 在文章1中出现了2次,文章2中出现了一次。它的出现位置为 2、5、2 代表的含义需要结合文章号和出现频率来分析。文章1中出现了2次,那么 2、5 就表示 live 在文章1中出现的两个位置,文章2中出现了一次,剩下的 2 就表示 live 是文章 2 中第 2 个关键字。
上述的关键字是按字符排序排列的,因此 lucene 可以用二元搜索算法快速定位关键词。实现时 lucene 将上面表格的三列分别作为词典文件、频率文件、位置文件保存。此种词典文件不仅保留关键词,还保留了指向频率文件和位置文件的指针。
假设要查询单词 live ,lucene 先对词典二元查找,找到改词后,通过指向频率文件的指针读取所有文章号。因此词典文件本身特别小,因而整个过程是毫秒级的。
相比如普通的顺序匹配,对文章内容进行字符串匹配,lucene 的倒排索引是相当快速的。
2)上面分析完 Elasticsearch 在搜索时采用的倒排索引,下面说一下 Elasticsearch 的聚合分析。聚合分析和搜索还是有很大的不同,典型的应用场景,比如计算文章1中每个关键词出现的次数,反向索引就略显无力。首先需要扫描整个词典文件,才能找到该文档包含的所有关键词,然后在进行聚合统计。在数据量大的情况下,扫描整个方向索引,性能肯定要受不小影响。
Elasticsearch 为聚合计算引入名为 fielddata 的数据结构,即采用我们平时常见正向索引,即文档到关键词的映射。类似于下表:
文章号 | guangzhou | he | i | live | shanghai | tom |
---|---|---|---|---|---|---|
文章1 | * | * | * | * | ||
文章2 | * | * | * |
对文章在进行聚合计算时,就只要根据文章 ID 查找就好。因为聚合计算也好,排序也好,通常是针对某些列,实际上 Elasticsearch 为了做聚合分析,生成的是文档到 field 的多个列式索引(至于什么是列式索引,后面做详细介绍)。在做聚合就分析,fielddata(类似上表) 是保存在内存中,这么做会有内存不够用的风险,而且内存是从 JVM (java 虚拟机)上分配的,JVM 对大内存的垃圾收集有一定不稳性。当数据量大时,内存不够是正常的,同时,也不可能一次性所有字段都加载,如果未命中搜索,还需要在内存中建立 fielddata ,这都影响响应时间。
为了解决 fielddata 的内存有限和 JVM 对大内存的垃圾回收导致的不稳定问题,Elasticsearch 引入如 DocValue。DocValue 也是和 fielddata 类似的结构。不同的是,DocValue 是持久存取在文件中。由于这消耗了额外的存储空间,但对于 JVM 的内存需求降低,多余的内存留给操作系统的文件缓存使用。加上DocValue 是预先构建的,查询时剩去了不命中是构建 fielddata 的时间。DocValue 比内存慢10%~25%,但是稳定性大幅提升。
3)何为列式存储?
看下图:
20141115094556515.png
从上图的内存结构可以看出,行式存储下,一张表的数据时放在一起的,但是列式存储则是分开保存。优缺点如下:
image2016-9-23 11_15_43.png
相关参考网址:
http://blog.csdn.net/dc_726/article/details/41143175 (几张图看懂列式存储)
https://yq.aliyun.com/articles/6902?do=login (Elasticsearch 中的 DocValue)
网友评论