elasticsearch(1)总体架构

时间:2022-11-08 08:54:41

1.倒排索引
熟悉mysql的索引的都知道,mysql的查询是通过在一大堆文字中查询关键词,我叫他正排索引,比如我们执行操作select * from t_books where name like ‘%java’; 这句话的工作流程是在name字段的内容到模糊查询条件。这种查询首先无法使用到mysql的索引,因为查询效率会比较低。
elasticsearch底层运用了lucence,而lucence引入了一个叫做倒排索引的东西。倒排索引之所以叫做倒排索引,是因为它是针对正排索引而言的,准确的说是从检索条件到字段内容。
设有两篇文章1和2:
文章1的内容为:Tom lives in Guangzhou,I live in Guangzhou too.    文章2的内容为:He once lived in Shanghai.
<1>取得关键词
由于lucene是基于关键词索引和查询的,首先我们要取得这两篇文章的关键词,通常我们需要如下处理措施:   
a.我们现在有的是文章内容,即一个字符串,我们先要找出字符串中的所有单词,即分词。英文单词由于用空格分隔,比较好处理。中文单词间是连在一起的需要特殊的分词处理。    
b.文章中的”in”, “once” “too”等词没有什么实际意义,中文中的“的”“是”等字通常也无具体含义,这些不代表概念的词可以过滤掉   
c.用户通常希望查“He”时能把含“he”,“HE”的文章也找出来,所以所有单词需要统一大小写。   
d.用户通常希望查“live”时能把含“lives”,“lived”的文章也找出来,所以需要把“lives”,“lived”还原成“live”   
e.文章中的标点符号通常不表示某种概念,也可以过滤掉   
在lucene中以上措施由Analyzer类完成。 经过上面处理后,
文章1的所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou]     文章2的所有关键词为:[he] [live] [shanghai]
<2>建立倒排索引
有了关键词后,我们就可以建立倒排索引了。上面的对应关系是:“文章号”对“文章中所有关键词”。倒排索引把这个关系倒过来,变成: “关键词”对“拥有该关键词的所有文章号”。
文章1,2经过倒排后变成   
关键词 文章号   
guangzhou 1   
he 2   
i 1   
live 1,2   
shanghai 2   
tom 1      
通常仅知道关键词在哪些文章中出现还不够,我们还需要知道关键词在文章中出现次数和出现的位置,通常有两种位置:
a.字符位置,即记录该词是文章中第几个字符(优点是关键词亮显时定位快);
b.关键词位置,即记录该词是文章中第几个关键词(优点是节约索引空间、词组(phase)查询快),lucene中记录的就是这种位置。   
加上“出现频率”和“出现位置”信息后,我们的索引结构变为:   
关键词 文章号[出现频率] 出现位置   
guangzhou 1[2] 3,6   
he 2[1] 1   
i 1[1] 4   
live 1[2] 2,5,
2[1] 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没有使用B树结构),因此lucene可以用二元搜索算法快速定位关键词。
<3>实现
实现时,lucene将上面三列分别作为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信息。   
Lucene中使用了field的概念,用于表达信息所在位置(如标题中,文章中,url中),在建索引中,该field信息也记录在词典文件中,每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)。
<4>压缩算法
为了减小索引文件的大小,Lucene对索引还使用了压缩技术。
首先,对词典文件中的关键词进行了压缩,关键词压缩为<前缀长度,后缀>,例如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>。
其次大量用到的是对数字的压缩,数字只保存与上一个值的差值(这样可以减小数字的长度,进而减少保存该数字需要的字节数)。例如当前文章号是16389(不压缩要用3个字节保存),上一文章号是16382,压缩后保存7(只用一个字节)。
<5>应用原因
下面我们可以通过对该索引的查询来解释一下为什么要建立索引。   
假设要查询单词 “live”,lucene先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结果。词典通常非常小,因而,整个过程的时间是毫秒级的。   
而用普通的顺序匹配算法,不建索引,而是对所有文章的内容进行字符串匹配,这个过程将会相当缓慢,当文章数目很大时,时间往往是无法忍受的

2.elasticsearch总体架构
2.1基本概念
elasticsearch中:索引-文档-类型
mysql中 :数据库-表-字段
除了上面三个概念,补充几个概念
映射:所有文档在写入索引钱都要进行分析,用户可以设置一些参数,来决定如何将输入文本分割成词条,哪些词条应该被过滤掉,哪些附加处理是有必要被调用的,这就是映射要扮演的角色,存储所有的元信息
节点、集群:单个ealsticsearch服务实例称为节点。有时候部署一个elasticsearch节点就足以应付大多数的简单的应用,但是考虑到容错性或者数据膨胀到单机没发应付这些状况时,会考虑多个节点的集群。
分片:es会将数据散步到多个物理Lucene索引上,这些索引就成为分片。
副本:es会为每个分片创建一个冗余的副本,便于容错,一旦某个主分片发生了宕机,那么副本的作用就体现了。由此我们不难想到,对于一个分片,其副本要和它在不同机器上,这样才有容错能力。
2.2es架构的一些特征
默认的分布式工作模式:每个节点总是假定自己是某个集群的一部分或者将是某个集群的一部分,一旦工作启动片会加入到某个集群

对等架构。es是去中心化的,所有节点都是平等的地位,因此不会出现单点故障问题。

易于向集群扩充新的节点
es的启动过程:
当es节点启动之后,它使用广播技术,发现同一个集群中的其他节点,并和他们链接。集群中有个管理节点(注意,这个节点并不会比其他节点重要)改节点负责集群的状态管理以及集群扩展变化时做出反应,分发索引分片至集群相应的节点上。
节点管理:假定有两个数据节点和一个管理节点,管理节点会给数据节点发出心跳检测,如果没有得到回复,那么管理节点会将这个没回复的节点剔除。

3.es中的一些通用属性:
index_name:该属性是存储在索引中字段名称,如果未指定,则默认为字段定义的对象的名称。
index:该属性的取值可为analyzed或者no,字符串的字段也可以设为not_analyzed.如果设为analyzed,则该字段将被索引,因而是可搜索的;如果是no,则该字段不可被搜索。默认是可搜索。字符串还有一个额外的选项–not_analyzed,表示该字段会被索引,但是不需要分析。因此,该字段按原样写入索引,只有完全匹配的搜索才能查到该字段。
store:该属性的取值是yes或者no,用于指定字段的原始值是否存入索引。默认是no,意味着不能再结果中返回字段的原始值。如果已建立索引,则依然可以搜索该字段的内容。
boost:该属性的默认值是1,用于定义该字段在文档中的重要性,值越高则该字段取值越重要。
null_valule:该属性指定如果某字段在索引文档中不存在是写入何值。
include_in_all:该属性指定某个是否应被包含到_all字段中。默认情况下,如果开启_all字段则包含所有的字段。

multi_field类型:有时候需要将同一个值存入不同的字段,加入一个字段用于搜索,另一个用于统计,es中有一个特别的类型—multi_field,它允许我们将多个核心类型映射到同一个字段,并且进行不同的分析。

4.路由规则:

Elasticsearch路由机制介绍

Elasticsearch的路由机制与其分片机制有着直接的关系。Elasticsearch的路由机制即是通过哈希算法,将具有相同哈希值的文档放置到同一个主分片中。这个和通过哈希算法来进行负载均衡几乎是一样的。

而Elasticsearch也有一个默认的路由算法:它会将文档的ID值作为依据将其哈希到相应的主分片上,这种算法基本上会保持所有数据在所有分片上的一个平均分布,而不会产生数据热点。

而我们为什么会需要自定义的Routing模式呢?首先默认的Routing模式在很多情况下都是能满足我们的需求的——平均的数据分布、对我们来说是透明的、多数时候性能也不是问题。但是在我们更深入地理解我们的数据的特征之后,使用自定义的Routing模式可能会给我们带来更好的性能。

假设你有一个100个分片的索引。当一个请求在集群上执行时会发生什么呢?
1. 这个搜索的请求会被发送到一个节点
2. 接收到这个请求的节点,将这个查询广播到这个索引的每个分片上(可能是主分片,也可能是复制分片)
3. 每个分片执行这个搜索查询并返回结果
4. 结果在通道节点上合并、排序并返回给用户

因为默认情况下,Elasticsearch使用文档的ID(类似于关系数据库中的自增ID,当然,如果不指定ID的话,Elasticsearch使用的是随机值)将文档平均的分布于所有的分片上,这导致了Elasticsearch不能确定文档的位置,所以它必须将这个请求广播到所有的100个分片上去执行。这同时也解释了为什么主分片的数量在索引创建的时候是固定下来的,并且永远不能改变。因为如果分片的数量改变了,所有先前的路由值就会变成非法了,文档相当于丢失了。

而自定义的Routing模式,可以使我们的查询更具目的性。我们不必盲目地去广播查询请求,取而代之的是:我们要告诉Elasticsearch我们的数据在哪个分片上。

原来的查询语句:“请告诉我,USER1的文档数量一共有多少”
使用自定义Routing(在USESR ID上)后的查询语句:“请告诉我,USER1的文档数量一共有多少,它就在第三个分片上,其它的分片就不要去扫描了