ElasticSearch8.X入门教程
概念
什么是ElasticSearch
- 是⼀个开源,是⼀个基于Apache Lucene库构建的Restful搜索引擎. Elasticsearch是在Solr之后⼏年推出的。
- 它提供了⼀个分布式,多租户能⼒的全⽂搜索引擎,具有HTTP Web界⾯(REST)和⽆架构JSON⽂档
- Elasticsearch的官⽅客户端库提供Java,Groovy,PHP,Ruby,Perl,Python,.NET和Javascript。
- 官网:https://www.elastic.co/cn/elasticsearch/
- 应用场景
- 搜索引擎
- 可以快速而准确地搜索大量的结构化和非结构化数据,用于构建搜索引擎、电商网站搜索等。
- 实时日志分析
- 提供了强大的实时索引功能和聚合功能,非常适合实时日志分析。
- 数据分析和可视化
- Elasticsearch与Kibana(Elastic Stack的一个组件)结合使用,可以进行复杂的数据分析和可视化。
- 实时推荐系统
- 基于Elasticsearch的实时搜索和聚合功能,可以用于构建实时推荐系统。
- 根据用户的行为和兴趣,动态地推荐相关的内容和产品。
- 电商商品搜索和过滤
- Elasticsearch具有强大的搜索和过滤能力,使其成为构建电商网站的商品搜索和过滤引擎的理想选择。
- 可以快速搜索和过滤商品属性、价格范围、地理位置等。
- 地理空间数据分析
- Elasticsearch内置了地理空间数据类型和查询功能,可以对地理位置进行索引和搜索
- 适合于构建地理信息系统(GIS)、位置服务和地理数据分析应用。
- 搜索引擎
- 在新版Elasticsearch中,文档document就是一行记录(json),而这些记录存在于索引库(index)中,索引名称必须是小写
Mysql数据库 | Elastic Search |
---|---|
Database | 7.X版本前有Type,对比数据库中的表,新版取消了 |
Table | Index |
Row | Document |
Column | Field |
分片、副本、元数据
- 分片shards
- 数据量特大,没有足够大的硬盘空间来一次性存储,且一次性搜索那么多的数据,响应跟不上
- ES提供把数据进行分片存储,这样方便进行拓展和提高吞吐
- 副本replicas
- 分片的拷贝,当主分片不可用的时候,副本就充当主分片进行使用
- 索引分片的备份,shard和replica一般存储在不同的节点上,用来提高高可靠性
- 案例
- 假如Elasticsearch中的每个索引分配3个主分片和1个副本
- 如果集群中至少有两个节点,索引将会有3个主分片和另外3个复制分片(1个完全拷贝)这样每个索引总共有6个分片
- 元数据
- Elasticsearch中以 “ _” 开头的属性都成为元数据,都有自己特定的意思
ES默认为一个索引创建1个主分片和1个副本,在创建索引的时候使用settings属性指定,每个分片必须有零到多个副本
注意:索引一旦创建成功,主分片primary shard数量不可以变(只能重建索引),副本数量可以改变
正排索引、倒排索引
-
正排索引 (Forward Index )
- 指将文档的内容按照文档的顺序进行索引,每个文档对应一个索引条目,包含了文档的各个字段的内容
- 例子假设我们有三个文档的标题和内容
文档1:标题 "Apple iPhone 12",内容 "The latest iPhone model" 文档2:标题 "Samsung Galaxy S21",内容 "Powerful Android smartphone" 文档3:标题 "Microsoft Surface Laptop",内容 "Thin and lightweight laptop"
- 正排索引的结构示意图如下
DocumentID | Title | Content ----------------------------------------------------------- 1 | Apple iPhone 12 | The latest iPhone model 2 | Samsung Galaxy S21 | Powerful Android smartphone 3 | Microsoft Surface Laptop | Thin and lightweight laptop
- 正排索引的优势在于可以快速的查找某个文档里包含哪些词项。但是 正排不适用于查找包含某个词项的文档有哪些
- 在数据库系统中,将正排索引类比为表格的结构,每一行是一个记录,每一列是一个字段
-
倒排索引(Inverted Index)
-
根据关键词构建的索引结构,记录了每个关键词出现在哪些文档或数据记录中,适用于全文搜索和关键词检索的场景
-
它将文档或数据记录划分成关键词的集合,并记录每个关键词所出现的位置和相关联的文档或数据记录的信息
-
案例一
例子假设 使用以下文档构建倒排索引 文档1:标题 "Apple iPhone 12",内容 "The latest iPhone model" 文档2:标题 "Samsung Galaxy S21",内容 "Powerful Android smartphone" 文档3:标题 "Microsoft Surface Laptop",内容 "Thin and lightweight laptop Apple"
-
倒排索引的结构示意图如下:
Term | Documents ----------------------------------------- Apple | 1,3 iPhone | 1 12 | 1 latest | 1 Samsung | 2 Galaxy | 2 S21 | 2 Powerful | 2 Android | 2 smartphone| 2 Microsoft | 3 Surface | 3 Laptop | 3 Thin | 3 lightweight| 3
-
案例二
假设我们有以下三个文档 文档1:我喜欢吃苹果 文档2:我喜欢吃橙子和苹果 文档3:我喜欢吃香蕉
-
倒排索引的结构示意图如下
关键词 "我":文档1、文档2、文档3 关键词 "喜欢":文档1、文档2、文档3 关键词 "吃":文档1、文档2、文档3 关键词 "苹果":文档1、文档2 关键词 "橙子":文档2 关键词 "香蕉":文档3
-
通过倒排索引,可以快速地找到包含特定关键词的文档或数据记录
-
倒排索引记录了每个词语出现在哪些文档中,通过这种方式,我们可以非常快速地得知每个关键词分别出现在哪些文档中。
-
当我们需要搜索包含特定关键词的文档时,可以直接查找倒排索引,找到包含该关键词的文档
-
-
总结
-
正排索引和倒排索引的结构和用途不同
-
正排索引用于快速访问和提取文档的内容
-
倒排索引用于快速定位和检索包含特定词语的文档
-
ElasticSearch8.X安装
说明
- Linux服务器安装JDK17+ElasticSearch8.X,Elasticsearch是使用Java开发的,8.1版本的ES需要JDK17及以上版本
- 在默认安装包中带有JDK环境,如果系统配置ES_JAVA_HOME环境变量,那会采用系统配置的JDK。
- 如果没有配置环境变量,ES会使用自带的JDK,虽然自带的JDK是Elasticsearch推荐的Java版本,但一般建议使用系统配置的JDK
- 这边配置JDK,因为后续SpringBoot3.X整合也需要使用到JDK17
安装jdk17
- 下载地址
jdk17 windows: 链接:https://pan.baidu.com/s/16q0JMY-1o-nU_fd6-jXqQA?pwd=pnr7 提取码:pnr7 jdk17 linux: 链接:https://pan.baidu.com/s/1rHzHpHbjP6RalCYYCM9EYw?pwd=sar2 提取码:sar2
- 上传linux包,解压:tar -zxvf jdk-17_linux-x64_bin.tar.gz
- 重命名
- 添加环境变量
vim /etc/profile 在末尾添加(JAVAHOME写自己的路径) JAVA_HOME=/usr/local/software/elk_test/jdk17 CLASSPATH=$JAVA_HOME/lib/ PATH=$PATH:$JAVA_HOME/bin export PATH JAVA_HOME CLASSPATH
- 环境变量立刻生效
- source /etc/profile
- 查看安装情况
- java -version
安装ElasticSearc8.X
-
下载地址
链接:https://pan.baidu.com/s/1oRTlwZeCXDzPY3r1LontKA?pwd=6sff 提取码:6sff
-
上传安装包和解压
tar -zxvf elasticsearch-8.4.1-linux-x86_64.tar.gz
-
新建一个用户,安全考虑,elasticsearch默认不允许以root账号运行
创建用户:useradd es_user 设置密码:passwd es_user
-
修改目录权限
- chmod是更改文件的权限
- chown是改改文件的属主与属组
- chgrp只是更改文件的属组。
chgrp -R es_user /usr/local/software/elk_test/elasticsearch-8.4.1 chown -R es_user /usr/local/software/elk_test/elasticsearch-8.4.1 chmod -R 777 /usr/local/software/elk_test/elasticsearch-8.4.1
-
修改文件和进程最大打开数,需要root用户,如果系统本身有这个文件最大打开数和进程最大打开数配置,则不用
在文件内容最后添加后面两行(切记*不能省略) vim /etc/security/limits.conf - soft nofile 65536 - hard nofile 65536
-
修改虚拟内存空间,默认太小
在配置文件中改配置 最后一行上加上 vim /etc/sysctl.conf vm.max_map_count=262144 退出保存,执行 sysctl -p(立即生效)
-
修改elasticsearch的JVM内存,机器内存不足,常规线上推荐16到24G内存
vim config/jvm.options -Xms1g -Xmx1g
-
修改 elasticsearch相关配置
- path.data和path.logs修改成自己的路径
vim config/elasticsearch.yml cluster.name: my-application node.name: node-1 path.data: /usr/local/software/elk_test/elasticsearch-8.4.1/data path.logs: /usr/local/software/elk_test/elasticsearch-8.4.1/logs network.host: 0.0.0.0 http.port: 9200 cluster.initial_master_nodes: ["node-1"] xpack.security.enabled: false xpack.security.enrollment.enabled: false ingest.geoip.downloader.enabled: false
配置说明 cluster.name: 指定Elasticsearch集群的名称。所有具有相同集群名称的节点将组成一个集群。 node.name: 指定节点的名称。每个节点在集群中应该具有唯一的名称。 path.data: 指定用于存储Elasticsearch索引数据的路径。 path.logs: 指定Elasticsearch日志文件的存储路径。 network.host: 指定节点监听的网络接口地址。0.0.0.0表示监听所有可用的网络接口,开启远程访问连接 http.port: 指定节点上的HTTP服务监听的端口号。默认情况下,Elasticsearch的HTTP端口是9200。 cluster.initial_master_nodes: 指定在启动集群时作为初始主节点的节点名称。 xpack.security.enabled: 指定是否启用Elasticsearch的安全特性。在这里它被禁用(false),意味着不使用安全功能。 xpack.security.enrollment.enabled: 指定是否启用Elasticsearch的安全认证和密钥管理特性。在这里它被禁用(false)。 ingest.geoip.downloader.enabled: 指定是否启用GeoIP数据库下载功能。在这里它被禁用(false)
-
以上命令均在root用户下执行
-
启动ElasticSearch
切换到es_user用户启动, 进入bin目录下启动, &为后台启动,再次提示es消息时 Ctrl + c 跳出 ./elasticsearch &
-
常见命令,可以用postman访问(网络安全组记得开发端口)
#查看集群健康情况 http://120.78.85.91:9200/_cluster/health #查看分片情况 http://120.78.85.91:9200/_cat/shards?v=true&pretty #查看节点分布情况 http://120.78.85.91:9200/_cat/nodes?v=true&pretty #查看索引列表 http://120.78.85.91:9200/_cat/indices?v=true&pretty
-
常见问题
-
磁盘空间需要85%以下,不然ES状态会不正常
-
不要用root用户安装
-
linux内存不够
-
linux文件句柄
-
没开启远程访问 或者 网络安全组没看开放端口
-
有9300 tcp端口,和http 9200端口,要区分
-
没权限访问,重新执行目录权限分配
chgrp -R es_user /usr/local/software/elk_test/elasticsearch-8.4.1 chown -R es_user /usr/local/software/elk_test/elasticsearch-8.4.1 chmod -R 777 /usr/local/software/elk_test/elasticsearch-8.4.1
-
安装Kibana(ES可视化分析)
-
Kibana
-
基于node.js开发,数据可视化和仪表盘工具,连接到Elasticsearch,通过简单易用的用户界面创建各种图表、图形和仪表盘
-
帮助用户快速探索和理解数据,并进行强大的数据分析和可视化
-
除了使用Kibana,也可以使用其他http请求工具,比如postman等进行测试接口和es语法
-
-
安装部署
-
安装包
链接:https://pan.baidu.com/s/1QyepsiMPgTYtFnUxKYLKcQ?pwd=o5ee 提取码:o5ee
-
上传安装包和解压
tar -zxvf kibana-8.4.1-linux-x86_64.tar.gz
-
配置用户权限
chgrp -R es_user /usr/local/software/elk_test/kibana-8.4.1 chown -R es_user /usr/local/software/elk_test/kibana-8.4.1 chmod -R 777 /usr/local/software/elk_test/kibana-8.4.1
-
修改配置文件
vim config/kibana.yml server.port: 5601 server.host: "0.0.0.0" elasticsearch.hosts: ["http://112.74.167.42:9200"] i18n.locale: "zh-CN" #汉化
#配置说明 server.port: 指定Kibana服务器监听的端口号,Kibana将在5601端口上监听HTTP请求。 server.host: 指定Kibana服务器绑定的网络接口地址, "0.0.0.0"表示监听所有可用的网络接口。 elasticsearch.hosts: 指定ES集群的主机地址,可以配置多个,Kibana将连接到位于"120.24.7.58"主机上、使用默认HTTP端口9200的es i18n.locale: 指定Kibana界面的语言区域,"zh-CN"表示使用简体中文作为语言。 启动,切换到es_user 用户, 建议先不用守护进程方式启动,可以直接启动查看日志
-
./kibana &
- 访问(网络安全组记得开发端口)
-
验证请求
进入开发工具管理台:http://120.78.85.91:5601 #查看集群健康情况 GET /_cluster/health #查看分片情况 GET /_cat/shards?v=true&pretty #查看节点分布情况 GET /_cat/nodes?v=true&pretty #查看索引列表 GET /_cat/indices?v=true&pretty
-
索引(Index)核心操作
-
查看索引列表
GET /_cat/indices?v=true&pretty 查看分片情况 GET /_cat/shards?v=true&pretty
-
创建索引(Create Index):
PUT /<index_name> { "settings": { "number_of_shards": 1, "number_of_replicas": 1 } } PUT /xdclass_shop { "settings": { "number_of_shards": 2, "number_of_replicas": 1 } }
当单节点部署es时,创建索引如果同时创建副本,此时es的状态的yellow,因为副本和主节点不能再同一台机器上
-
查看索引是否存在( 结果是200 和 404)
HEAD /<index_name> HEAD /xdclass_shop
-
获取索引(Get Index)
GET /<index_name> GET /xdclass_shop
-
更新索引设置(Update Index Settings):
PUT /<index_name>/_settings { "settings": { "number_of_replicas": 2 } } PUT /xdclass_shop/_settings { "settings": { "number_of_replicas": 2 } }
-
删除索引(Delete Index):
DELETE /<index_name> DELETE /xdclass_shop
文档(Document)核心操作
-
文档document
- 真正的数据,存储一条数据就是一份文档,存储格式为JOSN,等同于mysql中的一条数据
-
文档的基本操作
- 查询文档
GET /xdclass_shop/_doc/1
- 新增文档(需要指定ID)
PUT /xdclass_shop/_doc/1 { "id":5555, "title":"小滴课堂短链平台大课", "pv":144 }
- 新增文档(不指定ID或者指定ID都可以),会自动生成id
POST /xdclass_shop/_doc { "id":123, "title":"小滴课堂架构大课", "pv":244 }
- 修改(put和post都行,需要指定id)
PUT /xdclass_shop/_doc/1 { "id":999, "title":"小滴课堂短链平台大课v2", "pv":999, "uv":55 } POST /xdclass_shop/_doc/1 { "id":999, "title":"小滴课堂短链平台大课v3", "pv":999, "uv":559 }
- 搜索
GET /xdclass_shop/_search 字段解释 took字段表示该操作的耗时(单位为毫秒)。 timed_out字段表示是否超时。 hits字段表示搜到的记录,数组形式。 total:返回记录数,本例是1条。 max_score:最高的匹配程度,本例是1.0
- 删除数据
DELETE /xdclass_shop/_doc/1
Mapping和常见字段类型
-
什么是Mapping
- 类似于数据库中的表结构定义 schema,
- 定义索引中的字段的名称,字段的数据类型,比如字符串、数字、布尔等
-
查看索引库的字段类型
GET /<index_name>/_mapping GET /my_index/_mapping
-
Dynamic Mapping(动态映射)
-
用于在索引文档时自动检测和定义字段的数据类型
-
当我们向索引中添加新文档时,Elasticsearch会自动检测文档中的各个字段,并根据它们的值来尝试推断字段类型
-
常见的字段类型包括文本(text)、关键词(keyword)、日期(date)、数值(numeric)等
-
动态映射具备自动解析和创建字段的便利性,但在某些情况下,由于字段类型的不确定性,动态映射可能会带来一些问题
-
例如字段解析错误、字段类型不一致等,如果对字段类型有明确的要求,最好在索引创建前通过显式映射定义来指定字段类型
-
-
ElasticSearch常见的数据类型
-
在 ES 7.X后有两种字符串类型:Text 和 Keyword
-
Text类型:用于全文搜索的字符串类型,支持分词和索引建立
-
Keyword类型:用于精确匹配的字符串类型,不进行分词,适合用作过滤和聚合操作。
-
-
Numeric类型:包括整数类型(long、integer、short、byte)和浮点数类型(double、float)。
-
Date类型:用于存储日期和时间的类型。
-
Boolean类型:用于存储布尔值(true或false)的类型。
-
Binary类型:用于存储二进制数据的类型。
-
Array类型:用于存储数组或列表数据的类型。
-
Object类型:用于存储复杂结构数据的类型
-
-
指定索引库字段类型mapping
PUT /my_index { "mappings": { "properties": { "id": { "type": "keyword" }, "title": { "type": "text" }, "price": { "type": "float" } } } }
-
最高频使用的数据类型
-
text字段类型
-
text类型主要用于全文本搜索,适合存储需要进行全文本分词的文本内容,如文章、新闻等。
-
text字段会对文本内容进行分词处理,将文本拆分成独立的词项(tokens)进行索引
-
分词的结果会建立倒排索引,使搜索更加灵活和高效。
-
text字段在搜索时会根据分词结果进行匹配,并计算相关性得分,以便返回最佳匹配的结果。
-
-
keyword字段类型
-
keyword类型主要用于精确匹配和聚合操作,适合存储不需要分词的精确值,如ID、标签、关键字等。
-
keyword字段不会进行分词处理,而是将整个字段作为一个整体进行索引和搜索
-
这使得搜索只能从精确的值进行匹配,而不能根据词项对内容进行模糊检索。
-
keyword字段适合用于过滤和精确匹配,同时可以进行快速的基于精确值的聚合操作。
-
-
总结
-
在选择text字段类型和keyword字段类型时,需要根据具体的需求进行权衡和选择:
-
如果需要进行全文本检索,并且希望根据分词结果计算相关性得分,以获得最佳的匹配结果,则选择text字段类型。
-
如果需要进行精确匹配、排序或聚合操作,并且不需要对内容进行分词,则选择keyword字段类型。
-
-
-
案例实战
-
创建索引并插入文档
PUT /my_index { "mappings": { "properties": { "title": { "type": "text" }, "tags": { "type": "keyword" }, "publish_date": { "type": "date" }, "rating": { "type": "float" }, "is_published": { "type": "boolean" }, "author": { "properties": { "name": { "type": "text" }, "age": { "type": "integer" } } }, "comments": { "type": "nested", "properties": { "user": { "type": "keyword" }, "message": { "type": "text" } } } } } } POST /my_index/_doc/1 { "title": "小滴课堂最近上线了新课 Elasticsearch Introduction", "tags": ["search", "big data", "distributed system", "小滴课堂"], "publish_date": "2025-01-01", "rating": 4.5, "is_published": true, "author": { "name": "John Doe", "age": 30 }, "comments": [ { "user": "Alice", "message": "Great article!" }, { "user": "Bob", "message": "Very informative." } ] }
-
查询匹配关键词的文档一
GET /my_index/_search { "query": { "match": { "title": "Elasticsearch" } } }
-
查询匹配关键词的文档二
# tags是password类型,不支持分词,根据data查不到数据 GET /my_index/_search { "query": { "match": { "tags": "data" } } }
-
搜索引擎的分词和ES分词器
什么是搜索引擎的分词
- 在Elasticsearch 8.X中,分词(tokenization)是将文本内容拆分成独立的单词或词项(tokens)的过程
- 分词是搜索引擎在建立索引和执行查询时的关键步骤,将文本拆分成单词,并构建倒排索引,可以实现更好的搜索和检索效果。
- 案例
假设我们有两个产品标题: "Apple iPhone 12 Pro Max 256GB" "Samsung Galaxy S21 Ultra 128GB" 使用默认的标准分词器(Standard Tokenizer),这些标题会被分割为以下令牌: 标题1:["Apple", "iPhone", "12", "Pro", "Max", "256GB"] 标题2:["Samsung", "Galaxy", "S21", "Ultra", "128GB"] 分词器根据标点符号和空格将标题拆分为独立的词语。当我们执行搜索时,可以将查询进行分词,并将其与标题中的令牌进行匹配。 例如 如果我们搜索"iPhone 12",使用默认的分词器,它会将查询分解为["iPhone", "12"],然后与令牌进行匹配。 对于标题1,令牌["iPhone", "12"]匹配,它与查询相符。 标题2中没有与查询相符的令牌
- 分词规则是指定义如何将文本进行拆分的规则和算法
- Elasticsearch使用一系列的分词器(analyzer)和标记器(tokenizer)来处理文本内容
- 分词器通常由一个或多个标记器组成,用于定义分词的具体规则
- 以下是分词的一般过程:
- 标记化(Tokenization):
- 分词的第一步是将文本内容拆分成单个标记(tokens),标记可以是单词、数字、特殊字符等。
- 标记化过程由标记器(tokenizer)执行,标记器根据一组规则将文本切分为标记。
- 过滤(Filtering):
- 标记化后,标记会进一步被过滤器(filters)处理。
- 过滤器执行各种转换和操作,如转换为小写、去除停用词(stop words),词干提取(stemming),同义词扩展等。
- 倒排索引(Inverted Indexing):
- 分词处理完成后,Elasticsearch使用倒排索引(inverted index)来存储分词结果。
- 倒排索引是一种数据结构,通过将标记与其所属文档进行映射,快速确定包含特定标记的文档。
- 查询匹配:
- 当执行查询时,查询的文本也会进行分词处理。
- Elasticsearch会利用倒排索引来快速查找包含查询标记的文档,并计算相关性得分。
- 标记化(Tokenization):
- 以下是分词的一般过程:
- 常见的分词器,如Standard分词器、Simple分词器、Whitespace分词器、IK分词等,还支持自定义分词器
默认的Standard分词器的分词规则
- 标点符号切分:
- 标点符号会被删除,并将连字符分隔为两个独立的词。
- 例如,“Let’s go!” 会被切分为 “Let”, “s”, “go”。
- 小写转换:
- 所有的文本会被转换为小写形式。
- 例如,“Hello World” 会被切分为 “hello”, “world”。
- 停用词过滤:
- 停用词(stop words)是在搜索中没有实际意义的常见词,如 “a”, “an”, “the” 等。
- 停用词会被过滤掉,不会作为独立的词进行索引和搜索。
- 词干提取:
- 通过应用Porter2词干提取算法,将单词还原为其原始形式。
- 例如,running -> run、swimming -> swim、jumped -> jump
- 词分隔:
- 按照空格将文本切分成词项(tokens)。
如何查看ES分词存储效果?
-
使用analyze API 来对文本进行分词处理并查看分词结果,基本语法如下
GET /_analyze { "analyzer": "分词器名称", "text": "待分析的文本" }
-
案例
#字段是text类型 POST /my_index/_analyze { "field": "title", "text": "This is some text to analyze" } #字段是text类型 POST /my_index/_analyze { "field": "title", "text": "今天我在小滴课堂学习架构大课" } #字段是keyword类型 POST /my_index/_analyze { "field": "tags", "text": "This is some text to analyze" } #字段是keyword类型 POST /my_index/_analyze { "field": "tags", "text": ["This is","小滴课堂","Spring Boot" ] }
-
每个分词结果对象包含
-
分词后的单词(token)
-
开始位置(start_offset)
-
结束位置(end_offset)
-
类型(type)
-
ALPHANUM是一种数据类型,表示一个字符串字段只包含字母和数字,并且不会进行任何其他的分词或处理
-
它会忽略字段中的任何非字母数字字符(如标点符号、空格等),只保留字母和数字字符
-
-
-
单词在原始文本中的位置(position)
IK中文分词器配置
- 背景
- 在Elasticsearch 8.X中,分词(tokenization)是将文本内容拆分成独立的单词或词项(tokens)的过程
- 默认的Standard分词器对中文支持不是很友好,比如
#字段是text类型 POST /my_index/_analyze { "field": "title", "text": "我今天去小滴课堂学习spring cloud项目大课" } #结果如下,中文每个字单独一个词 { "tokens": [ { "token": "我", "start_offset": 0, "end_offset": 1, "type": "<IDEOGRAPHIC>", "position": 0 }, { "token": "今", }, { "token": "天", }, ...... { "token": "spring", "start_offset": 10, "end_offset": 16, "type": "<ALPHANUM>", "position": 10 }, { "token": "cloud", "start_offset": 17, "end_offset": 22, "type": "<ALPHANUM>", "position": 11 }, { "token": "项", "start_offset": 22, "end_offset": 23, "type": "<IDEOGRAPHIC>", "position": 12 }, { "token": "目", "start_offset": 23, "end_offset": 24, "type": "<IDEOGRAPHIC>", "position": 13 }, ] }
- 什么是IK分词器
- 是一个基于Java开发的开源中文分词器,用于将中文文本拆分成单个词语(词项)
- 是针对中文语言的特点和需求而设计的,可以有效处理中文分词的复杂性和多样性
- 地址
官网:https://github.com/medcl/elasticsearch-analysis-ik/releases 安装包: 链接:https://pan.baidu.com/s/1ZwyxlYGX7XszDKVNoZAx5Q?pwd=84jb 提取码:84jb
- 注意:Elastic Search版本和IK分词器版本需要对应
- 特点
- 高效且灵活
- IK分词器采用了多种算法和数据结构,以提供高效的分词速度。
- 支持细粒度的分词,可以根据应用需求进行灵活的配置。
- 分词准确性
- IK分词器使用了词典和规则来进行分词,可以准确地将句子拆分成词语。
- 还提供了词性标注功能,可以帮助识别词语的不同含义和用途。
- 支持远程扩展词库
- IK分词器可以通过配置和加载外部词典,扩展分词的能力
- 用户可以根据实际需求,添加自定义的词典,提升分词准确性和覆盖范围。
- 兼容性与集成性
- IK分词器兼容了Lucene和Elasticsearch等主流搜索引擎,可以方便地集成到这些系统中。
- 提供了相应的插件和配置选项,使得分词器的集成变得简单。
- 高效且灵活
- 安装
- 解压,上传到Elastic Search的plugins目录
- 重启Elastic Search即可
#关闭Elasticsearch节点 bin/elasticsearch -d #检查进程是否已经停止 ps -ef | grep elasticsearch
- IK有两种颗粒度的拆分
-
ik_smart: 会做最粗粒度的拆分
-
ik_max_word(常用): 会将文本做最细粒度的拆分
-
案例实践
GET /_analyze { "text":"今天星期一,我今天去小滴课堂学习spring cloud项目大课", "analyzer":"ik_smart" }
GET /_analyze { "text":"今天星期一,我今天去小滴课堂学习spring cloud项目大课", "analyzer":"ik_max_word" }
-
Query DSL语法和应用
- 什么是Query DSL
- Query DSL(Domain-Specific Language)是一种用于构建搜索查询的强大的领域特定查询语言
- 类似我们关系性数据库的SQL查询语法,
- ES中用JSON结构化的方式定义和执行各种查询操作,在ES中进行高级搜索和过滤
基本语法
GET /索引库名/_search
{
"query":{
"查询类型":{
}
}
- 数据准备
PUT /xdclass_shop_v1
{
"settings": {
"number_of_shards": 2,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"title": {
"type": "keyword"
},
"summary": {
"type": "text"
},
"price": {
"type": "float"
}
}
}
}
PUT /xdclass_shop_v1/_bulk
{ "index": { "_index": "xdclass_shop_v1" } }
{ "id": "1", "title": "Spring Boot","summary":"this is a summary Spring Boot video", "price": 9.99 }
{ "index": { "_index": "xdclass_shop_v1" } }
{ "id": "2", "title": "java","summary":"this is a summary java video", "price": 19.99 }
{ "index": { "_index": "xdclass_shop_v1" } }
{ "id": "3", "title": "Spring Cloud","summary":"this is a summary Spring Cloud video", "price": 29.99 }
{ "index": { "_index": "xdclass_shop_v1" } }
{ "id": "4", "title": "Spring_Boot", "summary":"this is a summary Spring_Boot video","price": 59.99 }
{ "index": { "_index": "xdclass_shop_v1" } }
{ "id": "5", "title": "SpringBoot","summary":"this is a summary SpringBoot video", "price": 0.99 }
match_all 查询全部数据
GET /xdclass_shop_v1/_search
{
"query": {
"match_all": {}
}
}
match 分词查询
- 对查询内容进行分词, 然后进行查询,多个词条之间是 or的关系
- 然后在与文档里面的分词进行匹配,匹配度越高分数越高越前面
GET /xdclass_shop_v1/_search { "query": { "match": { "summary": "Spring" } } } #包括多个词(多个词之间是or的关系,匹配度越高排在前面) GET /xdclass_shop_v1/_search { "query": { "match": { "summary": "Spring Java" } } }
term 精确匹配
- 用于精确匹配一个指定字段的关键词,不进行分词处理
- 虽然match也可以完成,但是match查询会多一步进行分词,浪费资源
#keyword类型字段,ES不进行分词 GET /xdclass_shop_v1/_search { "query": { "term": { "title": { "value": "Spring Boot" } } } }
_source:获取指定字段
- 某些情况场景下,不需要返回全部字段,太废资源,可以指定source返回对应的字段
GET /xdclass_shop_v1/_search { "_source":["price","title"], "query": { "term": { "title": { "value": "Spring Boot" } } } }
range 范围查询
-
用于根据范围条件进行查询,例如指定价格在一定区间内的商品
-
范围符号
-
gte:大于等于
-
gt:大于
-
lte:小于等于
-
lt:小于
GET /xdclass_shop_v1/_search { "query": { "range": { "price": { "gte": 5, "lte": 100 } } } }
-
分页查询
-
可以使用 from 和 size 参数进行分页查询
-
可以指定要跳过的文档数量(from)和需要返回的文档数量(size)
GET /xdclass_shop_v1/_search { "size": 10, "from": 0, "query": { "match_all": {} } }
sort查询结果排序
-
sort字段可以进行排序 desc 和 asc
GET /xdclass_shop_v1/_search { "size": 10, "from": 0, "sort": [ { "price": "asc" } ], "query": { "match_all": {} } }
bool 查询
-
通过组合多个查询条件,使用布尔逻辑(与、或、非)进行复杂的查询操作
-
语法格式
-
"must"关键字用于指定必须匹配的条件,即所有条件都必须满足
-
"must_not"关键字指定必须不匹配的条件,即所有条件都不能满足
-
"should"关键字指定可选的匹配条件,即至少满足一个条件
{ "query": { "bool": { "must": [ // 必须匹配的条件 ], "must_not": [ // 必须不匹配的条件 ], "should": [ // 可选匹配的条件 ], "filter": [ // 过滤条件 ] } } }
-
-
案例实战
GET /xdclass_shop_v1/_search { "query": { "bool": { "must": [ { "match": { "summary": "Cloud" }}, { "range": { "price": { "gte": 5 }}} ] } } }
filter查询
-
来对搜索结果进行筛选和过滤,仅返回符合特定条件的文档,而不改变搜索评分
-
Filter查询对结果进行缓存,提高查询性能,用于数字范围、日期范围、布尔逻辑、存在性检查等各种过滤操作。
-
语法格式
- "filter"关键字用于指定一个过滤条件,可以是一个具体的过滤器,如term、range等,也可以是一个嵌套的bool过滤器
{ "query": { "bool": { "filter": { // 过滤条件 } } } }
-
案例实战
PUT /product { "settings": { "number_of_shards": 2, "number_of_replicas": 0 }, "mappings": { "properties": { "product_id": { "type": "integer" }, "product_name": { "type": "text" }, "category": { "type": "keyword" }, "price": { "type": "float" }, "availability": { "type": "boolean" } } } } POST /product/_bulk { "index": { "_id": "1" } } { "product_id": 1, "product_name": "Product 1", "category": "books", "price": 19.99, "availability": true } { "index": { "_id": "2" } } { "product_id": 2, "product_name": "Product 2", "category": "electronics", "price": 29.99, "availability": true } { "index": { "_id": "3" } } { "product_id": 3, "product_name": "Product 3", "category": "books", "price": 9.99, "availability": false } { "index": { "_id": "4" } } { "product_id": 4, "product_name": "Product 4", "category": "electronics", "price": 49.99, "availability": true } { "index": { "_id": "5" } } { "product_id": 5, "product_name": "Product 5", "category": "fashion", "price": 39.99, "availability": true }
-
案例一 :使用 term 过滤器查询 category 为 books 的产品:
GET /product/_search { "query": { "bool": { "filter": { "term": { "category": "books" } } } } }
-
案例二:使用 range 过滤器查询价格 price 在 30 到 50 之间的产品:
GET /product/_search { "query": { "bool": { "filter": { "range": { "price": { "gte": 30, "lte": 50 } } } } } }
-
总结
-
过滤条件通常用于对结果进行筛选,并且比查询条件更高效
-
而bool查询可以根据具体需求组合多个条件、过滤器和查询子句
-
multi_match多字段匹配
- 业务查询,需要在多个字段上进行文本搜索,用 multi_match
- 在 match的基础上支持对多个字段进行文本查询匹配
- 语法格式
GET /index/_search { "query": { "multi_match": { "query": "要搜索的文本", "fields": ["字段1", "字段2", ...] } } } # query:需要匹配的查询文本。 # fields:一个包含需要进行匹配的字段列表的数组。
- 案例
#数据准备 PUT /product_v2 { "settings": { "number_of_shards": 2, "number_of_replicas": 0 }, "mappings": { "properties": { "product_name": { "type": "text" }, "description": { "type": "text" }, "category": { "type": "keyword" } } } } POST /product_v2/_bulk { "index": { "_index": "product_v2", "_id": "1" } } { "product_name": "iPhone 12", "description": "The latest iPhone model from Apple", "category": "electronics" } { "index": { "_index": "product_v2", "_id": "2" } } { "product_name": "Samsung Galaxy S21", "description": "High-performance Android smartphone", "category": "electronics" } { "index": { "_index": "product_v2", "_id": "3" } } { "product_name": "MacBook Pro", "description": "Powerful laptop for professionals", "category": "electronics" } { "index": { "_index": "product_v2", "_id": "4" } } { "product_name": "Harry Potter and the Philosopher's Stone", "description": "Fantasy novel by J.K. Rowling", "category": "books" } { "index": { "_index": "product_v2", "_id": "5" } } { "product_name": "The Great Gatsby", "description": "Classic novel by F. Scott Fitzgerald", "category": "books" }
- 在 product_name 和 description 字段上执行了一个multi_match查询
- 将查询文本设置为 “iPhone”,对这两个字段进行搜索,并返回包含匹配到的文档,这个是OR的关系,会有最佳匹配
GET /product_v2/_search { "query": { "multi_match": { "query": "iPhone", "fields": ["product_name", "description"] } } }
match_phrase 短语搜索匹配
-
是Elasticsearch中提供的一种高级匹配查询类型,用于执行精确的短语搜索
-
相比于match查询,match_phrase会在匹配时考虑到单词之间的顺序和位置
-
语法格式
GET /index/_search { "query": { "match_phrase": { "field_name": { "query": "要搜索的短语" } } } } # field_name:要进行匹配的字段名。 # query:要搜索的短语。
-
案例
- 使用match_phrase查询在description字段上执行了一个短语搜索将要搜索的短语设置为 “classic novel”。
- 使用match_phrase查询,Elasticsearch将会返回包含 “classic novel” 短语的文档
#match_phrase短语搜索 GET /product_v2/_search { "query": { "match_phrase": { "description": "classic novel" } } }
#match搜索,会进行分词 GET /product_v2/_search { "query": { "match": { "description": "classic novel" } } }
fuzzy模糊查询
-
fuzzy查询是Elasticsearch中提供的一种模糊匹配查询类型,用在搜索时容忍一些拼写错误或近似匹配
-
使用fuzzy查询,可以根据指定的编辑距离(即词之间不同字符的数量)来模糊匹配查询词
-
拓展:编辑距离
-
是将一个术语转换为另一个术语所需的一个字符更改的次数。
-
比如
-
更改字符(box→fox)
-
删除字符(black→lack)
-
插入字符(sic→sick)
-
转置两个相邻字符(dgo→dog)
-
-
-
fuzzy模糊查询是拼写错误的简单解决方案,但具有很高的 CPU 开销和非常低的精准度
-
用法和match基本一致,Fuzzy query的查询不分词
-
基本语法格式
GET /index/_search { "query": { "fuzzy": { "field_name": { "value": "要搜索的词", "fuzziness": "模糊度" } } } }
-
解析
-
field_name:要进行模糊匹配的字段名。
-
value:要搜索的词
-
fuzziness参数指定了模糊度,常见值如下
-
0,1,2
-
指定数字,表示允许的最大编辑距离,较低的数字表示更严格的匹配,较高的数字表示更松散的匹配
-
fuziness的值,表示是针对每个词语而言的,而不是总的错误的数值
-
-
AUTO:Elasticsearch根据词的长度自动选择模糊度
-
如果字符串的长度大于5,那 funziness 的值自动设置为2
-
如果字符串的长度小于2,那么 fuziness 的值自动设置为 0
-
-
-
-
案例操作
# 指定模糊度2,更松散匹配 GET /xdclass_shop_v1/_search { "query": { "fuzzy": { "summary": { "value": "clo", "fuzziness": "2" } } } }
# 指定模糊度1,更严格匹配 GET /xdclass_shop_v1/_search { "query": { "fuzzy": { "summary": { "value": "clo", "fuzziness": "1" } } } }
# 使用自动检查,1个单词拼写错误 GET /xdclass_shop_v1/_search { "query": { "fuzzy": { "summary": { "value": "Sprina", "fuzziness": "auto" } } } }
highlight 高亮显示
- 日常搜索产品的时候,会有关键词显示不一样的颜色,方便用户直观看到区别
- Elastic Search搜索引擎如何做到高亮显示
- 在 ES 中,高亮语法用于在搜索结果中突出显示与查询匹配的关键词
- 高亮显示是通过标签包裹匹配的文本来实现的,通常是 或其他 HTML 标签
- 基本用法:在 highlight 里面填写要高亮显示的字段,可以填写多个
- 案例实战
#创建索引库 PUT /xdclass_high_light_test { "mappings": { "properties": { "title": { "type": "text", "analyzer": "ik_max_word" }, "content": { "type": "text", "analyzer": "ik_max_word" } } }, "settings": { "number_of_shards": 2, "number_of_replicas": 0 } } #插入数据 PUT /xdclass_high_light_test/_doc/1 { "title": "小滴课堂2028年最新好看的电影推荐", "content": "每年都有新电影上线,2028年最新好看的电影有不少,小滴课堂上线了《架构大课》,《低代码平台》,《老王往事》精彩电影" } PUT /xdclass_high_light_test/_doc/2 { "title": "写下你认为好看的电影有哪些", "content": "每个人都看看很多电影,说下你近10年看过比较好的电影,比如《架构大课》,《海量数据项目大课》,《冰冰和老王的故事》" }
- 单条件查询高亮显示
GET /xdclass_high_light_test/_search { "query": { "match": { "content": "电影" } }, "highlight": { "fields": { "content": {} } } }
- 组合多条件查询,highlight里面填写需要高亮的字段
GET /xdclass_high_light_test/_search { "query": { "bool": { "should": [ { "match": { "title": "课堂" } }, { "match": { "content": "老王" } } ] } }, "highlight": { "fields": { "title": {}, "content": {} } } }
- 单条件查询高亮显示
- match查询,使用highlight属性,可以增加属性,修改高亮样式
-
pre_tags:前置标签
-
post_tags:后置标签
-
fields:需要高亮的字段
-
案例
GET /xdclass_high_light_test/_search { "query": { "bool": { "should": [ { "match": { "title": "课堂" } }, { "match": { "content": "老王" } } ] } }, "highlight": { "pre_tags": "<font color='yellow'>", "post_tags": "</font>", "fields": [{"title":{}},{"content":{}}] } }
-
聚合查询
什么是聚合查询
-
对大量数据聚合统计处理,类似Mysql数据库操作里面的group by 分组、sum、avg、max等函数处理
-
是 Elasticsearch 中强大的功能之一,根据数据进行分组、过滤、计算和统计,提取有关数据集信息,进行数据分析
-
数据可视化大屏里面的饼状图、柱状图、折线图、仪表盘数据等都是聚合查询的关键应用
-
术语一:对数据集求最大、最小、和、平均值等指标的聚合,称为 指标聚合 metric
- 基本语法格式如下
GET /index/_search { "size": 0, "aggs": { "aggregation_name": { "aggregation_type": { "aggregation_field": "field_name" // 可选参数 } } // 可以添加更多的聚合 } } # 解析 index:要执行聚合查询的索引名称。 size: 设置为 0 来仅返回聚合结果,而不返回实际的搜索结果,这里将hits改为0表示返回的原始数据变为0 aggs:指定聚合操作的容器。 aggregation_name:聚合名称,可以自定义。 aggregation_type:聚合操作的类型,例如 terms、avg、sum 等。 aggregation_field:聚合操作的目标字段,对哪些字段进行聚合
-
术语二:对数据集进行分组group by,然后在组上进行指标聚合,在 ES 中称为分桶,桶聚合bucketing
- 基本语法格式如下(先简单知道,后续会有进一步讲解)
GET /index/_search { "size": 0, "aggs": { "aggregation_name": { "bucket_type": { "bucket_options": { "bucket_option_name": "bucket_option_value", ... }, "aggs": { "sub_aggregation_name": { "sub_aggregation_type": { "sub_aggregation_options": { "sub_aggregation_option_name": "sub_aggregation_option_value", ... } } } } } } } } #解析 index: 替换为要执行聚合查询的索引名称。 aggregation_name: 替换为自定义的聚合名称。 bucket_type: 替换为特定的桶聚合类型(如 terms、date_histogram、range 等)。 bucket_option_name 和 bucket_option_value: 替换为特定桶聚合选项的名称和值。 sub_aggregation_name: 替换为子聚合的名称。 sub_aggregation_type: 替换为特定的子聚合类型(如 sum、avg、max、min 等)。 sub_aggregation_option_name 和 sub_aggregation_option_value: 替换为特定子聚合选项的名称和值
-
常见聚合用途和应用场景案例
-
聚合指标(Aggregation Metrics):
-
Avg Aggregation:计算文档字段的平均值。
-
Sum Aggregation:计算文档字段的总和。
-
Min Aggregation:找到文档字段的最小值。
-
Max Aggregation:找到文档字段的最大值。
-
-
聚合桶(Aggregation Buckets):
-
Terms Aggregation:基于字段值将文档分组到不同的桶中。
-
Date Histogram Aggregation:按日期/时间字段创建时间间隔的桶。
-
Range Aggregation:根据字段值的范围创建桶。
-
-
指标聚合案例实战
-
聚合查询 max 应用案例:
- 数据准备:假设有一个电商网站的销售记录索引,包含商品名称和销售价格字段
POST /sales_v1/_doc { "product_name": "手机", "price": 1000 } POST /sales_v1/_doc { "product_name": "电视", "price": 1500 } POST /sales_v1/_doc { "product_name": "小滴课堂老王的黑丝", "price": 4500 }
- 案例说明:使用 max 聚合查询来获取产品价格的最高值。
GET /sales_v1/_search { "size": 0, "aggs": { "max_price": { "max": { "field": "price" } } } }
- 数据准备:假设有一个电商网站的销售记录索引,包含商品名称和销售价格字段
-
聚合查询 - min 应用案例:
- 数据准备:一个学生考试成绩索引,包含学生姓名和考试分数字段。
POST /exam_scores/_doc { "student_name": "小滴课堂-大钊", "score" : 80 } POST /exam_scores/_doc { "student_name": "老王", "score" : 90 } POST /exam_scores/_doc { "student_name": "小滴课堂-D哥", "score" : 40 }
- 案例说明:使用 min 聚合查询来获取学生的最低考试分数。
GET /exam_scores/_search { "size": 0, "aggs": { "min_score": { "min": { "field": "score" } } } }
- 数据准备:一个学生考试成绩索引,包含学生姓名和考试分数字段。
-
聚合查询 - avg 应用案例:
- 数据准备(同上):一个学生考试成绩索引,包含学生姓名和考试分数字段。
- 使用 avg 聚合查询来计算学生的平均考试分数
GET /exam_scores/_search { "size": 0, "aggs": { "avg_score": { "avg": { "field": "score" } } } }
-
聚合查询 - sum 应用案例:
- 数据准备:假设有一个电商网站的销售记录索引,包含商品名称和销售数量字段。
POST /sales_order/_doc { "product_name": "手机", "sales_count" : 100 } POST /sales_order/_doc { "product_name": "电视", "sales_count" : 50 } POST /sales_order/_doc { "product_name": "小滴课堂永久会员", "sales_count" : 999 }
- 案例说明:使用 sum 聚合查询来计算销售记录的总销售数量。
GET /sales_order/_search { "size": 0, "aggs": { "total_sales": { "sum": { "field": "sales_count" } } } }
- 数据准备:假设有一个电商网站的销售记录索引,包含商品名称和销售数量字段。
桶聚合案例实战
-
分桶聚合查询 - Terms 案例:
-
数据准备:假设有一个在线书店的图书销售记录索引,包含图书名称和销售数量字段。
#创建索引库 PUT /book_sales { "mappings": { "properties": { "book_title": { "type": "keyword" }, "sales_count": { "type": "integer" } } }, "settings": { "number_of_shards": 2, "number_of_replicas": 0 } } # 批量插入数据 POST /book_sales/_bulk { "index": {} } { "book_title": "Elasticsearch in Action", "sales_count" : 100 } { "index": {} } { "book_title": "小滴课堂微服务最佳实践", "sales_count" : 50 } { "index": {} } { "book_title": "海量数据项目大课", "sales_count" : 80 } { "index": {} } { "book_title": "小滴课堂面试宝典", "sales_count" : 120 } { "index": {} } { "book_title": "数据结构与算法之美", "sales_count" : 90 } { "index": {} } { "book_title": "Python编程快速上手", "sales_count" : 70 } { "index": {} } { "book_title": "小滴课堂面试宝典", "sales_count" : 110 } { "index": {} } { "book_title": "小滴课堂Java核心技术", "sales_count" : 200 } { "index": {} } { "book_title": "深入理解计算机系统", "sales_count" : 150 } { "index": {} } { "book_title": "小滴课堂Java核心技术", "sales_count" : 80 }
-
案例说明:使用 terms 聚合查询将图书按销售数量进行分桶,并获取每个分桶内的销售数量总和。
GET /book_sales/_search { "size": 0, "aggs": { "book_buckets": { "terms": { "field": "book_title", "size": 10 }, "aggs": { "total_sales": { "sum": { "field": "sales_count" } } } } } }
-
-
分桶聚合查询 - Date Histogram
-
将日期类型的字段按照固定的时间间隔进行分桶,并对每个时间间隔内的文档进行进一步的操作和计算
-
基本语法如下
GET /index/_search { "size": 0, "aggs": { "date_histogram_name": { "date_histogram": { "field": "date_field_name", "interval": "interval_expression" }, "aggs": { "sub_aggregation": { "sub_aggregation_type": {} } } } } } #解析 index:替换为要执行聚合查询的索引名称。 date_histogram_name:替换为自定义的 date_histogram 聚合名称。 date_field_name:替换为要聚合的日期类型字段名。 interval_expression:指定用于分桶的时间间隔。时间间隔可以是一个有效的日期格式(如 1d、1w、1M),也可以是一个数字加上一个时间单位的组合(如 7d 表示 7 天,1h 表示 1 小时)。 sub_aggregation:指定在每个日期桶内进行的子聚合操作。 sub_aggregation_type:替换单独子聚合操作的类型,可以是任何有效的子聚合类型。
-
数据准备:一个电商网站的订单索引,包含订单日期和订单金额字段。
POST /order_history/_bulk { "index": {} } { "order_date": "2025-01-01", "amount" : 100 ,"book_title": "小滴课堂Java核心技术"} { "index": {} } { "order_date": "2025-02-05", "amount" : 150, "book_title": "小滴课堂面试宝典" } { "index": {} } { "order_date": "2025-03-02", "amount" : 500 ,"book_title": "小滴课堂Java核心技术"} { "index": {} } { "order_date": "2025-05-02", "amount" : 250 , "book_title": "小滴课堂面试宝典"} { "index": {} } { "order_date": "2025-05-05", "amount" : 10 ,"book_title": "小滴课堂微服务最佳实践"} { "index": {} } { "order_date": "2025-02-18", "amount" : 290 , "book_title": "小滴课堂微服务最佳实践"}
-
案例说明:使用 date_histogram 聚合查询将订单按日期进行分桶,并计算每个分桶内的订单金额总和。
GET /order_history/_search { "size": 0, "aggs": { "sales_per_month": { "date_histogram": { "field": "order_date", "calendar_interval": "month", "format": "yyyy-MM" }, "aggs": { "total_sales": { "sum": { "field": "amount" } } } } } }
-
-
分桶聚合查询 - Range
-
将字段的值划分为不同的范围,并将每个范围内的文档分配给相应的桶,对这些范围进行各种操作和计算。
-
语法介绍
GET /index/_search { "size": 0, "aggs": { "range_name": { "range": { "field": "field_name", "ranges": [ { "key": "range_key_1", "from": from_value_1, "to": to_value_1 }, { "key": "range_key_2", "from": from_value_2, "to": to_value_2 }, ... ] }, "aggs": { "sub_aggregation": { "sub_aggregation_type": {} } } } } } #解析 index:替换为要执行聚合查询的索引名称。 range_name:替换为自定义的 range 聚合名称。 field_name:替换为要聚合的字段名。 ranges:指定范围数组,每个范围使用 key、from 和 to 参数进行定义。 key:范围的唯一标识符。 from:范围的起始值(包含)。 to:范围的结束值(不包含)。 sub_aggregation:指定在每个范围内进行的子聚合操作。 sub_aggregation_type:替换单独子聚合操作的类型,可以是任何有效的子聚合类型。
-
数据准备:一个在线商店的商品索引,包括商品名称和价格字段
POST /product_v4/_bulk { "index": {} } { "product_name": "小滴课堂永久会员", "price" : 2000 } { "index": {} } { "product_name": "JVM专题课程", "price" : 200 } { "index": {} } { "product_name": "SpringBoot3.X最佳实践", "price" : 300 } { "index": {} } { "product_name": "高并发项目大课", "price" : 1500 } { "index": {} } { "product_name": "海量数据项目大课", "price" : 4120 } { "index": {} } { "product_name": "监控告警Prometheus最佳实践", "price" : 180 } { "index": {} } { "product_name": "全栈工程师学习路线", "price" : 250 } { "index": {} } { "product_name": "自动化测试平台大课", "price" : 4770 } { "index": {} } { "product_name": "小滴课堂-老王分手最佳实践", "price" : 400 } { "index": {} } { "product_name": "小滴课堂-大钊会所按摩往事", "price" : 150 }
-
案例说明:使用 range 聚合查询将商品按价格范围进行分桶,并计算每个分桶内的商品数量。
- 如果没写key,则会默认生成
GET /product_v4/_search { "size": 0, "aggs": { "price_ranges": { "range": { "field": "price", "ranges": [ { "to": 100 }, { "from": 100, "to": 200 }, { "from": 200 } ] } } } }
-
SpringBoot3.X整合ElasticSearch8.X
-
使用 Spring Data Elasticsearch
-
基于 Spring Data 的标准化数据访问技术,简化了与 Elasticsearch 的集成。
-
提供了丰富的 CRUD 操作和查询方法,简化了数据访问,包括自动化的索引管理和映射
-
Spring Data Elasticsearch 对于一些高级功能和复杂查询可能不够灵活,需要额外定制处理
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> spring.elasticsearch.uris=http://112.74.167.42:9200
-
-
什么是ElasticsearchTemplate
-
是 Spring Data Elasticsearch 提供的一个核心类,是 ElasticsearchClient 的一个具体实现
-
用于在 Spring Boot 中操作 Elasticsearch 进行数据的存取和查询
-
提供了一组方法来执行各种操作,如保存、更新、删除和查询文档,执行聚合操作等
-
-
ElasticsearchTemplate 的一些常用方法
-
save(Object): 保存一个对象到 Elasticsearch 中。
-
index(IndexQuery): 使用 IndexQuery 对象执行索引操作。
-
delete(String, String): 删除指定索引和类型的文档。
-
get(String, String): 获取指定索引和类型的文档。
-
update(UpdateQuery): 使用 UpdateQuery 对象执行更新操作。
-
search(SearchQuery, Class): 执行搜索查询,并将结果映射为指定类型的对象。
-
count(SearchQuery, Class): 执行搜索查询,并返回结果的计数
-
-
ElasticsearchTemplate 常见注解配置(都是属于spring data elasticsearch)
-
@Id 指定主键
-
@Document指定实体类和索引对应关系
indexName:索引名称
-
@Field指定普通属性
type 对应Elasticsearch中属性类型,使用FiledType枚举快速获取。 text 类型能被分词 keywords 不能被分词 index 是否创建索引,作为搜索条件时index必须为true analyzer 指定分词器类型。
-
index索引库操作
-
创建DTO
@Document(indexName = "video") public class VideoDTO { @Id @Field(type = FieldType.Text, index = false) private Long id; @Field(type = FieldType.Text) private String title; @Field(type = FieldType.Text) private String description; @Field(type = FieldType.Keyword) private String category; @Field(type = FieldType.Integer) private Integer duration; @Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second) private LocalDateTime createTime; public VideoDTO(){} public VideoDTO(Long id, String title, String description, Integer duration,String category) { this.id = id; this.title = title; this.description = description; this.duration = duration; this.createTime = LocalDateTime.now(); this.category = category; } //省略set get方法 }
-
创建测试方法
@SpringBootTest class XdclassEsProjectApplicationTests { @Autowired private ElasticsearchTemplate restTemplate; /** * 判断索引是否存在索引 */ @Test void existsIndex() { IndexOperations indexOperations = restTemplate.indexOps(VideoDTO.class); boolean exists = indexOperations.exists(); System.out.println(exists); } /** * 创建索引 */ @Test void createIndex() { // spring data es所有索引操作都在这个接口 IndexOperations indexOperations = restTemplate.indexOps(VideoDTO.class); // 是否存在,存在则删除 if(indexOperations.exists()){ indexOperations.delete(); } // 创建索引 indexOperations.create(); //设置映射: 在正式开发中,几乎不会使用框架创建索引或设置映射,这是架构或者管理员的工作,不适合使用代码实现 restTemplate.indexOps(VideoDTO.class).putMapping(); } /** * 删除索引 */ @Test void deleteIndex() { IndexOperations indexOperations = restTemplate.indexOps(VideoDTO.class); boolean delete = indexOperations.delete(); System.out.println(delete); } }
操作Document
-
案例一 新增文档
@Test void insert(){ VideoDTO videoDTO = new VideoDTO(); videoDTO.setId(1L); videoDTO.setTitle("小滴课堂架构大课和Spring Cloud"); videoDTO.setCreateTime(LocalDateTime.now()); videoDTO.setDuration(100); videoDTO.setCategory("后端"); videoDTO.setDescription("这个是综合大型课程,包括了jvm,redis,新版spring boot3.x,架构,监控,性能优化,算法,高并发等多方面内容"); VideoDTO saved = restTemplate.save(videoDTO); System.out.println(saved); }
-
案例二 更新文档
@Test void update(){ VideoDTO videoDTO = new VideoDTO(); videoDTO.setId(1L); videoDTO.setTitle("小滴课堂架构大课和Spring Cloud V2"); videoDTO.setCreateTime(LocalDateTime.now()); videoDTO.setDuration(102); videoDTO.setCategory("后端"); videoDTO.setDescription("这个是综合大型课程,包括了jvm,redis,新版spring boot3.x,架构,监控,性能优化,算法,高并发等多方面内容"); VideoDTO saved = restTemplate.save(videoDTO); System.out.println(saved); }
-
案例三 批量插入
@Test void batchInsert() { List<VideoDTO> list = new ArrayList<>(); list.add(new VideoDTO(2L, "老王录制的按摩课程", "主要按摩和会所推荐", 123, "后端")); list.add(new VideoDTO(3L, "冰冰的前端性能优化", "前端高手系列", 100042, "前端")); list.add(new VideoDTO(4L, "海量数据项目大课", "D哥的后端+大数据综合课程", 5432345, "后端")); list.add(new VideoDTO(5L, "小滴课堂永久会员", "可以看海量专题课程,IT技术持续充电平台", 6542, "后端")); list.add(new VideoDTO(6L, "大钊-前端低代码平台", "高效开发底层基础平台,效能平台案例", 53422, "前端")); list.add(new VideoDTO(7L, "自动化测试平台大课", "微服务架构下的spring cloud架构大课,包括jvm,效能平台", 6542, "后端")); Iterable<VideoDTO> result = restTemplate.save(list); System.out.println(result); }
-
案例四 根据主键查询
@Test void searchById(){ VideoDTO videoDTO = restTemplate.get("3", VideoDTO.class); assert videoDTO != null; System.out.println(videoDTO); }
-
案例五 根据id删除
@Test void deleteById() { String delete = restTemplate.delete("2", VideoDTO.class); System.out.println(delete); }
多案例搜索实战
ElasticSearch的Query接口
- Query是Spring Data Elasticsearch的接口,有多种具体实现
- CriteriaQuery
- 创建Criteria来搜索数据,而无需了解 Elasticsearch 查询的语法或基础知识
- 允许用户通过简单地连接和组合,指定搜索文档必须满足的对象来构建查询
- StringQuery
- 将Elasticsearch查询作为JSON字符串,更适合对Elasticsearch查询的语法比较了解的人
- 也更方便使用kibana或postman等客户端工具行进调试
- NativeQuery
- 复杂查询或无法使用CriteriaAPI 表达的查询时使用的类,例如在构建查询和使用聚合的场景
- CriteriaQuery
NativeQuery案例
-
案例一:搜索全部
/** - 查询所有 */ @Test void searchAll(){ SearchHits<VideoDTO> search = restTemplate.search(Query.findAll(), VideoDTO.class); List<SearchHit<VideoDTO>> searchHits = search.getSearchHits(); // 获得searchHits,进行遍历得到content List<VideoDTO> videoDTOS = new ArrayList<>(); searchHits.forEach(hit -> { videoDTOS.add(hit.getContent()); }); System.out.println(videoDTOS); }
-
案例二:匹配搜索
/** * match查询 */ @Test void matchQuery(){ Query query = NativeQuery.builder().withQuery(q -> q .match(m -> m .field("description") //字段 .query("spring") //值 )).build(); SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class); // 获得searchHits,进行遍历得到content List<VideoDTO> videoDTOS = new ArrayList<>(); searchHits.forEach(hit -> { videoDTOS.add(hit.getContent()); }); System.out.println(videoDTOS); }
-
案例三:分页搜索
/** * 分页查询 */ @Test void pageSearch() { Query query = NativeQuery.builder().withQuery(Query.findAll()) .withPageable(Pageable.ofSize(3).withPage(0)).build(); SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class); // 获得searchHits,进行遍历得到content List<VideoDTO> videoDTOS = new ArrayList<>(); searchHits.forEach(hit -> { videoDTOS.add(hit.getContent()); }); System.out.println(videoDTOS); }
-
案例四:搜索排序,withSort() 需要传入 Sort 对象,.by代表根据一个字段进行排序
-
.ascending() 方法:默认的,正序排序
-
.descending()方法:倒叙排序
/** * 排序查询,根据时长降序排列 */ @Test void sortSearch() { Query query = NativeQuery.builder().withQuery(Query.findAll()) .withPageable(Pageable.ofSize(10).withPage(0)) .withSort(Sort.by("duration").descending()).build(); SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class); // 获得searchHits,进行遍历得到content List<VideoDTO> videoDTOS = new ArrayList<>(); searchHits.forEach(hit -> { videoDTOS.add(hit.getContent()); }); System.out.println(videoDTOS); }
-
StringQuery 案例
-
案例:布尔must查询,搜索标题有 架构 关键词,描述有 spring关键字,时长范围是 10~6000之间的
-
原始DSL查询
GET /video/_search { "query": { "bool": { "must": [{ "match": { "title": "架构" } }, { "match": { "description": "spring" } }, { "range": { "duration": { "gte": 10, "lte": 6000 } } }] } } }
-
SpringBoot+SpringData查询
@Test void stringQuery() { //搜索标题有 架构 关键词,描述有 spring关键字,时长范围是 10~6000之间的 String dsl = """ {"bool":{"must":[{"match":{"title":"架构"}},{"match":{"description":"spring"}},{"range":{"duration":{"gte":10,"lte":6000}}}]}} """; Query query = new StringQuery(dsl); List<SearchHit<VideoDTO>> searchHitList = restTemplate.search(query, VideoDTO.class).getSearchHits(); // 获得searchHits,进行遍历得到content List<VideoDTO> videoDTOS = new ArrayList<>(); searchHitList.forEach(hit -> { videoDTOS.add(hit.getContent()); }); System.out.println(videoDTOS); }
聚合搜索案例实战
-
方案一:可以使用原始DSL进行处理
-
方案二:使用NativeQuery完成聚合搜索
-
案例实战:统计不同分类下的视频数量
/**
* 聚合查询
*/
@Test
void aggQuery() {
Query query = NativeQuery.builder()
.withAggregation("category_group", Aggregation.of(a -> a
.terms(ta -> ta.field("category").size(2))))
.build();
SearchHits<VideoDTO> searchHits = restTemplate.search(query, VideoDTO.class);
//获取聚合数据
ElasticsearchAggregations aggregationsContainer = (ElasticsearchAggregations) searchHits.getAggregations();
Map<String, ElasticsearchAggregation> aggregations = Objects.requireNonNull(aggregationsContainer).aggregationsAsMap();
//获取对应名称的聚合
ElasticsearchAggregation aggregation = aggregations.get("category_group");
Buckets<StringTermsBucket> buckets = aggregation.aggregation().getAggregate().sterms().buckets();
//打印聚合信息
buckets.array().forEach(bucket -> {
System.out.println("组名:"+bucket.key().stringValue() + ", 值" + bucket.docCount());
});
// 获得searchHits,进行遍历得到content
List<VideoDTO> videoDTOS = new ArrayList<>();
searchHits.forEach(hit -> {
videoDTOS.add(hit.getContent());
});
System.out.println(videoDTOS);
}
ElasticSearch8.X高可用集群搭建实战
介绍
- 需求背景
- 生产环境中 Elastic Search基本不可能单机部署,采用高可用集群架构
- 高可用集群架构是指在生产环境中使用多台服务器来部署Elasticsearch,以实现数据的冗余和故障容错
- Elasticsearch高可用集群架构常见概念
- 集群(Cluster)
- 集群是由多个节点组成的Elasticsearch实例的集合,
- 集群共享相同的索引和数据,并协同工作以提供高可用性和性能
- 节点(Node)
- 节点是运行在单个服务器上的Elasticsearch实例
- 一个节点可以容纳多个分片,每个节点都有一个唯一的名称和地址。
- 分片(Shard)
- 分片是数据的基本单元,在分布式环境中将索引的数据划分成多个分片存储在不同的节点上
- 主分片负责处理读写请求,副本分片用于数据的冗余和故障转移
- search 相关请求可以由主分片处理,也可以由副本分片处理
- 选主(Master Election)
- 在一个集群中,通过选举机制选择一个主节点进行集群管理和控制
- 主节点负责分配和管理主分片,而非主节点则负责处理读请求和副本分片。
- 集群发现(Cluster Discovery)
- 集群发现是指节点之间自动发现和加入集群的过程
- Elasticsearch提供了多种集群发现机制,如多播发现、单播发现、云发现等。
- 集群(Cluster)
- 查看节点角色
- 集群中有多个节点角色的时候,就需要手动设定、配置节点的角色
- 不手动设置节点角色,默认节点角色如下所示
GET _cat/nodes?v ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name 172.17.0.1 57 84 1 0.00 0.02 0.05 cdfhilmrstw * node-1
- 拓展
C:Coordinating Node(协调节点):负责请求的路由和负载均衡,不存储数据。 D:Data Node(数据节点):存储数据并执行数据相关的操作,如索引和搜索。 F:Fetch Node(提取节点):从其他节点获取数据,协助执行分布式搜索。 H:HTTP Node(HTTP 节点):可以使用HTTP协议与之通信的节点。 I:Ingest Node(摄取节点):对文档进行预处理,如转换和过滤。 L:Machine Learning Node(机器学习节点):运行机器学习任务。 M:Master Node(主节点):负责集群管理和控制,如选主、分配分片等。 R:Remote Client Node(远程客户端节点):允许远程客户端连接的节点。 S:Scripting Node(脚本节点):负责脚本的评估和执行。 T:Transform Node(转换节点):执行转换任务,将源索引数据转换为目标索引。 W:ML Datafeed Node(机器学习数据源节点):用于处理机器学习数据源。
- Elasticsearch集群三种主要类型的节点
- 主节点(Master Node)
- 功能
- 主节点负责集群管理、控制和协调操作,包括分配和管理主分片,并参与选主过程。
- 用途
- 在集群中,通常有一个或多个主节点,主节点的数量取决于集群的规模和要求
- 主节点一般不参与数据的读写操作,它只负责协调工作
默认的是主节点+数据节点(master+data) ,节点可以成为主节点的资格,又可以存储数据 node.master: true node.data: true
- 功能
- 数据节点(Data Node)
- 功能
- 数据节点负责存储和处理数据,包括索引、搜索和查询等操作。数据节点接收客户端的读写请求,执行各种操作
- 处理数据相关,如 CRUD、搜索和聚合,是 I/O 密集型、内存密集型和 CPU 密集型的,需要大量的CPU、内存和IO
- 用途
- 在生产环境中,一般会有多个数据节点,以存储和处理大量的数据
- 数据节点可以水平扩展,提供更高的性能和容量
节点没有成为主节点的资格,不参与选举,只存储数据 node.master: false node.data: true
- 功能
- 协调节点(Coordinating Node)
- 功能
- 是一个无数据节点,用于负载均衡和请求协调。它接收客户端的读写请求,并将它们转发给合适的数据节点进行处理。
- 用途
- 在高负载情况下,协调节点可以平衡请求的分发,提高系统的性能和吞吐量。还可以缓存结果,减轻数据节点的压力
不能成为主节点,也不存储数据,主要是进行负载均衡 node.master: false node.data: false
- 功能
- 主节点(Master Node)
- 总结
- 一个节点可以充当一个或多个角色,默认三个角色都有
- 每种节点类型都有不同的功能和用途在生产环境中,通常的配置是将这些节点类型组合使用,实现高可用性和高性能
- 建议
- 小规模集群不需严格区分角色;
- 大规模集群则可以分开角色,并发量大可以增加独立协调节点和数据节点,提升处理能力
- 节点的数量和规模取决于数据量、性能需求和可用资源等因素
- 一个典型的Elasticsearch集群配置
- 3个主节点、5个数据节点和1个或多个协调节点,这样的配置可以实现高可用性、数据冗余和负载均衡
- 需要根据实际情况评估和调整节点的配置,以满足业务需求,也需要考虑硬件资源、网络带宽和数据量等因素。
Linux搭建Elastic Search8.X高可用集群
需要三台服务器,以下操作在三台服务器上均执行
-
上传安装包到 /usr/local/software/elk_test目录
-
解压
tar -zxvf elasticsearch-8.4.1-linux-x86_64.tar.gz
-
新建一个用户,安全考虑,elasticsearch默认不允许以root账号运行
创建用户:useradd es_user 设置密码:passwd es_user
-
修改目录权限
# chmod是更改文件的权限 # chown是改改文件的属主与属组 # chgrp只是更改文件的属组。 chgrp -R es_user /usr/local/software/elk_test/elasticsearch-8.4.1 chown -R es_user /usr/local/software/elk_test/elasticsearch-8.4.1 chmod -R 777 /usr/local/software/elk_test/elasticsearch-8.4.1
-
修改文件和进程最大打开数,需要root用户,如果系统本身有这个文件最大打开数和进程最大打开数配置,则不用
在文件内容最后添加后面两行(切记*不能省略) vim /etc/security/limits.conf * soft nofile 65536 * hard nofile 65536
-
修改虚拟内存空间,默认太小
在配置文件中改配置 最后一行上加上 vim /etc/sysctl.conf vm.max_map_count=262144 保存退出后执行 sysctl -p(立即生效)
-
修改elasticsearch的JVM内存,机器内存不足,常规线上推荐16到24G内存
vim config/jvm.options -Xms1g -Xmx1g
-
三台服务器构建3个节点(修改discovery.seed_hosts和cluster.initial_master_nodes)
-
节点一
vim config/elasticsearch.yml cluster.name: xdclass-cluster node.name: node-1 path.data: /usr/local/software/elk_test/elasticsearch-8.4.1/data path.logs: /usr/local/software/elk_test/elasticsearch-8.4.1/logs network.host: 0.0.0.0 http.port: 9200 discovery.seed_hosts: ["172.31.101.11:9300","172.31.101.13:9300","172.31.101.12:9300"] cluster.initial_master_nodes: ["172.31.101.11:9300","172.31.101.13:9300","172.31.101.12:9300"] xpack.security.enabled: false xpack.security.enrollment.enabled: false ingest.geoip.downloader.enabled: false
-
节点二
vim config/elasticsearch.yml cluster.name: xdclass-cluster node.name: node-2 path.data: /usr/local/software/elk_test/elasticsearch-8.4.1/data path.logs: /usr/local/software/elk_test/elasticsearch-8.4.1/logs network.host: 0.0.0.0 http.port: 9200 discovery.seed_hosts: ["172.31.101.11:9300","172.31.101.13:9300","172.31.101.12:9300"] cluster.initial_master_nodes: ["172.31.101.11:9300","172.31.101.13:9300","172.31.101.12:9300"] xpack.security.enabled: false xpack.security.enrollment.enabled: false ingest.geoip.downloader.enabled: false
-
节点三
vim config/elasticsearch.yml cluster.name: xdclass-cluster node.name: node-3 path.data: /usr/local/software/elk_test/elasticsearch-8.4.1/data path.logs: /usr/local/software/elk_test/elasticsearch-8.4.1/logs network.host: 0.0.0.0 http.port: 9200 discovery.seed_hosts: ["172.31.101.11:9300","172.31.101.13:9300","172.31.101.12:9300"] cluster.initial_master_nodes: ["172.31.101.11:9300","172.31.101.13:9300","172.31.101.12:9300"] xpack.security.enabled: false xpack.security.enrollment.enabled: false ingest.geoip.downloader.enabled: false
-
配置说明
-
discovery.seed_hosts参数:
-
功能:discovery.seed_hosts参数用于配置集群中用于发现其他节点的主机名或IP地址列表。
-
作用:每个节点通过这个参数指定其他节点的地址,以便在启动时进行发现和加入集群。
-
配置:在每个节点的elasticsearch.yml配置文件中设置该参数,指定其他节点的地址,多个地址使用逗号分隔。
-
-
cluster.initial_master_nodes参数:
-
功能:cluster.initial_master_nodes参数用于配置初始主节点的名称。
-
作用:当集群启动时,用于指定初始的主节点,以启动集群的选主过程。
-
配置:只需在初始启动的几个节点的elasticsearch.yml配置文件中设置该参数,列出节点名称。
-
-
注意
- cluster.initial_master_nodes参数和discovery.seed_hosts参数之间的设置应该保持一致,确保集群中的所有节点都能正确发现和加入。
-
-
-
启动ElasticSearch
切换到es_user用户启动, 进入bin目录下启动, &为后台启动,再次提示es消息时 Ctrl + c 跳出 ./elasticsearch &
-
常见命令,可以用postman访问(网络安全组记得开发端口)
#查看集群健康情况 http://112.74.167.42:9200/_cluster/health #查看分片情况 http://112.74.167.42:9200/_cat/shards?v=true&pretty #查看节点分布情况 http://112.74.167.42:9200/_cat/nodes?v=true&pretty #查看索引列表 http://112.74.167.42:9200/_cat/indices?v=true&pretty
-
集群状态说明
green:所有的主分片和副本分片都正常运行。 yellow:所有的主分片都正常运行,但有部分副本分片运行不正常。 red:主分片没能正常运行
SpringBoot3.X整合Elastic Search8.X集群实战
- 配置文件修改
spring.elasticsearch.uris=http://112.74.167.42:9200,http://112.74.50.221:9200,http://120.79.53.241:9200
- 准备数据,创建多个索引列表
PUT /xdclass_shop_v1 { "settings": { "number_of_shards": 3, "number_of_replicas": 2 }, "mappings": { "properties": { "id": { "type": "keyword" }, "title": { "type": "keyword" }, "summary": { "type": "text" }, "price": { "type": "float" } } } } PUT /xdclass_shop_v1/_bulk { "index": { "_index": "xdclass_shop_v1" } } { "id": "1", "title": "Spring Boot","summary":"this is a summary Spring Boot video", "price": 9.99 } { "index": { "_index": "xdclass_shop_v1" } } { "id": "2", "title": "java","summary":"this is a summary java video", "price": 19.99 } { "index": { "_index": "xdclass_shop_v1" } } { "id": "3", "title": "Spring Cloud","summary":"this is a summary Spring Cloud video", "price": 29.99 } { "index": { "_index": "xdclass_shop_v1" } } { "id": "4", "title": "Spring_Boot", "summary":"this is a summary Spring_Boot video","price": 59.99 } { "index": { "_index": "xdclass_shop_v1" } } { "id": "5", "title": "SpringBoot","summary":"this is a summary SpringBoot video", "price": 0.99 }
- 高可用测试
- 停掉某个节点服务器,然后测试相关的数据搜索和索引分布情况
- 停掉某个节点服务器,然后测试相关的数据搜索和索引分布情况
Elastic Search8.X常见性能优化
- 背景
- 官方数据Elastic Search最高的性能可以达到,PB级别数据秒内相应
- 1PB=1024TB = 1024 * 1024GB
- 但是很多同学公司的Elastic Search集群,里面存储了几百万或者几千万数据,但是ES查询就很慢了
- 记住,ES数量常规是亿级别为起点,之所以达不到官方的数据,多数是团队现有技术水平不够和业务场景不一样
- 海量数据检索领域榜单:https://db-engines.com/en/ranking/search+engine
- 官方数据Elastic Search最高的性能可以达到,PB级别数据秒内相应
- Elastic Search8.X常见性能优化最佳实践
-
硬件资源优化:
-
内存分配
- 将足够的堆内存分配给Elasticsearch进程,以减少垃圾回收的频率
- ElasticSearch推荐的最大JVM堆空间是30~32G, 所以分片最大容量推荐限制为30GB
- 30G heap 大概能处理的数据量 10 T,如果内存很大如128G,可在一台机器上运行多个ES节点
- 比如业务的数据能达到200GB, 推荐最多分配7到8个分片
-
存储器选择
-
使用高性能的存储器,如SSD,以提高索引和检索速度
-
SSD的读写速度更快,适合高吞吐量的应用场景。
-
-
CPU和网络资源
- 根据预期的负载需求,配置合适的CPU和网络资源,以确保能够处理高并发和大数据量的请求。
-
-
分片和副本优化:
-
合理设置分片数量
-
过多的分片会增加CPU和内存的开销,因此要根据数据量、节点数量和性能需求来确定分片的数量。
-
一般建议每个节点上不超过20个分片
-
-
考虑副本数量
-
根据可用资源、数据可靠性和负载均衡等因素,设置合适的副本数量
-
至少应设置一个副本,以提高数据的冗余和可用性。
-
不是副本越多,检索性能越高,增加副本数量会消耗额外的存储空间和计算资源,
-
-
-
索引和搜索优化
-
映射和数据类型
-
根据实际需求,选择合适的数据类型和映射设置
-
避免不必要的字段索引,尽可能减少数据在硬盘上的存储空间。
-
-
分词和分析器
-
根据实际需求,选择合适的分词器和分析器,以优化搜索结果。
-
了解不同分析器的性能特点,根据业务需求进行选择
-
-
查询和过滤器
-
使用合适的查询类型和过滤器,以减少不必要的计算和数据传输
-
尽量避免全文搜索和正则表达式等开销较大的查询操作。
-
-
-
缓存和缓冲区优化:
-
缓存大小
-
在Elasticsearch的JVM堆内存中配置合适的缓存大小,以加速热数据的访问
-
可以根据节点的角色和负载需求来调整缓存设置。
-
-
索引排序字段
-
选择合适的索引排序字段,以提高排序操作的性能
-
对于经常需要排序的字段,可以为其创建索引,或者选择合适的字段数据类型。
-
-
-
监控和日志优化
-
监控集群性能
-
使用Elasticsearch提供的监控工具如Elastic Stack的Elasticsearch监控、X-Pack或其他第三方监控工具
-
实时监控集群的健康状态、吞吐量、查询延迟和磁盘使用情况等关键指标。
-
-
-
集群规划和部署:
-
多节点集群
- 使用多个节点组成集群,以提高数据的冗余和可用性。多节点集群还可以分布负载和增加横向扩展的能力。
-
节点类型和角色
-
根据节点的硬件配置和功能需求,将节点设置为合适的类型和角色
-
如数据节点、主节点、协调节点等,以实现负载均衡和高可用性。
-
-
-
性能测试和优化:
-
压力测试
-
使用性能测试工具模拟真实的负载,评估集群的性能极限和瓶颈
-
根据测试结果,优化硬件资源、配置参数和查询操作等。
-
-
日常性能调优
- 通过监控指标和日志分析,定期评估集群的性能表现,及时调整和优化配置,以满足不断变化的需求。
-
-
升级和版本管理:
-
计划升级
-
定期考虑升级Elasticsearch版本,以获取新功能、性能改进和安全修复。
-
在升级过程中,确保备份数据并进行合理的测试。
-
-
版本管理
- 跟踪Elasticsearch的发行说明和文档,了解新版本的特性和已知问题,并根据实际需求选择合适的版本。
-
-