一文带你了解Elasticsearch底层逻辑

1. 什么是Elasticsearch

Elasticsearch 是一个分布式、RESTful 风格的搜索引擎,基于 Apache Lucene。它提供了一个高度可扩展的全文搜索引擎,具备近实时的搜索能力。Elasticsearch 适用于各种用例,包括文档搜索、日志和指标数据分析、应用程序性能监控、线程分析等。

Elasticsearch最根本的使用场景是搜索引擎,比如说我们有一堆文档,我们想要搜索到所有包含"树獭叔叔"的文档,这个时候就可以借助Elasticsearch了。

2. Segment

Segment是Lucene的基本存储单元,Lucene是es依赖的底层开源技术,一个Segment单元由以下四部分组成:

2.1. 倒排索引 Inverted Index

倒排索引是一种用于快速全文检索的数据结构,它将文档和词语进行关联,从而使搜索引擎能够快速查找到包含特定词语的文档。倒排索引逆转了传统索引(如在书本的后面查找关键词)的关系,即它将每个词和包含该词的文档列表关联起来。

假设我们有以下三个文档集:

  1. "Elasticsearch is a search engine"
  2. "Elasticsearch is extremely powerful"
  3. "Search engines are fascinating"

建立倒排索引的步骤如下:

  1. 分词(Tokenization)
    • 第一步是将文档分解为独立的词语。例如:
      • Doc 1: "Elasticsearch", "is", "a", "search", "engine"
      • Doc 2: "Elasticsearch", "is", "extremely", "powerful"
      • Doc 3: "Search", "engines", "are", "fascinating"
  1. 去重和排序
    • 过滤掉重复的词,并对词语进行排序。例如:
      • 总词汇表: "Elasticsearch", "Search", "a", "are", "engine", "engines", "extremely", "fascinating", "is", "powerful"
  1. 建立倒排列表
    • 对每个词建立一个文档列表,记录包含该词的所有文档。结果如下:
词语 文档列表
Elasticsearch 1, 2
Search 1, 3
a 1
are 3
engine 1
engines 3
extremely 2
fascinating 3
is 1, 2
powerful 2

在Elasticsearch中,倒排索引是Lucene库的一部分。Elasticsearch 使用Lucene来管理和查询这些倒排索引,从而实现高效的全文搜索。下面是如何在Elasticsearch中处理倒排索引的一些关键步骤:

  1. 文档的分词和分析
    • 当文档被索引时,Elasticsearch会先将文档内容进行分词和分析。这通常包括分词、去除停用词(如"a", "is", "the"等)以及将单词归一化(例如将单词转换为小写)。
  1. 建立倒排索引
    • 分词过程生成的词语会被添加到倒排索引中,每个词语关联到包含该词的文档列表中。
  1. 查询和匹配
    • 当进行搜索时,Elasticsearch 会解析查询内容,找到相关的词语,并使用倒排索引快速定位到包含这些词语的文档。然后,根据查询的类型,可能还会计算每个文档的相关度得分,从而排序返回结果。

2.2. Term Index

以上面的倒表索引表为例:

词语(Term) 文档列表
Elasticsearch 1, 2
Search 1, 3
a 1
are 3
engine 1
engines 3
extremely 2
fascinating 3
is 1, 2
powerful 2

其实我们不难发现,如果是对文章进行分词,那么词项的数量级是很大的,这个时候如果是通过遍历的方式查找每一个词项,那么他的效率是很低的,因此,我们可以按照字典序对词项进行排序,查找的时候就可以借助二分法优化查询效率。

就算这样,我们在查找时还是会存在问题,因为词项的数据量很大,如果直接把词项表存在内存中,很可能有内容问题,因此,我们可以借助字典数的数据结构维护整个词项表,减少内存占用的同时提高查询效率。

2.3. Doc Values

Doc Values本质是通过冗余存储达到更快的排序与搜索,例如我们可以把商品文档的价格属性进行冗余存储,这样我们在依靠价格进行排序时,就能更快的完成排序与搜索过程。

2.4. Stored Fields

文档数据存储的物理单元。

3. Lucene

前面我们已经介绍了Lucene的基本单元segment,这里就要介绍一下Lucene是如何对segment进行调度了。

前面提到,segment是由多个存储结构共同构成的,如果更新的话,就需要对多个结构进行更新,为了满足高性能读写的需求,我们可以在segment的维度进行读写分离,老segment只负责读,新写入的数据生成新的segment,随着segment越来越多,可以定期对小的segment进行merge,合并成大的segment,这就是Lucene中对segment的基本调度规则。

4. 如何基于Lucene实现高可用

如果大量的数据都写在一个Lucene单元中,必然会导致读写操作的竞争,那么,有什么办法提高奇并发读写的性能吗?当然有,就像数据库的分库分表一样,es也有自己的分库分表:

4.1. Index name

可以根据数据类型对Lucene进行分类,分成多个Index name,根据不同的Index name路由道不同类型的数据。例如,将娱乐文章和学术文章区分开(类似于数据库的垂直分表)。

4.2. Shard分片

可以将同一个Index name中的数据通过hash的方式打散到不同的分片上,之后部署到不同的机器,进一步提升可用性。(类似于水平分表)

我们还可以对shard分片进行主从冗余部署,提高可靠性。

5. ES的结构

5.1.1. Document

ES是面向文档的,索引、检索、排序、过滤的对象都是文档。

它是ES中可搜索的最小单位,使用JSON作为文档的格式。

文档中包含着若干个字段,类似于关系型数据库中的一行数据。

ruby 复制代码
{
	"_index": "user",
	//"_type": "_doc",
	"_id": "1",
	"_version": 1,
	"_seq_no": 26,
	"_primary_term": 4,
	"found": true,
	"_source": {
		"name": "John Doe",
		"age": 21,
		"birthday": "2000/01/01",
		"interests": ["running", "movie"]
	}
}

5.1.2. Mapping

文档中的每个字段都有自己的类型,可以是字符串、数值、日期等。通过 Mapping来设定字段的名称和类型, 类似于关系型数据库中的 Schema。比如上面那个文档对应的Mapping 如下:

sql 复制代码
user {
	"mappings": {
		"properties": {
			"name": {
				"type": "string"
			},
			"age": {
				"type": "short"
			},
			"birthday": {
				"type": "date"
			},
			"interests": {
				"type": "string"
			}
		}
	}
}
相关推荐
小蒜学长3 分钟前
springboot党建云课堂学习与管理系统(代码+数据库+LW)
java·数据库·spring boot·后端·学习
烂蜻蜓2 小时前
Flask入门教程(十二):表单处理——从基础到Flask-WTF完整实践
后端·python·flask
2601_962055979 小时前
跟据spring boot版本,查看对应的tomcat,并查看可支持的tomcat的版本范围
spring boot·后端·tomcat
Lost of 程序猿10 小时前
ASP.NET Core API 幂等性设计深度实战:从一次重复申领事故说起
后端·asp.net
QQ_216962909611 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端
郑州光合科技余经理13 小时前
本地生活服务系统:模块边界与结算字段怎么拆
java·开发语言·前端·后端·系统架构·uni-app·php
IT_陈寒13 小时前
Vue的嵌套组件竟然吃掉了我的事件?
前端·人工智能·后端
大辉狼_音频架构14 小时前
进阶:从源码编译 SOF 固件与 topology
后端
大辉狼_音频架构14 小时前
上板:让 SOF 在 FRDM-i.MX8MP 上跑起来
后端
大辉狼_音频架构14 小时前
FRDM-IMX8MP UUU 烧录 eMMC 指南
后端