引言
1.1 ES简介
Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。
Elasticsearch提供了存储、搜索、分析数据三大功能,其主要特点有:分布式、零配置、易装易用、自动发现、RESTful风格接口、多数据源和自动搜索负载等。它能很方便的使大量数据具有搜索和分析能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。
Elasticsearch 的实现原理主要分为以下几个步骤:首先用户将数据提交到Elasticsearch ,通过分词器将对应的语句分词,将其权重和分词结果一并存入数据库;当用户搜索数据时,再根据权重将结果打分、排名,再将结果返回呈现给用户。
官方网址: Elasticsearch:官方分布式搜索和分析引擎 | Elastic
Github: https://github.com/elastic/elasticsearch
ES的其他叫法:
- 搜索引擎
- 全文检索引擎
- OLAP系统
- 分布式搜索中间件
通常所说的搜索引擎(如百度、谷歌)定义如下,跟我们说ES是一个搜索引擎有所区别。
所谓搜索引擎,就是根据用户需求与一定算法,运用特定策略从互联网检索出指定信息反馈给用户的一门检索技术。搜索引擎依托于多种技术,如网络爬虫技术、检索排序技术、网页处理技术、大数据处理技术、自然语言处理技术等,为信息检索用户提供快速、高相关性的信息服务。搜索引擎技术的核心模块一般包括爬虫、索引、检索和排序等,同时可添加其他一系列辅助模块,以为用户创造更好的网络使用环境。
题外话:关于OLAP和OLTP系统的比较: 关于OLAP和OLTP你想知道的一切-腾讯云开发者社区-腾讯云
| 特性 | OLAP | OLTP |
| 主要使用场景 | 数据分析、决策支持 | 业务交易处理 |
| 涉及数据量 | 大规模数据(TB或PB级别) | 中等规模数据(GB或TB级别) |
| 事务和数据完整性 | 不涉及事务 | 需要严格的事务控制和ACID特性,以保证数据的一致性和可靠性 |
| 功能使用需求 | 多维度查询、聚合、切片、钻取等 | 插入、更新、删除、查询等基本业务操作 |
| 并发要求 | 读写比较平均,相对较低的并发请求 | 高并发的数据插入、更新、删除和查询操作 |
| 可用性要求 | 强调冷热数据分离、容错性等,但非高可用性 | 强调高可用性、故障恢复、备份和灾备等 |
| 数据模型/规约 | 多维度数据模型,支持OLAP Cube等 | 关系型数据模型,支持SQL查询等 |
| 技术典范 | Hadoop、Spark、Hive等大数据技术栈 | MySQL、Oracle、Microsoft SQL Server等传统数据库技术栈 |
ES有完善的社区和生态,与ES密切相关的技术栈成为Elastic Stack(ELK Stack)。ELK在日志分析、 安全性监测、大数据可视化场景下有比较成熟的解决方案。

ES的特点:
- 开源、免费:基于Apache License 2.0开源协议,完全免费
- 基于Java语言:Elasticsearch基于Java语言开发,运行在Jvm环境中。
- 基于Lucene框架:基于开源的Apache Lucene框架开发( Apache Lucene - Apache Lucene Core)。
- 原生分布式:不依赖Zookeeper或其他分布式系统,自带分布式解决方案
- 高性能:支持海量数据的全文检索。支持PB级数据秒内响应。对于ES来说,上亿级别数据只不过是起点!足以满足各种对性能要求极高的场景。
- 可伸缩:弹性搜索,可根据不同规模服务对性能需要的不同而动态扩展或收缩性能。
- 易扩展:支持非常方便的横向扩展集群。
- restfulAPI,跨编程语言: 支持Java、Golang、Python、C#、PHP等多种变成语言,几乎所有语言开发者都可以使用Elasticsearch。
擅长:
- 擅长高性能检索和聚合分析:ES是OLAP系统,擅长从海量数据中检索少量相关数据
不擅长:
- 不擅长单次查询大量数据(大单页)
- 写入实时性并不是很高,默认1秒,也就是ES缓冲区Buffer的刷新间隔时间,ES并非忽略了对写入性能的优化,而是“有意为之”,其原因就在于基子 ES 的写入机制其写入实时性和大数据检索性能是一个二选一的行为。实际上生产环境中经常通过“牺牲写入实时性”的操作来换取更高更快的“数据检索”。
- 数据一致性不高,正因为ES的写入实时性并不高,如果需要快速响应用户请求,常采取的手段就是使用缓存,但是在很多高并发的场景下,我们需要数据保持强一致性(如银行系统),此时需要使用支持ACID的数据库来支持,比如传统的关系性数据库。
常见数据库横向对比:
| Elastic Search | Solr | MongoDB | MySQL | |
| 数据库类型 | 搜索引擎 | 搜索引擎 | 文档型数据库 | 关系型数据库 |
| 框架 | Lucene | Lucene | ||
| 开发语言 | Java | Java | C++ | C++ |
| 数据结构 | FST、Hash | B+ Tree | B+ Tree | |
| 数据格式 | Json | Json/xml/csv | Bson | Row |
| 分布式支持 | 原生支持 | 支持 | 原生支持 | 不支持 |
| 数据分区方案 | 分片 | 分片 | 分片 | 分库分表 |
| 业务系统类型 | OLAP | OLAP | OLTP | OLTP |
| 事务支持 | 不支持 | 不支持 | 多文档ACID事务 | 支持 |
| 数据量级 | PB | TB~PB | PB | 单库3000万 |
| 一致性策略 | 最终一致性 | 最终一致性 | 实时一致性 最终一致性 | 实时一致性 |
| 擅长领域 |
|
|
|
|
| 劣势 |
|
|
|
|
| 查询性能 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 写入性能 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
总结:
- elasticsearch是一个分布式的搜索、聚合分析和存储引擎。
- elasticsearch是一个基于Lucene的高扩展的分布式搜索服务器,支持开箱即用。
- elasticsearch隐藏了Lucene的复杂性,对外提供Restful 接口来操作索引、搜索。
1.2 ES的重要性和应用场景

众所周知,几乎没有一款软件是没有搜索功能的。毫不客气的说,只要是用到搜索的场景,ES几乎都可以说是最好的选择,没有之一。
Serch Engines排名,ES遥遥领先!


1.3 目标
- 掌握集群的部署方式
- ES的分词器、分析器
- 索引定义与生成过程
- 查询过程以及查询性能提升的方式
ES索引入门
2.1 索引简介
2.1.1 正排索引
正排索引(前向索引) 正排索引也称为"前向索引"。
正向索引的结构如下:
“文档1”的ID > 单词1:出现次数,出现位置列表;单词2:出现次数,出现位置列表;…………。
“文档2”的ID > 此文档出现的关键词列表。

一般是通过key,去找value。因为互联网上收录在搜索引擎中的文档的数目是个天文数字,这样的索引结构根本无法满足实时返回排名结果的要求。
2.1.2 倒排索引
倒排索引的结构如下:
“关键词1”:“文档1”的ID,“文档2”的ID,…………。
“关键词2”:带有此关键词的文档ID列表。

在倒排索引中,有词条(Tem)、词项词典(Term Dictionary)、倒排表(Post List)三部分,下面我们一一介绍。
- 倒排表(Posting List)
倒排表是倒排索引结构中最核心的部分。对于文档集合中出现的每个单词(或称为词项),倒排表中都有一个条目与之对应。这个条目包含了该单词在哪些文档中出现的信息,通常包括文档ID和单词在该文档中出现的位置、频率等附加信息。
例如,假设我们有一个文档集合,包含三个文档:
Doc1: "The quick brown fox"
Doc2: "Quick foxes jump over lazy dogs"
Doc3: "Brown foxes are not quick"
对于单词"quick",倒排表中的条目可能如下:
quick -> Doc1:1; Doc3:4 (这里的数字表示单词在文档中的位置)
- 词项字典(Term Dictionary)
词项字典是一个包含文档集合中所有唯一单词的列表。每个单词在词项字典中都有一个唯一的条目,这个条目指向倒排表中与该单词对应的条目。
使用上面的文档集合作为例子,词项字典如下:
The
quick
brown
fox
foxes
jump
over
lazy
dogs
are
not
每个单词都按照某种顺序(例如字典序)排列,并且每个单词都有一个指针或引用,指向倒排表中相应的条目。
- 词项索引(Term Index)
词典查找的挑战:
全文检索系统通常需要处理大量的文本数据,这意味着词典(Term Dictionary)也会非常大。虽然可以使用各种高效的数据结构(如哈希表、B树等)来加速查找,但这些数据结构通常都需要将数据加载到内存中才能实现最优的查找性能。然而,将整个词典加载到内存中可能会导致巨大的内存消耗,甚至耗尽可用内存。
此外,即使词典被加载到内存中,由于内存访问速度仍然远低于CPU的处理速度,因此查找性能仍然可能受到限制。特别是在需要进行大量的随机内存访问时,性能影响会更加显著。
词项索引(Term Index)的作用:
为了解决这些问题,引入了词项索引。词项索引的目的是提供一个更紧凑、更快速的方式来查找词典中的词项。它通常使用Trie树(或前缀树)结构来存储词项的前缀信息。
Trie树是一种树形数据结构,用于高效地存储和查找字符串(或其他类型的数据)。在Trie树中,从根到任何一个节点,按照路径上的标签字符顺序连接起来,就是一个相应的字符串。这种结构非常适合于存储大量的字符串,并且可以快速查找具有相同前缀的字符串。
然而,传统的Trie树可能会消耗大量的内存,特别是当词典非常大时。为了解决这个问题,可以使用一种压缩版的Trie树,称为有限状态转换器(Finite State Transducers,FST)。FST是一种特殊类型的有限状态机,它可以用来表示字符串之间的映射关系,并且非常节省内存。
倒排索引结构通过倒排表、词项字典和词项索引这三个部分,实现了从单词到文档的快速映射。这种结构使得搜索引擎能够高效地处理大量的文本数据和复杂的查询请求。


前文中提及,Elasticsearch是基于Lucene实现的。在Lucene中,词典和倒排表是实现快速检索的重要基石。另外,词典和倒排表是分两部分存储的,词典存储在内存中,倒排表存储在磁盘上。
2.2 ES的存储结构
ES之所以能够在海量数据中实现毫秒级的搜索响应,以及高效灵活的数据分析,要归功于其内部精妙的数据结构和机制:行存储(Stored Fields)、列存储(Doc Values)和倒排索引(Inverted Index)这三种关键组件,他们相互协调用于不同的数据存储和检索策略,倒排索引上面介绍过,下面简单介绍行存和列存。
| 行存 | 列存 | |
| 定义 | 也称为行式存储。在行存中,数据按照行的形式存储在存储介质(如硬盘)上。每一行对应着数据的一条记录,包含了多个字段的数据。 | 也称为列式存储。在列存中,数据按照列的形式存储。每一列存储了相同类型的数据,通常是某个字段的数据。 |
| 使用场景 | 适合于OLTP场景,即CRUD场景 | 适合于OLAP场景,对大量数据进行排序、聚合、统计和分析 |
| 优点 | 支持事务和复杂查询 | 高效数据压缩、快速扫描、高效的聚合操作 |
| 缺点 | 大量数据时性能不佳 | 不支持事务和复杂查询 |
| ES中的使用 |
|
|
| 存储结构 |
|
|
扩展:
深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之行存(一)_es的列存储-优快云博客
深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之列存(二)_elasticsearch是列式存储嘛-优快云博客
深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之倒排索引(三)_es倒排索引数据结构-优快云博客
2.3 索引的创建与映射
2.3.1 索引创建
ES的索引库是一个逻辑概念,索引表述的含义可以简单理解成 MySQL中的database,或相当于Mongodb中集合的概念。
关于索引这个语:
索引(名词):ES是基于Lucene构建的一个搜索服务,它要从索引库搜索符合条件的数据。
索引(动词):索引库刚创建起来是空的,将数据添加到索引库的过程称为索引。
- 文档
在ES中,一条文档指一条数据。文档基本结构如下:

索引的组成部分
- alias:即 索引别名
- settings:索引设置,常见设置如分片、副本的数量等。
- mappings: 即映射,定义了索引中包含哪些字段,以及字段的类型、长度、分词器等
settings:
number_of_shards:设置主分片的数量,主分片数设置后不可修改,要想修改主分片数量,需要使用reindex。
number_of_replicas:设置副本分片的数量,设置副本是为了提高ES的高可靠性,单机环境可设置为0.
如下是创建的例子,创建xc_course索引库,共1个分片,0个副本:


2.3.2字段映射
2.3.2.1 常用映射类型
- text文本字段
下图是ES6.2核心的字段类型如下:

字符串包括text和keyword两种类型:
- text
1)analyzer
通过analyzer属性指定分词器。
下边指定name的字段类型为text,使用ik分词器的ik_max_word分词模式。
"name": {
"type": "text",
"analyzer": "ik_max_word"
}
上边指定了analyzer是指在索引和搜索都使用ik_max_word,如果单独想定义搜索时使用的分词器则可以通过 search_analyzer属性。
对于ik分词器建议是索引时使用ik_max_word将搜索内容进行细粒度分词,搜索时使用ik_smart提高搜索精确性。
"name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
2)index
通过index属性指定是否索引, false时不会构建改字段的倒排索引。
默认为index=true,即要进行索引,只有进行索引才可以从索引库搜索到。
但是也有一些内容不需要索引,比如:商品图片地址只被用来展示图片,不进行搜索图片,此时可以将index设置为false。
"pic": {
"type": "text",
"index": false
}
3)store
是否在source之外存储,每个文档索引后会在 ES中保存一份原始文档,存放在"_source"中,一般情况下不需要设置store为true,因为在_source中已经有一份原始文档了。
- keyword关键字字段
上边介绍的text文本字段在映射时要设置分词器,keyword字段为关键字字段,通常搜索keyword是按照整体搜索,所以创建keyword字段的索引时是不进行分词的,比如:邮政编码、手机号码、身份证等。keyword字段通常用于过虑、排序、聚合等。
- date日期类型
日期类型不用设置分词器。 通常日期类型的字段用于排序。
1)format:设置日期格式
例子: 下边的设置允许date字段存储年月日时分秒、年月日及毫秒三种格式。
{
"properties": {
"timestamp": {
"type": "date",
"format": "yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd"
}
}
}
- 数值类型
下边是ES支持的数值类型

1、尽量选择范围小的类型,提高搜索效率和减少存储空间
2、对于浮点数尽量用比例因子,比如一个价格字段,单位为元,我们将比例因子设置为100这在ES中会按 分存储,映射如下:
"price": {
"type": "scaled_float",
"scaling_factor": 100
},
由于比例因子为100,如果我们输入的价格是23.45则ES中会将23.45乘以100存储在ES中。
如果输入的价格是23.456,ES会将23.456乘以100再取一个接近原始值的数,得出2346。
使用比例因子的好处是整型比浮点型更易压缩,节省磁盘空间。
如果比例因子不适合,则从下表选择范围小的去用:

2.3.2.2 创建映射
- 概念说明
映射是 ES 中用来定义索引中字段、类型、分词器和字段映射方式的过程。在索引中每个文档都包括了一个或多个field,创建映射就是向索引库中创建field的过程,下边是document和field 与关系数据库的概念的类比:
文档(Document)----------------Row记录
字段(Field)-------------------Columns 列
注意:6.0之前的版本有type(类型)概念,type 是一个用于标识索引中文档类型的字段。它是 Elasticsearch 中一个重要的概念,被用来区分不同的文档类型并将其存储在同一个索引中。
在早期版本的 Elasticsearch 中,type 字段是必需的,并且每个索引可以包含多个类型。但是,在 Elasticsearch 6.0 版本中,type 字段已经不再是必需的,并且计划在以后的版本中逐步取消该字段。从 Elasticsearch 7.0 版本开始,每个索引只能包含一个类型。
- 动态映射
动态映射(Dynamic Mapping)是指在索引中插入文档时,自动检测文档中的字段,并且动态地创建字段映射。如果文档中出现了新的字段,Elasticsearch 会自动创建该字段的映射。
优点:可以自动检测和创建字段映射,避免了手动定义每个字段的类型和属性的繁琐过程,方便新手和开发环境debug。
缺点:可能会导致映射错误或者不一致,因为它不能保证每个字段都被正确地映射(例如日期类型,需要严格的utc时间格式,数字型会映射为long类型),生产环境推荐使用手动映射。
可以使用一些策略来控制动态映射,例如禁止自动创建新的字段、使用动态模板等。
- 手动映射(静态映射)
静态映射(Static Mapping)在创建索引时,定义好索引中每个字段的类型、属性、分析器。静态映射需要手动指定每个字段的类型和属性,例如文本类型、数字类型、日期类型等。通过静态映射,我们可以控制每个字段的存储方式、分析器、索引方式等,以便于更好地控制索引和查询的行为。
静态映射的优点是可以提高索引和查询的性能,因为 Elasticsearch 可以根据字段的类型和属性进行优化,例如使用不同的存储方式、分析器等。但是,静态映射的缺点是需要手动指定每个字段的类型和属性,如果索引中的字段比较多,会比较繁琐。
请求示例 put:http://localhost:9200/xc_course
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"name": {
"type": "text"
},
"description": {
"type": "text"
},
"studymodel": {
"type": "keyword"
}
}
}
}
}
2.4 数据创建
ES中的文档相当于MySQL数据库表中的记录。
发送:put 或Post http://localhost:9200/xc_course/_doc
(如果不指定id值ES会自动生成ID)
{
"name": "Bootstrap开发框架",
"description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
"studymodel": "201001"
}
2.5 数据导入与索引优化
1. 数据导入工具与方法介绍
在 Elasticsearch 中,进行数据导入的常用工具和方法包括:
- Logstash:Logstash 是 ES提供的开源数据收集引擎,可以方便地将各种数据源的数据导入到 ES中。通过 Logstash 的管道(pipeline)机制,可以对数据进行清洗、处理和转换后再导入到 Elasticsearch 中。
- Elasticsearch Ingest Node:Ingest Node 是 ES自带的一个功能,可以在数据写入索引之前进行预处理操作。可以通过配置 Ingest Node Pipeline 来实现对原始数据的处理,例如解析日志、添加字段等。
- ES客户端库:Elasticsearch 提供了多种编程语言的客户端库,如 Elasticsearch-Py(Python)、elasticsearch-js(JavaScript)等,可以通过这些客户端库直接连接 Elasticsearch 实例,并编写代码实现数据的导入操作。
- Bulk API:Elasticsearch 的 Bulk API 允许一次性发送多个操作(索引、更新、删除)来提高导入的效率。通过批量导入数据,可以减少网络开销和提升导入速度。
- 消息队列:通过将业务数据库数据(比如mysql数据)变更同步到消息队列,通过监听消息队列来实现ES的数据同步
2. 索引生成过程中的性能优化技巧
在索引生成过程中,为了提高性能和效率,可以采取以下优化技巧:
- 批量操作:使用 Bulk API 进行批量数据导入,减少网络开销和提升导入速度。
- 合理设置分片数:根据数据量和集群规模合理设置索引的分片数量,尤其是主分片数量,避免分片过多或过少导致的性能问题。
- 关闭刷新(Refresh):在大批量导入数据时,暂时关闭索引的自动刷新功能,待数据全部导入完成后再手动执行一次刷新操作。
- 禁用副本:在数据导入阶段暂时禁用副本,待数据导入完成后再恢复副本,以加快索引生成过程。
ES的分词器与分析器
在 ES中,分词器在索引中扮演着至关重要的角色。在创建索引时,可以设置整个索引的分词器或字段级别的分词器(通过分析器的方式),这些分词器会被应用到索引中所有字段或指定字段上。分词器的选择对于整个索引的文本处理方式至关重要,影响着索引中文本数据的分词、标准化和建立倒排索引的过程。
3.1 分词器的作用与种类
分词器是 ES 中用于将文本进行分词的组件,它将文本转换成一个个词项(term),以便建立倒排索引。
在 Elasticsearch 中,有多种内置的分词器可供使用,以下是其中几种常用的分词器:
- 标准分词器(Standard Analyzer):适用于大部分场景,根据空格、标点符号等将文本拆分成词语。
- 中文分词器(CJK Analyzer):专门用于处理中文文本,采用字典匹配和最大正向匹配等算法进行分词。
- 简单分词器(Simple Analyzer):按照非字母字符进行切分。
- 语言分词器(Language Analyzers):针对不同语言的特点设计的分词器,如英文、法文、德文等。
除了这些内置的分词器外,Elasticsearch 还支持自定义分词器的设计与实现。
3.2 分析器的使用与配置
3.2.1 分析器的使用
分析器是由字符过滤器(Character Filters)、分词器和标记过滤器(Token Filters)组成的一个处理链。分析器用于处理文本,在索引和搜索过程中进行字符过滤、分词和标记过滤等操作。
- 分析器的组成与配置参数:
- 字符过滤器(Character Filters):在分词之前对原始文本进行处理,如去除 HTML 标签、转换大小写等。可以配置多个。
- 分词器(Tokenizer):将原始文本切分成单个的词语。只能配置1个。
- 标记过滤器(Token Filters):对分词结果进行进一步处理,如去除停用词、同义词替换等。可以配置多个。
- 分析器的链式调用与效果演示:
分析器可以通过配置将字符过滤器、分词器和标记过滤器组合起来形成一个处理链。每个组件按照顺序依次处理文本,最终得到处理后的结果。
以下是一个示例,演示了使用标准分词器、小写字符过滤器和停用词过滤器的分析器配置:
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "standard",
"char_filter": [
"html_strip"
],
"filter": [
"lowercase",
"stop"
]
}
},
"filter": {
"stop": {
"type": "stop",
"stopwords": "_english_"
}
}
}
}
}
3.2.2 分析器的优先级
在 Elasticsearch 中,分析器(Analyzer)可以根据索引建立和查询过程分开配置,同时也支持多层级别的配置和优先级设置。以下是关于分析器配置介绍:
- 按照索引建立和查询过程分开配置:
- 索引阶段配置:在创建索引时,可以为整个索引指定默认的分析器,该分析器将应用于索引中所有字段的文本处理过程。
- 查询阶段配置:在执行搜索查询时,可以通过查询请求中的查询语句或查询参数,指定特定的分析器来处理查询条件。
- 不同配置级别的优先级:
- 默认配置:在创建索引时,如果不指定分词器则会采用ES默认的分词器(Standard Analyzer)。这是最基本的配置级别。
- 索引级别配置:除了默认配置外,还可以在创建索引时针对当前索引指定默认分析器。这种设置会覆盖默认配置,但仍适用于整个索引。
- 字段级别配置:对于每个字段,可以单独指定该字段使用的分析器。字段级别配置的优先级最高,会覆盖索引级别和默认配置,允许为不同字段选择不同的文本处理方式。
- 查询时指定:在执行搜索查询时,可以通过查询语句或查询参数中指定特定的分析器来处理查询条件,此时指定的分析器会覆盖索引级别和字段级别的默认配置。
- 分词器优先级:
查询时指定 > 字段级别 > 索引级别 > 默认
如果是查询,则在上述各级别内部还有如下优先级:查询分词器>索引分词器
3.3 分词与分析的过程示例
在 Elasticsearch 中,文本的分词与分析是一个非常重要的过程,它直接影响着索引和搜索的效果。下面以一个简单的示例来演示分词与分析的过程。
假设有如下一段英文文本:"Elasticsearch is a distributed, RESTful search and analytics engine."
字符过滤器处理
如果配置了小写字符过滤器,那么词语会被转换成小写形式:
- elasticsearch
- is
- a
- distributed
- restful
- search
- and
- analytics
- engine
使用标准分词器进行分词
标准分词器会根据空格和标点符号将文本进行分词,因此上述文本会被分成以下词语序列:
- Elasticsearch
- is
- a
- distributed
- RESTful
- search
- and
- analytics
- engine
标记过滤器处理
如果配置了停用词过滤器,会去除常用的停用词(如 "is"、"a"、"and" 等),得到最终的词语序列:
- elasticsearch
- distributed
- restful
- search
- analytics
- engine
这样经过分词器、字符过滤器和标记过滤器的处理,原始文本就被处理成了一个可以建立倒排索引的词语序列。这些词语将会被存储在倒排索引中,用于搜索时的匹配和检索。
通过合理配置分词器和分析器,可以提高搜索的准确性和效率,从而为用户提供更好的搜索体验。在实际应用中,根据具体需求和数据特点选择合适的分词器和过滤器组合是非常重要的。
检索与优化
4.1 ES 的查询模型
首先来看下 ES 的查询模型。 ES 的任意节点可作为写入请求的协调节点,接收用户请求。协调节点将请求转发至对应一个或多个数据分片的主或者从分片进行查询,各个分片查询结果最后在协调节点汇聚,返回最终结果给客户端。

ES 的分布式查询主要有2个阶段,Query阶段跟Fetch阶段。
- Query 阶段:协调节点将查询拆分成多个分片任务,发送到数据分片上通过调用Lucene 执行查 “倒排索引”,查询满足条件的文档id集合。Query 内又可以细分为2个阶段,本质上是一个倒排合并过程:
- 对查询语句进行拆解,预估每个子语句的匹配结果数量;
- 对符合条件的最小结果集进行遍历,检查其是否匹配其他查询子语句,得到一个最终的结果集。
- Fetch 阶段:归并生成最终的检索、聚合结果。Fetch 也可以细分为以下2个阶段:
- 对Query 阶段的多个分片结果进行归并
- 抓取用户需要的字段信息
如果只有一个分片,ES 会将流程合并为 QueryAndFetch 一个阶段。
4.2 查询语法与DSL查询
通过ES查询表达式(Query DSL),可以实现复杂的查询功能,ES查询表达式主要由JSON格式编写,可以灵活的组合各种查询语句。
4.2.1 查询基本语法结构
GET /{索引名}/_search
{
"from" : 0, // 返回搜索结果的开始位置
"size" : 10, // 分页大小,一次返回多少数据
"_source" :[ ...需要返回的字段数组... ],
"query" : { ...query子句... },
"aggs" : { ..aggs子句.. },
"sort" : { ..sort子句.. }
}
{索引名},支持支持一次搜索多个索引,多个索引使用逗号分隔,例子:
GET /order1,order2/_search
按前缀匹配索引名,搜索索引名以order开头的索引:
GET /order*/_search
4.2.2 查询索引指定字段
query子句主要用来编写类似SQL的Where语句,支持布尔查询(and/or)、IN、全文搜索、模糊匹配、范围查询(大于小于)。
GET */_search
{
"query": {
"match_all": {}
},
"_source": ["name", "studymodel"]
}
4.2.3 分页查询
ES支持分页查询,传入两个参数:from和size。
form:表示起始文档的下标,从0开始。 size:查询的文档数量。
GET /{索引名}/_search
{
"from": 0,
"size": 1,
"query": {
"match_all": {}
},
"_source": ["name", "studymodel"]
}
4.2.4 Term Query
Term Query为精确查询,在搜索时会整体匹配关键字,不再将关键字分词。
GET /{索引名}/_search
{
"query": {
"term": {
"name": "spring"
}
},
"_source": ["name", "studymodel"]
}
#上边的搜索会查询name包括“spring”这个词的文档。
4.2.5 根据id精确匹配
ES提供根据多个id值匹配的方法:
GET /{索引名}/_search
{
"query": {
"ids": {
"type": "doc",
"values": ["3", "4", "100"]
}
}
}
4.2.6 match Query
1、基本使用
match Query即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。
match query与Term query区别是match query在搜索前先将搜索关键字分词,再拿各各词语去索引中搜索。
GET /{索引名}/_search
{
"query": {
"match": {
"description": {
"query": "spring开发",
"operator": "or"
}
}
}
}
query:搜索的关键字,对于英文关键字如果有多个单词则中间要用半角逗号分隔,而对于中文关键字中间可以用逗号分隔也可以不用。
operator:or 表示 只要有一个词在文档中出现则就符合条件,and表示每个词都在文档中出现则才符合条件。
上边的搜索的执行过程是:
1)将“spring开发”分词,分为[spring,开发]两个词
2)再使用spring和开发两个词去匹配索引中搜索。
3)由于设置了operator为or,只要有一个词匹配成功则就返回该文档。
2、minimum_should_match
上边使用的operator = or表示只要有一个词匹配上就得分,如果实现三个词至少有两个词匹配如何实现?
使用minimum_should_match可以指定文档匹配词的占比:
比如搜索语句如下:
GET /{索引名}/_search
{
"query": {
"match": {
"description": {
"query": "spring开发框架",
"minimum_should_match": "80%"
}
}
}
}
“spring开发框架”会被分为三个词:spring、开发、框架 .
设置"minimum_should_match": "80%"表示,三个词在文档的匹配占比为80%,即3*0.8=2.4,向上取整得2,表示至少有两个词在文档中要匹配成功。
4.2.7 multi Query
上边提到的termQuery和matchQuery一次只能匹配一个Field,而multiQuery一次可以匹配多个字段。
1、基本使用
单项匹配是在一个fifield中去匹配,多项匹配是拿关键字去多个Field中匹配。
例子:
拿关键字 “spring css”去匹配name 和description字段。
GET /{索引名}/_search
{
"query": {
"multi_match": {
"query": "spring css",
"minimum_should_match": "50%",
"fields": ["name", "description"]
}
}
}
2、提升boost
匹配多个字段时可以提升字段的boost(权重)来提高得分
例子: 提升boost之前,执行下边的查询:
GET /{索引名}/_search
{
"query": {
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": ["name", "description"]
}
}
}
通过查询发现Bootstrap排在前边。
提升boost,通常关键字匹配上name的权重要比匹配上description的权重高,这里可以对name的权重提升。
GET /{索引名}/_search
{
"query": {
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": ["name^10", "description"]
}
}
}
“name^10” 表示权重提升10倍,执行上边的查询,发现name中包括spring关键字的文档排在前边。
4.2.8 布尔查询
布尔查询可实现将多个查询组合起来。
三个参数:
must:文档必须匹配must所包括的查询条件,相当于 “AND”
should:文档应该匹配should所包括的查询条件其中的一个或多个,相当于 "OR"
must_not:文档不能匹配must_not所包括的该查询条件,相当于“NOT”,must_not不参与算分。
分别使用must、should、must_not测试下边的查询:
GET /{索引名}/_search
{
"_source": ["name", "studymodel", "description"],
"from": 0,
"size": 1,
"query": {
"bool": {
"must": [{
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": ["name^10", "description"]
}
}, {
"term": {
"studymodel": "201001"
}
}]
}
}
}
4.2.9 过滤器
过滤是针对搜索的结果进行,过滤器主要判断文档是否匹配,不去计算和判断文档的匹配度得分,所以过滤器性能比查询要高,推荐尽量使用过滤器去实现查询或者过滤器和查询共同使用。另外,过滤器不参与算分。
过滤器在布尔查询中使用,下边是在搜索结果的基础上进行过滤:
GET /{索引名}/_search
{
"_source": ["name", "studymodel", "description", "price"],
"query": {
"bool": {
"must": [{
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": ["name^10", "description"]
}
}],
"filter": [{
"term": {
"studymodel": "201001"
}
}, {
"range": {
"price": {
"gte": 60,
"lte": 100
}
}
}]
}
}
}
range:范围过虑,保留大于等于60 并且小于等于100的记录。
term:项匹配过虑,保留studymodel等于"201001"的记录。
注意:range和term一次只能对一个Field设置范围过虑。
4.2.10 排序
sort子句,用来设置排序条件,类似SQL的order by语句
可以在字段上添加一个或多个排序,支持在keyword、date、float等类型上添加,text类型的字段上不允许添加排序。
过虑0-10元价格范围的文档,并且对结果进行排序,先按studymodel降序,再按价格升序
GET /{索引名}/_search
{
"_source": ["name", "studymodel", "description", "price"],
"query": {
"bool": {
"filter": [{
"range": {
"price": {
"gte": 0,
"lte": 100
}
}
}]
}
},
"sort": [{
"studymodel": "desc"
}, {
"price": "asc"
}]
}
4.2.11 高亮显示
高亮显示可以将搜索结果一个或多个字突出显示,以便向用户展示匹配关键字的位置。
在搜索语句中添加highlight即可实现,如下:
GET /{索引名}/_search
{
"_source": ["name", "studymodel", "description", "price"],
"query": {
"bool": {
"must": [{
"multi_match": {
"query": "开发框架",
"minimum_should_match": "50%",
"fields": ["name^10", "description"],
"type": "best_fields"
}
}],
"filter": [{
"range": {
"price": {
"gte": 0,
"lte": 100
}
}
}]
}
},
"sort": [{
"price": "asc"
}],
"highlight": {
"pre_tags": ["<tag1>"],
"post_tags": ["</tag2>"],
"fields": {
"name": {},
"description": {}
}
}
}
4.2.12 aggs
aggs子句,用于聚合分析,类似SQL的group by语句。 ES系列14:你知道25种(桶聚合)Bucket Aggs 类型各自的使用场景么?【聚合分析】-腾讯云开发者社区-腾讯云

GET /{索引名}/_search
{
"size": 0,
"aggs": {
"total_sales": {
"sum": {
"field": "sales"
}
},
"average_price": {
"avg": {
"field": "price"
}
},
"sales_by_country": {
"terms": {
"field": "country.keyword",
"size": 10
}
}
}
}
在这个示例中,我们进行了三种类型的聚合:
- "total_sales" 聚合使用 "sum" 聚合类型来计算 "sales" 字段的总和。
- "average_price" 聚合使用 "avg" 聚合类型来计算 "price" 字段的平均值。
- "sales_by_country" 聚合使用 "terms" 聚合类型来按照 "country" 字段进行分组,并统计每个国家的销售量,同时使用 "size" 参数限制返回的桶数量。
4.3 查询结果分析
ES查询结果分析:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [{
"_index": "xc_course",
"_type": "doc",
"_id": "4028e58161bcf7f40161bcf8b77c0000",
"_score": 0.2876821,
"_source": {
"name": "Bootstrap开发框架",
"description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较 为广泛。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现 一个不受浏览器限制的精美界面效果。",
"studymodel": "201001"
}
}]
}
}
took:本次操作花费的时间,单位为毫秒。
timed_out:请求是否超时
_shards:说明本次操作共搜索了哪些分片
hits:结果集,搜索命中的记录
hits.total : 符合条件的文档总数 hits.hits :匹配度较高的前N个文档
hits.max_score:文档匹配得分,这里为最高分
_score:文档的相关度评分,按照降序排列(相关度评分用于对检索结果排序,在7.x之前相关度评分财认使用TF-IDF算法,7.x之后为BM25)。
_source:文档的源数据。
4.4 ES查询优化 “三十六计”
4.4.1 分片数、副本数、索引规模的合理评估
为了让分片查询性能发挥到最优,需要对规模进行限制,我们通常有以下使用原则:
- 集群总分片数建议控制在5w以内,单个索引的规模控制在 1TB 以内,单个分片大小控制在30 ~ 50GB ,docs数控制在10亿内;
- 分片的数量通常建议小于或等于ES 的数据节点数量,最大不超过总节点数的2倍,通过增加分片数可以提升并发;
- 分片数越多长尾效应越明显,所以并不是越多越好,在搜索场景合理控制分片数也可以提升性能。
- 增加副本数,也可以分摊查询的负载,提升查询的性能。
4.4.2 Mapping 的设计
Mapping的设计对于如何发挥ES的查询性能和优化存储空间非常重要。在ES 中,一旦一个字段被定义在了 mapping中,是无法被修改的(新增字段除外),如果修改需要重建索引。 为了高效发挥mapping 的性能并降低存储成本,介绍一些常见的使用技巧:
- 对于一份数据,ES 默认会建立倒排索引,行存,列存(分析型text除外)。对于某些不重要的字段,可以通过指定(index: false , store: false ,doc_values: false)来关闭,以减少冗余存储成本。
- 对于有限枚举值的数值字段,建议使用keyword 类型以创建倒排索引。
- 字段值太长会大幅增加 ES的序列化跟Highlight 开销,且Lucene 限制单个term 长度不能超过65536,对于超长的值可以配置ignore_above忽略超长的数据,以避免性能的严重衰减。
- 字段可以设置子字段,比如对于text 字段有sort和聚合查询需求的场景,可以添加一个keyword子字段以支持这两种功能。
- 字段数量如果太多会降低ES 的性能,需要合理设计字段。同时为了避免字段爆炸,ES 有如下优化使用方式:
- 在某个父层级字段设置 enabled: false 来防止其下面创建子字段 mapping ,但是能被行存查询出来。
- mapping 层级可以设置dynamic=runtime,虽然加入新字段也会更新 mapping,但是新加入的字段不会被索引,也就是不会使得索引变大。虽然不被索引,但是新加入的字段依然可以被查询,只是查询的代价会更大(运行时构建)。这种类型一般不建议用在经常查询的条件字段上,而更适合用在一些不确定数据结构且查询需求不大的数据中。
- mapping 层级也可以设置dynamic=strict (不允许新增一个不在 mapping中的字段,一旦新增的字段不在 mapping 定义中,则直接报错)或者dynamic=false(新字段不会被索引,不能作为查询条件,但是能被行存查询出来)
4.4.3 查询 Routing 路由优化
正常情况下,单个查询会扫描所有分片,容易遇到长尾效应,且大量节点在空转,可利用ES路由能力,提高查询吞吐、降低长尾。通过写入时支持指定routing ,ES 会计算 target_shard_id = hash(routing) 将写入数据路由到指定分片上,这样在查询时,也可以通过指定routing,快速定位到目前数据所在的分片,查询的效率能够提升一个数量级。

具体使用方式参考:ElasticSearch查询优化routing_es 查询走routing-优快云博客。但使用这种方式需要特别注意的是,指定的 routing 须尽可能随机,保证分片之间尽量均衡,然后容易造成“热Key” 导致负载不均衡。
4.4.4 Fetch 字段性能优化:不同类型字段拉取性能优化对比
我们在上面提到,ES 存储字段的类型这么多,那么我们最关心的不同类型字段的拉取性能究竟有什么区别呢? 下面是基于8C 32G 规格,构建100w 条测试数据(每条数据包含100个字段)不断变化查询字段数进行查询,得到查询耗时的结果如下。可以看到,通过不同方式拉取字段的性能是存在一个平衡点的,大约在40左右。

(1) 当字段数很少时,低于 40 时,使用 doc_value Fields 拉取,性能最优。
分析:如果我们只需要返回其中包含的一小部分字段时,读取并解压这个巨大的_source字段可能会开销很高。
(2) 当字段超较多时,达到 40 以上时,使用 _source 变为最优。
分析:当我们需要非常多或者几乎全部字段时,此时使用 doc_value Fields 可能会有非常多的随机IO。这个时候,读取 _source 一个字段就能够处理全部业务字段。
在不同业务规模场景下,数据大小不一样,_source、列存、Store 查询性能的平衡点可能会偏移,需要实际的压测。业务可以根据需求选择最合适的存储字段。
4.4.5 Force merge 优化
ES 实时写入的数据都在 lucene 内存 buffer 中,同时写入 translog 保证数据的一致性。当buffer积攒到一定程度后,将他们批量写入一个Segment(文件系统缓存)。 这样,数据写入都是 Batch 和 Append,能达到很高的吞吐量。但是这种方式,也会产生大量的小Segment,查询时会产生非常多的随机IO,导致查询效率低下。 ES后台会进行segment merge(段合并)操作,但是默认段合并非常缓慢。所以我们可以通过强制的 force merge 来大幅降低Segment 数量,减少函数空转跟随机IO。 所以定期进行force merge ,有助于维持较好的查询性能。
Elasticsearch核心技术(四):分布式存储架构与索引原理分析 - James_Shangguan - 博客园

4.4.6 用好缓存
缓存是加快数据检索速度的王道。ES 是使用各种缓存的大户。从整体来说,ES 可以利用的缓存汇总介绍如下:
- 系统缓存 (page cache/buffer cache) : 由Linux 控制,ES 使用系统页缓存可以减少磁盘的访问次数(如flush之前的数据)。
- 分片级请求缓存(Shard Request Cache):请求级别的查询缓存,主要用于缓存聚合结果。
- 节点级查询缓存(Node Query Cache):字段级别的查询缓存,主要用于缓存某个字段的查询结果,并且由节点级别的LRU策略来控制。使用 Filter 可以告知 ES 优先对某些查询语句进行缓存。
- Fielddata Cache:可以理解为ES 在内存中实时动态构建的文档 “正排索引” 缓存,主要是用于text 跟聚合场景。从5.0 开始,text 字段默认关闭了 Fielddata 功能,所以目前默认只在聚合场景开启(global ordinals)。在低基数的聚合场景下,对聚合有较好的提升效果。
- Prestore 缓存:是一种用于存储预加载数据的高级缓存机制,它可以在索引数据时提前加载指定的数据到缓存中,以加快后续的搜索请求响应速度。Prestore 缓存通常用于存储频繁访问或重要的数据,以减少搜索过程中对磁盘的读取操作。
集群的部署方式
5.1 关键概念
ES通常以集群方式工作,这样做不仅能够提高 ES的存储能力还可以处理大规模数据的搜索,同时也增加了系统的高可用,ES可以实现PB级数据的搜索。
下图是ES集群结构的示意图:

节点
ES集群由多个ES服务组成,每个服务即为一个Node节点。
一个节点就是一个ES服务实例,或者一个ES进程。
一个节点 ≠ 一台服务器
- 主节点
一个集群中会有一个或多个主节点角色(但是某时刻只有一个真正的主节点,其他的是备选主节点)
主节点的作用是集群管理,比如增加节点,移除节点等,主节点挂掉后ES会重 新选一个主节点。
- 节点转发
每个节点都知道其它节点的信息(均具备协调节点角色),我们可以对任意一个节点发起请求,接收请求的节点会转发给其它节点查询数据。
分片
分片,也叫主分片(Primary Shard),即索引的碎片,每个碎片可存储到不同的节点上。
主分片具有可读、可写的能力。
当我们的文档量很大时,由于内存和硬盘的限制,同时也为了提高ES的处理能力、容错能力及高可用能力,我们将 索引分成若干分片,每个分片可以放在不同的服务器,这样就实现了多个服务器共同对外提供索引及搜索服务。 一个搜索请求过来,会分别从各分片去查询,最后将查询到的数据合并返回给用户。
副本
副本也叫副本分片(Replica Shard),即主分片的备份,一个分片可以有多个副本。
副本分片仅读,不具备写入能力。
为了提高ES的高可用同时也为了提高搜索的吞吐量,我们将分片复制一份或多份存储在其它的服务器,这样即使当 前的服务器挂掉了,拥有副本的服务器照常可以提供服务。
角色
角色是ES节点的重要属性。角色在分布式、可扩展的系统架构中发挥着至关重要的作用。
- 常见的主要角色
- 主节点 (active master) :一般指活跃的主节点,一个集群中只能有一个,主要作用是对集群的管理。
- 候选节点 (master-eligible) :当主节点发生故障时,参与选举,也就是主节点的替代节点。
- 仅投票节点(voting-only node):只有选举权,通常可以作为数据节点一起使用
- 专用主节点(dedicated master-eligible node):专用候选节点(专用主节点)一般指仅配置了master角色的节点,其设计初衷为尽可能的让主节点职责单一,避免重负载任务给集群管理带来压力。
- 数据节点 (data node) : 数据节点保存包含已编入索引的文档的分片。数据节点处理数据相关操作,如 CRUD、搜索和聚合。这些操作是I/O 密集型、内存密集型和 CPU密集型的。因此,我们需要监控这些资源并在它们过载时对齐进行扩容。
- 预处理节点 (ingest node) :预处理节点有点类似于logstash的消息管道,所以也叫ingest pipeline,常用于一些数据写入之前的预处理操作以及脚本执行。
- 协调节点(coordinate node):类似负载平衡器,将搜索任务分发到相关的数据节点,并收集所有结果,然后再将它们汇总并返回给客户端应用程序。一个节点角色未设置,默认为协调节点

集群
ES集群是服务自动发现的,即零配置,开箱即用,无需任何网络配置,ES将绑定到可用的主机地址并扫描本地端口9300到9305连接同一服务器上运行的其他节点,自动形成集群。此行为无需进行任何配置即可提供自动发现集群服务。
5.2 ES部署模式
5.2.1 节点推荐配置
前面提到了ES节点的角色,这些角色对计算资源和存储资源的要求是不一样的,具体来说:
- Master
资源要求:中高CPU;中高内存;中低IO。一般在生产环境中配置3台候选主节点,一个集群只有1台活跃的主节点,负责分片管理,索引创建,集群管理等操作
- Data
资源要求:高CPU、高内存、高磁盘IO
- Ingest
资源要求:高配置CPU; 中等配置的RAM; 低配置的磁盘
- Coordinating
资源要求:一般中高CPU;中高内存;低磁盘
协调节点扮演者负载均衡、结果的聚合,在大es集群中条件允许可以使用高配的cpu和内存。
5.2.2 架构模式
5.2.2.1 基础版

这是一个基础版的职责分离的部署架构:
- 比如当磁盘容量无法满足需求时,可以增加数据节点;
- 磁盘读写压力大时,增加数据节点。
但是如果大量的聚合查询等操作,这种架构不太适合了。
5.2.2.2 水平扩展部署

当系统中有大量的复杂查询或者聚合时候,我们可增加Coordinating节点,增加查询的性能。这里增加了负载均衡层,通过负载均衡扩展时对应用程序无感知。
5.2.2.3 读写分离

写入多,多部署ingetst节点;读的时候聚合查询较多可以多部署协调节点;存储数据量大,可以适当对数据节点进行调优。
5.2.2.4 冷热分离
数据有冷热之分,比如写入频繁的日志数据,近期的索引将会频繁写入。ES根据数据这些特征引入了hot节点和warm节点。
- hot节点
使用ssd,该节点上的索引不断的有新文档写入和查询,对cpu、io的要求较高。
- warm节点
可以使用HDD,上面的索引不会有写入,查询较少。上面只保存只读索引或者旧索引,可使用大容量低成本的机械硬盘。

配置步骤:
- 在ES节点启动的时候,在ElasticSearch.yml配置文件node.attr中指定当前的节点是hot还是warm。如:node.attr.testNodeType=hot
- 通过GET/_cat/nodeattrs?v查看所有的节点的状态
- 创建索引时指定在何种类型的节点上,使用属性:"index.routing.allocation.require.testNodeType":"hot"
- 也可以在已有的索引上使用上述属性,它会将索引的数据迁移到hot节点上
5.2.2.5 跨机房部署集群
针对多机房灾备,ElasticSearch有多种不同的通用解决方案:
- 跨机房部署集群
同一个集群中的节点分布在不同的机房
优点:部署简单,一致性高。
缺点:对网络带宽和延迟要求较高,仅适用于同城灾备,可能由于机房间网络中断造成不可用。
- 应用双写
应用程序同时将数据写入两个集群
优点:应用端灵活可控
缺点:但是一致性差、延迟高、集群故障时数据会丢失
- 借助消息队列实现双写
应用程序先将数据写入消息队列,然后由下游的消费者消费并写入集群
优点:这种方案数据可靠性高,不易丢失
缺点:引入额外的消息队列组件,维护成本高,开发难度大、延迟高,需要保证消息中间件的高可用。
- CCR跨集群复制
ElasticSearch官方的跨集群复制功能,基于文档操作实现订阅复制
优点:一致性高、设置简单、延迟低、提供完善的API,并且可以监控同步进度,整体有保障。
缺点:白金功能,会员独享;集群之间拉取数据可能会增加额外的负载并影响原有集群本身的磁盘和网络性能
- 定期快照
定期将索引备份到外部存储,如hdfs等设备
优点:操作简单,无技术成本
缺点:但是需要通过快照将数据恢复到新集群中,恢复时间长,数据不是实时备份,可能丢失数据
- 极限网关
写请求交给网关,网关实时写入主集群,然后异步写备集群
- 优点:无缝透明,应用程序无需任何调整、网关自动处理故障情况、一致性高,通过校验任务确保数据完全一致
- 对网关的要求较高
5.2.2.6 小规模集群高可用部署架构
如果说专用主节点设计初衷为尽可能的让主节点职责单一,避免重负载任务给集群管理带来压力,那么仅投票节点存在的意义则是为了降低资源浪费。因为高可用系统在很多层面都需要以空间换时间,在很多情况下需要我们去权衡利弊,做出最佳选择。
为了避免让主节点执行重负载任务,遵循职责单一原则,一般不为其分配 data 角色,从而避免让主节点执行数据的增删改查这种重负载任务。
但是这无形中造成很大的资源浪费,尤其是小规模集群,本身服务器资源就不多,节点就少。以一个五节点的集群为例,如果我们为了遵循职责单一法则,让其中3个master节点都作为专用候选节点(仅配置master角色),那么真正执行增删改查的节点就只有两个了,
一个很好的解决办法就是“二加一部署”,即两个专用主节点 + 一个仅投票节点

仅投票节点没有被选举权只有选举权,也就是仅投票节点永远无法成为主节点,这样的话我们就可以为其分配data角色让其承担数据负载,这样技能保证选举出的新的主节点是一个专用主节点,又降低的资源浪费。
原文链接:ES节点角色深层解读,及高可用集群架构角色设计_es集群9节点角色分配-优快云博客
5.3 集群健康状态
用三种颜色来展示健康状态: green 、 yellow 或者 red 。
绿色: 所有分片都可用
黄色: 至少有一个副本不可用,但是所有主分片都可用,此时集群能提供完整的读写服务,但是不具备高可用。
红色: 至少有一个主分片不可用,数据不完整。此时集群无法提供完整的读写服务集群不可用。
检查方式:
GET /_cat/health?v
GET /_cluster/health

5.4 集群故障诊断
通过检查集群的健康状态,是否有节点未加入或者脱离集群,以及是否有异常状态的分片。可采取以下 API 完成对集群的故障诊断。
常用APIs:
_cat/indices?health=yellow&v=true:查看当前集群中的所有索引
_cat/health?v=true: 查看健康状态
_cat/nodeattrs: 查看节点属性
_cat/nodes?v: 查看集群中的节点
_cat/shards: 查看集群中所有分片的分配情况
Cluster APIs
_cluster/allocation/explain: 可用于诊断分片未分配原因
_cluster/health/<target>: 检查集群状态
索引未分配的原因:
- 集群变红。
- 创建索引失败,我们可以通过Allocation Explain API查看,会返回解释信息。
- 集群重启阶段,短暂变红。
- 打开一个之前关闭的索引。
- 有节点离线。通常只需要重启离线的节点使其回来即可。
- 一个节点离开集群,有索引被删除,离开的节点又回来了。会导致出现红色,产生了dangling索引。
- 磁盘空间限制,分片规则(Shard Filtering)引发的,需要调整规则或者增加节点。官方文档给出了详细的未分配分片的可能原因:
5.5 安全性与可扩展性考虑
在部署 Elasticsearch 时,需要考虑安全性与可扩展性:
- 身份验证与授权:配置用户认证和角色授权,限制用户对 Elasticsearch 的访问权限,确保数据安全。
- 传输加密:使用 SSL/TLS 加密传输数据,防止数据在传输过程中被窃取。
- 网络隔离:将 Elasticsearch 集群部署在安全的网络环境中,避免直接暴露在公共网络中。
- 水平扩展:集群节点职责分离,通过对数据节点的扩容来实现集群的水平扩展。
- 启用配置检查:生产环境启用配置检查,来确保集群的安全


3357

被折叠的 条评论
为什么被折叠?



