ES的核心概念
十万个为什么
什么是ES
Elasticsearch是一个基于Lucene库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎,具有HTTP Web接口和无模式JSON文档。Elasticsearch是用Java开发的,并在Apache许可证下作为开源软件发布。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。
Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发。这三个产品被设计成一个集成解决方案,称为“Elastic Stack”(以前称为“ELK stack”)。
为什么要使用ES
- 数据库模糊查询是全表扫描,时间慢,性能耗费大。
- 数据库模糊查询无法无法查询关键字中间被隔开的情况,无法满足搜索需求。
什么是全文检索
全文检索主要来说的话就是倒排索引的应用,对于数据库模糊查询而言,以name
字段为例,数据库要对整个表进行全表扫描,而如果根据name
分词建立了倒排索引,就可以对倒排索引的词条进行扫描,可能很快就能找到该数据。
比如数据库100w行,模糊查询必然扫描100w次。而name分词之后可能有1000w个词,但是不需要整个扫描完,可能10w次就解决了。
并且数据库的模糊查询要对每一行中的数据进行模糊匹配,如果该数据字节数很多的话,会更加损耗性能,而分词只需要比较一下是否相等就可以了。
或许你会想到扫描1000w次这种极端情况,这个Lucene的倒排索引算法会对该情况有处理,后面再介绍。
什么是正排索引
正排索引是指,当要找内容包含一个字符串的文件时,对逐个文件依次进行查找,从头查到尾,一直扫描完所有的文件位置。
- 优点:查找准确率高
- 缺点:查询速度慢(在数据量大的情况下)
典型的正排索引有MySQL中的like关键字搜索、编辑器中的ctrl+f搜索都是正排索引。
什么是倒排索引
举个例子:在字典中,会以偏旁为部首建立一个目录,我们会先查找这个目录,根据这个目录在找到对应的内容。这个目录就类似于倒排索引,根据目录找到的内容就是文档。
倒排索引是根据属性来确定文档的位置,而不是根据记录来确定属性。
如果给定如下数据源:
文档id | 文档内容 |
---|---|
0 | it is what it is |
1 | what is it |
2 | it is a banana |
则Lucene可以根据该文档(数据源)创建出类似于这样的数据结构:
"a": {(2, 2)}
"banana": {(2, 3)}
"is": {(0, 1), (0, 4), (1, 1), (2, 1)}
"it": {(0, 0), (0, 3), (1, 2), (2, 0)}
"what": {(0, 2), (1, 0)}
这就是倒排索引,它包含着该属性的文档id、位置(position)与词频。
对于“a”,它的文档id是2,位置是2,词频是1;对于“is”,文档id分别是0、1、2,位置分别是1、4、1、1,词频是4。
如果我们执行短语搜索"what is it"
我们得到这个短语的全部单词各自的结果所在文档为文档0和文档1。但是这个短语检索的连续的条件仅仅在文档1得到。
什么是Lucene
Lucene就是一个jar包,里面包含了封装好的各种建立倒排索引和进行搜索的api。
用Lucene我们可以通过已有的数据(数据源)去建立索引,Lucene会在本地磁盘中帮助我们组织索引的数据结构(就是在本地存储索引库),然后我们就可以用Lucene提供的api对磁盘中的索引库中的数据进行搜索。
为什么有了Lucene还要有ES
Lucene不支持分布式存储与检索,只能在单台服务器上使用。
如果使用Lucene,在数据量很大的情况下,超过了单台机器的承受范围,就必须用多台机器进行数据的存储和搜索,如果我们自己来实现,会很麻烦:
- 如何高性能的建立索引、执行搜索很麻烦
- 跟多台机器通信的过程,很麻烦
- 保证原生Lucene分布式系统的高可用性很麻烦
总之就是很麻烦。
而如果使用es:
- 自动维护数据分布到多个节点的索引建立,以及搜索请求到各个节点的执行
- 保证分布式系统高可用性
- 封装了更多高级功能:复杂搜索功能、聚合分析功能、基于地理位置的搜索(距离我当前位置xxx公里内的烤肉店)
ES与Lucene该如何选择
如果是单服务器,且服务器的内存不高,并且应用数据量较小,则可以直接使用Lucene去建立倒排索引并使用它的API,因为ES相对而言会比较占用内存。
ES核心概念
-
字段 Field
:相当于mysql中的字段。
-
文档 Document
:一个document相当于mysql中的记录。
{ "id": "1", "name": "高渐离" }
如上就是一个document,而id就是field。
+----+-------+ | id | name | +----+-------- | 1 | 高渐离 | +----+-------+
-
类型 Type
:一个Type中可以存储多个Document,相当于mysql中的表。
在Elasticsearch 7.X之后的版本,type被弃用了。
-
索引 Index
:一个Index中可以存储多个Type,相当于mysql中的库。
-
映射 mapping
:相当于数据库中表结构的定义。
+----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(30) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+
-
近实时 Near Realtime(NRT)
:近实时,一方面是指从写入数据到数据可被检索有一个小延迟(1s),另一方面是指ES执行检索和分析是秒级的。
比如Github使用的搜索引擎就是ES,当我们创建一个仓库之后是可以
近实时
的被检索到的。 -
集群 Cluster
:集群包含多个节点,每个节点属于哪个集群通过配置来决定,对于中小型项目,刚开始集群就一个节点是很正常的。
-
节点 Node
:每一个启动的ES进程就是一个节点。
集群中的节点可以配置自己的名称,节点的名称在运维的时候很重要,如果没有配置则随机分配。
节点默认会加入名为elasticsearch的集群,如果直接启动一堆节点,则它们自动组成一个名为Elasticsearch的集群,当然一个节点也会组成名为Elasticsearch的集群。
-
分片 Shard
:单台机器可能无法存储过大的数据,当数据量过大时,ES可以将一个
Index
中的数据切分为多个Shard
,分布在多台服务器上存储。而Index
实际上是指向一个或者多个物理分片的逻辑命名空间。有了
Shard
就可以横向存储,更为方便的存储更多数据、并且让检索与分析分布到不同的服务器上去执行,提高吞吐量和性能,每个Shard
都是一个Lucene的实例,并且其本身就是一个完整的搜索引擎。但是应用程序是直接与索引而不是分片进行交互的。横向存储是指,比如此时有3T数据,而一个节点最多只能存储1T,这时
Index
就会被拆分为多个Shard
,每个Shard
存储这个Index
的一部分数据,这些Shard
散落在多台服务器上,而如果此时又增加了4T数据,此时很简单,只需要重新建立一个新的Index
,并将其拆为4个Shard
即可。单台机器也可以存储多个
Shard
。 -
副本 Replica
:服务器可能会宕机,此时Shard就会丢失,因此可以为每个Shard创建多个Replica副本。
Replica可以在Shard故障时提供备用服务,并且提升检索的吞吐量。
Replica与Shard不能位于同一个节点上。
Elasticsearch在默认情况下会给每个Index分配5个Shard和1个Replica,但是Shard和Replica不能再同一台机器上,所以当启动Elasticsearch单个进程时,Replica副本是无法正常创建的。
所以在后面我们用kibana(postman\浏览器\elasticsearch-head等皆可)请求Elasticsearch的API查看集群状态时会发现ES的状态是Yellow(不健康的)。