【技术派后端篇】ElasticSearch 实战指南:环境搭建、API 操作与集成实践

1 ES介绍及基本概念

ElasticSearch是一个基于Lucene 的分布式、高扩展、高实时的基于RESTful 风格API的搜索与数据分析引擎。

RESTful 风格API的特点:

  1. 接受HTTP协议的请求,返回HTTP响应;
  2. 请求的参数是JSON,返回响应的内容也是JSON格式;
  3. 请求的类型(GET、POST、PUT、DELETE)就代表对资源的操作类型。

1.1 基本概念

在Elasticsearch(ES)的体系中,各核心概念清晰且独特,支撑着其强大的搜索与数据分析能力:

  • 字段(Field):字段代表一种属性,类似于关系型数据库表中的列。在数据库里,每一行数据由多个属性值构成,比如员工表中,“姓名”“年龄”“职位”这些列就是字段,对应具体员工的数据,如“张三”“30”“工程师”就是字段值。在ES中,一个字段同样承载特定的属性信息,像一篇博客文章,“标题”“发布时间”“内容”等都可作为字段。
  • 文档(Document):ES的数据存储方式与传统关系型数据库截然不同,所有数据均以JSON格式的document形式存在。document作为ES索引与搜索的最小数据单元,类比于数据库中的一行数据。以电商平台为例,一条商品信息记录就是一个document,它由“商品名称”“价格”“库存”“描述”等多个字段值组成,可能像这样:
{"商品名称": "智能手表","价格": 1299,"库存": 50,"描述": "具备多种健康监测功能的智能手表"
}
  • 映射(Mapping):Mapping用于定义document中每个字段的类型、字段所采用的分词器等细节,其作用等同于关系型数据库中的表结构,为数据的存储与处理提供规范。例如,在一个新闻资讯索引中,“标题”字段可定义为字符串类型,并使用标准分词器,以便对标题进行合理切分用于搜索;“发布时间”字段定义为日期类型,方便按时间范围检索新闻。通过这样的映射定义,ES能更高效地管理和利用数据。
  • 索引(Index):Index是Elasticsearch存储数据的载体,可理解为关系型数据库中的数据库概念,用于存放一类相同或相似的document。假设运营一个在线图书馆系统,可能会有“小说类书籍索引”“学术文献索引”等。“小说类书籍索引”中存放的就是所有小说书籍相关的document,每个document包含书籍的名称、作者、出版社、内容简介等信息。
  • 类型(Type):Type属于逻辑层面的数据分类方式,一种Type类似于一张表,像常见的用户表、订单表等。在Elasticsearch 6.X版本中,默认Type为_doc ;而到了ES 7.x版本,Type这一概念已被移除 。在早期的论坛系统ES应用中,可能会设置“用户类型”和“帖子类型”,“用户类型”的document存储用户的账号、密码、注册时间等信息;“帖子类型”的document存放帖子的标题、内容、发布者、发布时间等数据。但在7.x及之后版本,不再使用这种多类型区分方式,而是更强调数据的统一索引管理 。

1.2 ES原理与倒排索引

1.2.1 ES整体原理概述

ES 是一个分布式的搜索与数据分析引擎,基于 Lucene 构建。它将数据存储在分布式的节点上,以实现高可用性、高扩展性和高性能。其核心工作流程围绕索引和搜索两个关键环节。在索引阶段,数据被处理并构建索引结构;搜索阶段则依据构建好的索引快速检索出符合条件的数据。

1.2.2 倒排索引的概念

传统数据库使用的是正向索引,即从文档 ID 到文档内容及单词位置的映射。而倒排索引恰恰相反,是从单词到包含该单词的文档 ID 列表的映射。简单来说,倒排索引就是将文档中的每个单词提取出来,记录每个单词在哪些文档中出现过以及出现的位置等信息。

例如,有以下两篇技术博客文章:
文章 1(ID=1):“Elasticsearch 是强大的搜索工具,适用于大数据场景。”
文章 2(ID=2):“学习技术博客写作,掌握搜索技巧很重要,比如使用 Elasticsearch。”
倒排索引构建过程如下:

单词包含该单词的文档ID列表
Elasticsearch1, 2
1
强大的1
搜索1, 2
工具1
适用于1
大数据1
场景1
学习2
技术博客2
写作2
掌握2
技巧2
很重要2
比如2
使用2

这样在搜索时,根据输入的关键词能快速定位到包含该关键词的文档,大大提高搜索效率。

1.2.3 以技术博客网站文章检索为例

假设一个技术博客网站有大量文章,存储在ES中。当用户在搜索框输入关键词“Elasticsearch”进行检索时,ES的工作流程如下:

  1. 用户输入:用户在博客网站搜索框输入“Elasticsearch”。
  2. 请求发送:网站将搜索请求发送给ES服务器。
  3. 倒排索引查询:ES在倒排索引中查找“Elasticsearch”这个单词,找到对应的文档ID列表,即[1, 2]。
  4. 文档获取:根据文档ID,从存储文档的地方获取对应的两篇文章内容。
  5. 结果返回:将这两篇文章的相关信息(如标题、摘要等)返回给用户展示。

在这里插入图片描述

通过这种基于倒排索引的机制,ES能够快速准确地从海量的技术博客文章中找到用户需要的内容,为用户提供高效的搜索体验 。

2 ES环境搭建

2.1 Windows版安装步骤

2.1.1 ElasticSearch安装

  1. 安装Java环境:下载并安装JDK(Java Development Kit),并配置好Java环境变量。具体可参考相关Java安装教程。
  2. 下载安装包:从ElasticSearch官网下载适合Windows系统的zip安装包。

注意:不要下载最新版本,最好根据IK分词器的版本来下载,不然可能会没有对应的分词器版本

  1. 解压文件:将下载后的zip文件解压到指定目录,例如D:\elasticsearch

  2. 启动服务:进入解压目录下的bin目录,双击elasticsearch.bat文件启动ElasticSearch服务。启动后,在浏览器地址栏输入http://localhost:9200/ ,若能看到ElasticSearch相关信息,说明启动成功。
    在这里插入图片描述

  3. 安装为Windows服务(可选)

    • 设置环境变量:右键点击“此电脑”,选择“属性”,点击“高级系统设置”,在弹出窗口中点击“环境变量”。在系统变量中新建变量,变量名可设为ELASTICSEARCH_HOME ,变量值为ElasticSearch的安装目录(如D:\elasticsearch );然后在Path变量中添加%ELASTICSEARCH_HOME%\bin
    • 安装服务:以管理员身份运行命令提示符,进入ElasticSearch的bin目录,执行elasticsearch-service.bat install命令安装服务。可使用elasticsearch-service.bat start启动服务、elasticsearch-service.bat stop停止服务、elasticsearch-service.bat remove移除服务。
  4. 修改 Elasticsearch 配置为 HTTP(不推荐用于生产环境):如果发现启动ES后无法访问,打开 Elasticsearch 安装目录下的 config 文件夹,找到 elasticsearch.yml 文件,修改配置之后再重启ElasticSearch,即可正常访问。
    在这里插入图片描述

2.1.2 Kibana安装

  1. 下载安装包:从Kibana官网下载与ElasticSearch版本匹配的Windows版.zip安装包。
  2. 解压文件:在D盘新建kibana目录,将下载的.zip文件解压到该目录下,解压后得到kibana-版本号-windows-x86_64文件夹(即$KIBANA_HOME )。
  3. 配置文件:打开$KIBANA_HOME\config\kibana.yml配置文件,设置elasticsearch.url为指向ElasticSearch实例地址,默认http://localhost:9200一般无需修改。如果ElasticSearch服务地址有变化,需相应调整。
  4. 启动服务:进入$KIBANA_HOME\bin目录,双击kibana.bat启动Kibana。启动后可在浏览器输入http://localhost:5601访问Kibana界面。
    在这里插入图片描述

2.1.3 IK分词器安装

  1. 下载:根据ElasticSearch版本,从https://github.com/medcl/elasticsearch-analysis-ik/releases下载对应的IK分词器压缩包。例如,若ElasticSearch是7.10.1版本,则下载ik-710.1.zip
  2. 解压与放置:解压下载的文件,将解压后的文件夹复制到ElasticSearch安装目录下的plugins文件夹内,并将文件夹重命名为analysis-ik 。比如ElasticSearch安装在D:\elasticsearch ,则将文件夹复制到D:\elasticsearch\plugins\analysis-ik
  3. 重启ElasticSearch:以管理员身份运行bin目录下的elasticsearch.bat重启ElasticSearch,即可加载IK分词器。可通过发送请求测试分词效果,如使用Postman等工具。
    在这里插入图片描述

2.2 Ubuntu版(Linux版)安装步骤

2.2.1 ElasticSearch安装

  1. 下载和解压
    • 从ElasticSearch官网(https://www.elastic.co/cn/downloads/elasticsearch )选择合适版本下载,然后上传到Ubuntu服务器。也可在命令行执行wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-版本号-linux-x86_64.tar.gz下载(下载速度可能较慢)。
    • 执行解压缩命令tar -zxvf elasticsearch-版本号-linux-x86_64.tar.gz -C /usr/local
  2. 配置JDK(若有冲突):新版本ElasticSearch压缩包自带JDK,若Ubuntu已安装JDK且版本不符,启动时会报错。可切换到解压目录的bin目录,执行export JAVA_HOME=/usr/local/elasticsearch-版本号/jdk指定使用自带JDK 。
  3. 创建专用用户root用户不能直接启动ElasticSearch,需创建专用用户,如user-es 。使用命令useradd user-es创建用户,passwd user-es设置密码 。
  4. 修改配置文件:进入config文件夹,编辑elasticsearch.yml文件。可修改http.port等参数,如http.port: 19200 。还可根据需求配置集群相关参数等。
  5. 解决内存权限问题:若启动报错max virtual memory areas vm.max_map_count (65530) is too low, increase to at least (262144) ,切换到root用户(sudo su ),编辑/etc/sysctl.conf文件,在文件末尾添加vm.max_map_count=262144 ,保存退出后执行sysctl -p刷新配置 。
  6. 启动服务:切换到专用用户(su user-es ),进入ElasticSearch的bin目录,执行./elasticsearch启动服务。启动成功后可通过http://服务器IP:端口号(如http://127.0.0.1:19200 )访问,出现相关信息则安装成功。
    在这里插入图片描述
    在这里插入图片描述

2.2.2 Kibana安装

  1. 下载和解压:从Kibana官网(https://www.elastic.co/cn/downloads/kibana )下载与ElasticSearch版本匹配的安装包,例如kibana-版本号-linux-x86_64.tar.gz 。使用命令wget https://artifacts.elastic.co/downloads/kibana/kibana-版本号-linux-x86_64.tar.gz下载后,执行tar -zxvf kibana-版本号-linux-x86_64.tar.gz解压 。
  2. 修改配置文件:进入解压后的目录,编辑config/kibana.yml文件,配置内容如下:
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.url: "http://服务器IP:9200"
kibana.index: ".kibana"

服务器IP替换为实际ElasticSearch服务器的IP地址。
3. 启动服务:切换到解压目录的bin目录,执行./kibana &&表示在后台运行)启动Kibana。启动过程中若ElasticSearch未启动会有警告,连接成功后可通过浏览器访问http://服务器IP:5601

2.2.3 IK分词器安装

  1. 下载:根据ElasticSearch版本,从https://github.com/medcl/elasticsearch-analysis-ik/releases下载对应的IK分词器压缩包。
  2. 解压与放置:解压下载的文件,将解压后的文件夹(需命名为analysis-ik )复制到ElasticSearch安装目录下的plugins文件夹内。比如ElasticSearch安装在/usr/local/elasticsearch-版本号 ,则将文件夹复制到/usr/local/elasticsearch-版本号/plugins/analysis-ik
  3. 重启ElasticSearch:切换到启动ElasticSearch的专用用户,进入ElasticSearch的bin目录,执行./elasticsearch重启服务,即可加载IK分词器。

3 RESTful API操作ES

3.1 操作索引

  • 添加索引
PUT user

向Elasticsearch集群添加名为user的索引。若索引已存在,会返回相应错误提示。

  • 查询单个索引
GET /teacher

获取名为teacher的索引的相关信息,如索引的基本设置、映射等。若索引不存在,会返回404错误。

  • 查询多个索引
GET /user,student

同时获取userstudent两个索引的相关信息。可一次性查看多个索引的状态,方便对比和管理。

  • 查询所有索引
GET /_all

返回Elasticsearch集群中的所有索引的相关信息。在管理多个索引,需要快速了解整体索引情况时使用。

  • 删除索引
DELETE /student

从Elasticsearch集群中删除名为student的索引及其包含的所有文档数据。删除操作不可逆,谨慎使用。

  • 打开索引
POST /student/_open

将处于关闭状态的student索引打开,使其可进行数据的读写和查询操作。索引关闭时,对其进行的任何数据操作都会失败。

  • 关闭索引
POST /student/_close

关闭student索引,关闭后索引不可读写,但索引数据仍存储在磁盘上。可用于在维护索引或减少资源占用时临时关闭索引。

3.2 数据类型

3.2.1 简单数据类型

我们先来看一个简单的映射定义:

PUT teacher/_mapping
{"properties": {"id": {"type": "integer"  },"name": {"type": "text"},"isMale": {"type": "boolean"}}
}

在定义映射的时候,类比于定义数据库中的表结构,我们需要指明每一个字段的名称,数据类型等等信息,所以我们先得了解映射中包含的数据类型。

  • 字符串

    • text:会分词,不支持聚合
    • keyword:不会分词,将全部内容作为一个词条,支持聚合
  • 数值:long, integer, short, byte, double, float, half_float, scaled_float

  • 布尔:boolean

  • 二进制:binary

  • 范围类型:integer_range,float_range, long_range, double_range, date_range

  • 日期:date

3.2.2 复杂数据类型

  • 数组:[ ] 没有专门的数组类型,ES会自动处理数组类型数据

比如说 给某一个字段 定义为 integer类型,那么这个字段是可以存储 integer数组的,ES会自动处理

  • 对象:{ } Object: object(for single JSON objects 单个JSON对象)

3.3 操作映射

  • 给已存在索引添加映射
PUT /user/_mapping
{"properties":{"id": {"type":"integer"},"name":{"type":"keyword"},"age":{"type":"long"}}
}

为已存在的user索引添加字段映射,定义id为整数类型、name为关键词类型、age为长整型。添加映射时,字段类型一旦确定,后续修改会受限制。

  • 创建索引并指定映射
PUT teacher
{"mappings": {"properties": {"tid":{"type": "integer"},"tname":{"type": "text"}}}
}

创建名为teacher的索引,并同时指定其映射,定义tid为整数类型、tname为文本类型。在创建索引时规划好映射,能确保数据存储和查询的准确性。

  • 查询映射
GET /teacher/_mapping

获取teacher索引的映射信息,包括字段类型、分词器设置等。方便查看索引的结构定义,排查查询问题。

  • 修改映射(只能添加字段)
PUT /teacher/_mapping
{"properties":{"height":{"type":"float"},"weight":{"type":"double"}}
}

teacher索引的映射中添加heightweight字段,分别为浮点型和双精度型。Elasticsearch不支持直接修改已存在字段的类型,只能添加新字段。

3.4 操作文档

  • 添加文档 - 指定文档id
POST /user/_doc/1
{"id": 1001,"name":"贾宝玉","age":15
}

user索引中添加一个文档,并指定文档的id为1。若指定id的文档已存在,会覆盖原有文档。

  • 添加文档 - 不指定文档id
POST /user/_doc
{"id":1002,"name":"贾迎春","age":13
}

user索引添加文档,Elasticsearch会自动生成一个唯一的文档id。适用于对文档id无特定要求的场景。

  • 查询文档 - 根据文档id查询
GET /user/_doc/1
GET /user/_doc/NsORPo0BJehhapNsslSw

根据文档id获取user索引中的文档。若文档不存在,会返回404错误。

  • 查询文档 - 查询所有文档
GET /user/_search

获取user索引中的所有文档。在数据量较大时,可能需要结合分页参数使用,避免一次性返回过多数据。

  • 修改文档 - 直接覆盖
POST /user/_doc/1
{"id": 2001,"name":"刘姥姥","age":80
}

用新的文档数据覆盖user索引中id为1的文档。会完全替换原有文档内容,包括所有字段。

  • 修改指定字段
POST /user/_update/1
{"doc": {"name":"贾琏","age": 30}
}

仅修改user索引中id为1的文档的nameage字段,其他字段保持不变。比直接覆盖更灵活,可减少数据传输量。

  • 删除文档(指定文档id)
DELETE /user/_doc/1

删除user索引中id为1的文档。删除操作不可逆,操作前需确认数据是否不再需要。

3.5 IK分词器测试

  • ik_max_word分词模式
GET /_analyze
{"text": "湖南是全国唯一一个叫湖南的省份","analyzer": "ik_max_word"
}

使用ik_max_word分词器对文本进行分词,它会尽可能细粒度地切分文本,如上述文本会被切分成“湖南”“是”“全国”“唯一”“一个”“叫”“湖南”“的”“省份”等多个词条。

  • ik_smart分词模式
GET /_analyze
{"text": "湖南是全国唯一一个叫湖南的省份","analyzer": "ik_smart"
}

ik_smart分词器的粒度更粗,会对文本进行更合理的合并切分,上述文本可能被切分成“湖南”“是”“全国”“唯一一个”“叫”“湖南的省份”等词条。

  • 使用ES自带的分词器
GET /_analyze
{"text": "stone is best man, ciggar is handsome man","analyzer": "standard"
}

使用ES自带的standard分词器对英文文本进行分词,它会按空格和标点符号进行切分,并将单词转换为小写形式,如上述文本会被切分成“stone”“is”“best”“man”“ciggar”“is”“handsome”“man”等词条。

3.6 ES批量操作

  • 创建索引并设置映射
DELETE /teacher
PUT /teacher
{"mappings": {"properties": {"id":{"type": "integer"},"name":{"type": "text","analyzer": "ik_max_word"},"age":{"type": "integer"}}}
}

先删除可能存在的teacher索引,再创建新的teacher索引,并设置其映射。其中name字段使用ik_max_word分词器进行分词。

  • 查询索引中的所有文档
GET /teacher/_search

获取teacher索引中的所有文档,用于查看当前索引中的数据内容。

  • 批量操作
POST /_bulk
{"create":{"_index":"teacher","_id":"1"}}
{"id":1,"name":"金角大王","age":30}
{"create":{"_index":"teacher","_id":"2"}}
{"id":2,"name":"银角大王","age":20}
{"create":{"_index":"teacher","_id":"3"}}
{"id":3,"name":"小钻风","age":10}
{"delete":{"_index":"teacher","_id":"1"}}
{"update":{"_index":"teacher","_id":"2"}}
{"doc":{"name":"狮驼岭","age":1000}}

在一次请求中对teacher索引执行多个操作,包括创建文档(create)、删除文档(delete)和更新文档(update)。批量操作可减少网络请求次数,提高数据处理效率。

  • 创建另一个索引并设置映射
PUT /member
{"mappings": {"properties": {"id":{"type": "integer"},"name":{"type": "keyword"},"addr":{"type": "text","analyzer": "ik_max_word"},"gender":{"type": "keyword"},"money":{"type": "integer"}}}
}

创建名为member的索引,并设置其映射。addr字段使用ik_max_word分词器,方便对地址进行分词查询。

  • 查询索引信息
GET /member/_search
GET /member/_mapping

分别查询member索引中的所有文档和获取member索引的映射信息,用于了解索引的数据和结构。

3.7 ES高级查询

  • match_all查询
GET /member/_search
{"query": {"match_all": {}},"from": 0,"size": 3
}

查询member索引中的所有文档,并指定从第0条开始,返回3条数据。常用于获取索引的部分数据样本,或在不关心具体查询条件时获取全部数据。

  • term查询
GET /member/_search
{"query": {"term": {"addr": {"value": "山区"}}}
}

member索引中查询addr字段值为“山区”的文档。term查询不会对搜索关键字进行分词,直接与目标字段进行精确匹配。

  • 全文查询 - match
GET /member/_search
{"query": {"match": {"addr": "湖北武汉"}}
}

member索引的addr字段进行全文查询,会对搜索关键字“湖北武汉”进行分词,然后与addr字段的分词结果进行匹配。默认取并集,即只要匹配到其中一个分词结果的文档就会被返回。

  • 模糊查询 - 通配符查询
GET /member/_search
{"query": {"wildcard": {"addr": {"value": "武?"}}}
}

member索引中查询addr字段值以“武”开头且后面跟任意一个字符的文档。?表示占位,*表示通配任意多个字符。

  • 正则查询
GET /member/_search
{"query": {"regexp": {"addr": "[A-Z a-z 0-9_]+(.)*"}}
}

使用正则表达式对member索引的addr字段进行查询,匹配由字母、数字、下划线组成且后面可跟任意字符的地址。

  • 前缀查询
GET /member/_search
{"query": {"prefix": {"addr": {"value": "青"}}}
}

member索引中查询addr字段值以“青”开头的文档。前缀查询不太适用于text类型字段,因为text类型字段会被分词,可能导致查询结果不准确。

  • queryString多条件查询
GET /member/_search
{"query": {"query_string": {"fields": ["addr","gender"], "query": "武汉 AND 男"}}
}

member索引中查询addr字段包含“武汉”且gender字段为“男”的文档。注意ANDOR要大写,且不要使用simple_query_string,它不会识别ANDOR关键字。

  • 排序查询
GET /member/_search
{"query": {"match_all": {}},"sort": [{"money": {"order": "asc"}}]
}

查询member索引中的所有文档,并按money字段的值进行升序排序。可根据需求指定其他字段进行排序,以及选择升序(asc)或降序(desc)。

  • 范围查询
GET /member/_search
{"query": {"range": {"money": {"gte": 300,"lte": 600}}},"sort": [{"money": {"order": "desc"}}],"from": 0,"size": 3
}

member索引中查询money字段值在300到600之间的文档,并按money字段的降序排序,返回前3条数据。

3.8 bool查询

  • must条件
GET /member/_search
{"query": {"bool": {"must": [{"term": {"addr": {"value": "武汉"}}},{"term": {"gender": {"value": "女"}}}]}}
}

查询member索引中addr字段为“武汉”且gender字段为“女”的文档,会计算文档的近似度得分。must条件下的所有子条件都必须满足才能匹配到文档。

  • filter条件
GET /member/_search
{"query": {"bool": {"filter": [{"match": {"addr": "湖北武汉"}},{"range": {"money": {"gte": 200,"lte": 500}}}]}}
}

查询member索引中addr字段包含“湖北武汉”且money字段值在200到500之间的文档,filter不会计算近似度得分,查询效率更高,适用于不需要计算得分的精确过滤场景。

  • must_not条件
GET /member/_search
{"query": {"bool": {"must_not": [{"match": {"addr": "武汉"}},{"term": {"gender": {"value": "女"}}}]}}
}

查询member索引中addr字段不包含“武汉”且gender字段不为“女”的文档,同样不会计算近似度得分。

  • should条件
GET /member/_search
{"query": {"bool": {"should": [{"term": {"addr": {"value": "武汉"}}},{"term": {"gender": {"value": "女"}}}]}}
}

查询member索引中addr字段为“武汉”或者gender字段为“女”的文档,会计算近似度得分。只要满足should中的一个子条件,文档就可能被返回。

  • 综合练习
GET /member/_search
{"query": {"bool": {"filter": [{"range": {"money": {"gte": 200,"lte": 600}}},{"term": {"gender": "男"}}],"must": [{"match": {"addr": "湖北武汉"}}]}}
}

查询member索引中money字段值在200到600之间、gender为“男”且addr包含“湖北武汉”的文档。

4 技术派整合ES

4.1 构造 RestHighLevelClient 客户端

  • 引入依赖:在 paicoding-service 模块的 pom 文件中,我们需要引入 es 和 es-client 相关的依赖。具体的依赖配置如下:
<!--引入es-high-level-client相关依赖  start-->
<dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>6.8.2</version>
</dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>6.8.2</version>
</dependency>
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>6.8.2</version>
</dependency>
  • 配置 yml 文件:在 paicoding-web 模块的 src->main->resource-env->dev->application-dal.yml 中,配置 ES 的相关信息。具体配置如下:
# elasticsearch配置
elasticsearch:# 是否开启ES?本地启动如果没有安装ES,可以设置为false关闭ESopen: false# es集群名称clusterName: elasticsearchhosts: 127.0.0.1:9200userName: elasticpassword: elastic# es 请求方式scheme: http# es 连接超时时间connectTimeOut: 1000# es socket 连接超时时间socketTimeOut: 30000# es 请求超时时间connectionRequestTimeOut: 500# es 最大连接数maxConnectNum: 100# es 每个路由的最大连接数maxConnectNumPerRoute: 100

在配置 yml 文件时,一定要注意格式的正确性,避免因格式错误导致配置失效。

  • 编写 config 配置类 RestHighLevelClient:配置类的作用是将 RestHighLevelClient 客户端的创建交由 Spring 管理。具体的配置类代码如下:
/*** es配置类** @author ygl* @since 2023-05-25**/
@Slf4j
@Data
@Configuration
// 下面这个表示只有 elasticsearch.open = true 时,采进行es的配置初始化;当不使用es时,则不会实例 RestHighLevelClient
@ConditionalOnProperty(prefix = "elasticsearch", name = "open")
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticsearchConfig {// 是否开启ESprivate Boolean open;// es host ip 地址(集群)private String hosts;// es用户名private String userName;// es密码private String password;// es 请求方式private String scheme;// es集群名称private String clusterName;// es 连接超时时间private int connectTimeOut;// es socket 连接超时时间private int socketTimeOut;// es 请求超时时间private int connectionRequestTimeOut;// es 最大连接数private int maxConnectNum;// es 每个路由的最大连接数private int maxConnectNumPerRoute;/*** 如果@Bean没有指定bean的名称,那么这个bean的名称就是方法名*/@Bean(name = "restHighLevelClient")public RestHighLevelClient restHighLevelClient() {// 此处为单节点esString host = hosts.split(":")[0];String port = hosts.split(":")[1];HttpHost httpHost = new HttpHost(host, Integer.parseInt(port));// 构建连接对象RestClientBuilder builder = RestClient.builder(httpHost);// 设置用户名、密码CredentialsProvider credentialsProvider = new BasicCredentialsProvider();credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password));// 连接延时配置builder.setRequestConfigCallback(requestConfigBuilder -> {requestConfigBuilder.setConnectTimeout(connectTimeOut);requestConfigBuilder.setSocketTimeout(socketTimeOut);requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut);return requestConfigBuilder;});// 连接数配置builder.setHttpClientConfigCallback(httpClientBuilder -> {httpClientBuilder.setMaxConnTotal(maxConnectNum);httpClientBuilder.setMaxConnPerRoute(maxConnectNumPerRoute);httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);return httpClientBuilder;});return new RestHighLevelClient(builder);}
}

需要注意的是,在 yml 中的 elasticsearch.hosts 配置中,不要添加 https 前缀,只需填写 127.0.0.1:9200 即可,否则在配置类中创建 HttpHost 时会出错。

4.2 技术派首页全局查询走 ES 数据库

在进行 ES 查询整合之前,我们先来了解一下大致的逻辑:

  1. 根据查询条件在 ES 中查询数据。
  2. 从查询结果中提取出 id,并将这些 id 添加到 ids 集合中。
  3. 使用 ids 集合去 MySQL 数据库中查询相应的数据。

通过这种方式,可以大大提高查询的效率,相比直接在 MySQL 中进行 like% 值 % 的查询,性能有显著提升。

在 paicoding-service 模块的 ArticleReadServiceImpl 类中,我们需要注入 RestHighLevelClient 客户端,然后编写实现代码。具体代码如下:

public List<SimpleArticleDTO> querySimpleArticleBySearchKey(String key) {// TODO 当KEY为空时,返回热门推荐if (StringUtils.isBlank(key)) {return Collections.emptyList();}key = key.trim();SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(key,ESFieldConstant.ES_FIELD_TITLE,ESFieldConstant.ES_FIELD_SHORT_TITLE);searchSourceBuilder.query(multiMatchQueryBuilder);SearchRequest searchRequest = new SearchRequest(new String[]{ESIndexConstant.ES_INDEX_ARTICLE}, searchSourceBuilder);SearchResponse searchResponse = null;try {searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);} catch (IOException e) {e.printStackTrace();}SearchHits hits = searchResponse.getHits();SearchHit[] hitList = hits.getHits();List<Integer> ids = new ArrayList<>();for (SearchHit documentFields : hitList) {ids.add(Integer.parseInt(documentFields.getId()));}if (ObjectUtils.isEmpty(ids)) {return null;}List<ArticleDO> records = articleDAO.selectByIds(ids);return records.stream().map(s -> new SimpleArticleDTO().setId(s.getId()).setTitle(s.getTitle())).collect(Collectors.toList());
}

4.3 兼容未安装 ES 继续走 MySQL 查询

考虑到有些小伙伴可能没有安装 ES 和 Canal,为了保证代码在这种情况下也能正常运行,我们进行了兼容性处理,使得在未安装 ES 时,首页查询依然可以走 MySQL 数据库。
首先,在 yml 中增加了是否开启 ES 的配置项:

# elasticsearch配置
elasticsearch:# 是否开启ES?本地启动如果没有安装ES,可以设置为false关闭ESopen: true# es集群名称clusterName: elasticsearchhosts: 127.0.0.1:9200userName: elasticpassword: elastic# es 请求方式scheme: http# es 连接超时时间connectTimeOut: 1000# es socket 连接超时时间socketTimeOut: 30000# es 请求超时时间connectionRequestTimeOut: 500# es 最大连接数maxConnectNum: 100# es 每个路由的最大连接数maxConnectNumPerRoute: 100

然后,在 Service 层将 open 值注入:

@Value("${elasticsearch.open}")
private Boolean openEs;

最后,在业务层的代码中实现兼容逻辑:

@Override
public List<SimpleArticleDTO> querySimpleArticleBySearchKey(String key) {// TODO 当KEY为空时,返回热门推荐if (StringUtils.isBlank(key)) {return Collections.emptyList();}// 如果没有开启ES,那么继续从MYSQL中获取数据if (!openEs) {List<ArticleDO> records = articleDAO.listSimpleArticlesBySearchKey(key);return records.stream().map(s -> new SimpleArticleDTO().setId(s.getId()).setTitle(s.getTitle())).collect(Collectors.toList());}// ES整合逻辑key = key.trim();SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(key,ESFieldConstant.ES_FIELD_TITLE,ESFieldConstant.ES_FIELD_SHORT_TITLE);searchSourceBuilder.query(multiMatchQueryBuilder);SearchRequest searchRequest = new SearchRequest(new String[]{ESIndexConstant.ES_INDEX_ARTICLE}, searchSourceBuilder);SearchResponse searchResponse = null;try {searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);} catch (IOException e) {e.printStackTrace();}SearchHits hits = searchResponse.getHits();SearchHit[] hitList = hits.getHits();List<Integer> ids = new ArrayList<>();for (SearchHit documentFields : hitList) {ids.add(Integer.parseInt(documentFields.getId()));}if (ObjectUtils.isEmpty(ids)) {return null;}List<ArticleDO> records = articleDAO.selectByIds(ids);return records.stream().map(s -> new SimpleArticleDTO().setId(s.getId()).setTitle(s.getTitle())).collect(Collectors.toList());
}

5 ES集群相关知识

5.1 ES集群基础概念

  1. 定义与组成:Elasticsearch(ES)集群是由多个ES节点组成的集合 ,节点间协同工作,实现数据存储、搜索及分析功能。
  2. 优势
    • 效率提升:多节点并行处理搜索请求,相比单节点搜索效率更高。
    • 存储扩容:突破单节点磁盘空间限制,利用多个节点存储资源,扩大数据存储容量。
    • 高可用性:部分节点故障时,集群仍能对外提供服务,保障整体可用性。
      在这里插入图片描述

5.2 ES集群节点

  1. 节点类型
    • 主节点(Master Node):负责管理集群元数据,如索引创建、删除,分片分配,监控节点状态等。为防止脑裂,一般设置奇数个主节点。脑裂是指在集群中,多个节点都认为自己是主节点,导致集群出现多个“大脑”,从而使集群状态混乱、数据不一致等问题。设置奇数个主节点,是因为在选举主节点时,奇数个节点能避免出现平局情况,降低脑裂风险 。
    • 数据节点(Data Node):用于存储数据,执行数据的增、删、改、查及聚合操作,需根据数据量和查询需求合理配置资源。
    • 协调节点(Coordinate Node):不承担主节点和数据节点功能,专门负责接收请求、转发请求至其他节点、汇总返回数据。大规模集群并发查询量大时,可添加独立协调节点。
    • Ingest节点:对文档数据进行预处理,如通过管道实现数据转换与丰富,可按需水平扩展。一个节点可兼具多种角色,小规模集群可不严格区分。
  2. 节点协作:数据节点向主节点发送心跳数据包汇报状态,主节点依此监控集群状态。

5.3 ES集群分片

  1. 主分片(Primary Shard)
    • 定义:将索引文档数据分散存储的单元,所有主分片数据合起来构成完整索引数据,主分片数量至少为1 。
    • 作用:承载索引的原始数据存储,是数据写入和读取的基础单元。
  2. 副本分片(Replica Shard)
    • 定义:主分片的备份,数量大于等于0 。
    • 作用:提高数据可用性和查询性能,主分片故障时可顶替提供服务,还可分担查询负载。
  3. 分片规则
    • 主分片和副本分片不能存储在同一节点上。
    • 单节点ES可有多主分片,但无副本分片。
    • 创建索引时可指定主、副本分片数量,索引创建后,主分片数量不可更改,仅副本分片数量可调整。
      在这里插入图片描述

5.4 文档在ES集群中的操作

  1. 存储流程

    • 用户将存储请求发送到集群中任意一个节点。
    • 接收请求的节点通过文档路由,把数据发送给对应的主分片。
    • 主分片将数据同步给它的所有副本分片。
      在这里插入图片描述
  2. 搜索流程

    • 用户向集群中任意一个节点发起搜索请求。
    • 接收请求的节点(协调节点)把每个主分片和它的副本分片看作“同一组”分片,从中选择一组有完整数据的分片(默认轮训选择),然后分发请求。
    • 被选中的分片进行查询,之后返回结果。
    • 协调节点把收到的结果聚合,返回给用户。
      在这里插入图片描述

5.5 ES 集群相关问题及解决

  • 脑裂问题:因网络问题,集群被分成两个,出现两个 “大脑”(主节点) ,导致数据不一致 。解决方法包括设置
    • 最小主节点数量,计算公式为discovery.zen.minimum_master_nodes: (有master资格节点数/2) + 1
    • 设置专门奇数个主节点
    • 采用单播发现机制(关闭多播发现机制discovery.zen.ping.multicast.enabled: false ,配置单播发现主节点 ip 地址discovery.zen.ping.unicast.hosts : ("master1", "master2", "master3") )
    • 配置选举发现数,延长 ping master 等待时长(如discovery.zen.ping_timeout: 30 ,discovery.zen.minimum_master_nodes: 2 ) 。
  • 分片数量配置:索引分片数指定后一般不可更改,除非重做索引 。ElasticSearch 推荐最大 JVM 堆空间 30 - 32G ,可据此估算分片数量,如预计数据量 200GB ,最多分配 7 - 8 个分片 。初始阶段,可按节点数量的 1.5 - 3 倍创建分片,如 3 个节点,分片数最多不超 9 个 。对于基于日期、搜索少、数据量小(如每个索引 1GB 甚至更小 )的索引需求,如日志管理,建议分配 1 个分片 。
    在这里插入图片描述

6 总结

本文全面讲解 ElasticSearch(ES)相关知识。ES 是基于 Lucene 的分布式搜索与分析引擎,有分布式、高扩展、高实时特性,采用 RESTful 风格 API 。介绍了字段、文档等基本概念,基于倒排索引的原理。详述 Windows 和 Ubuntu 版搭建步骤,RESTful API 操作及 ES 集成。还提及 ES 集群中的脑裂问题,主节点在管理集群元数据中起关键作用,为防止脑裂,通常设置奇数个主节点,避免选举时出现平局,降低集群状态混乱、数据不一致等风险。

7 参考链接

  1. 技术派实现ES查询
  2. 项目仓库(GitHub)
  3. 项目仓库(码云)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79246.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从标准九九表打印解读单行表达式的书写修炼(Python)

解读单行表达式书写&#xff0c;了解修习单行捷径。 笔记模板由python脚本于2025-04-16 23:24:17创建&#xff0c;本篇笔记适合喜欢单行喜好python的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅仅是知识的简单复述…

深入解析布尔注入:原理、实战与防御

目录 一、布尔注入的原理与核心逻辑 二、布尔注入的实战步骤 三、关键函数与绕过技巧 四、实战案例&#xff1a;获取数据库名称 五、防御策略与最佳实践 六、总结 一、布尔注入的原理与核心逻辑 布尔注入&#xff08;Boolean-Based Blind SQL Injection&#xff09;是一种…

OpenGL学习笔记(几何着色器、实例化、抗锯齿)

目录 几何着色器爆破物体法向量可视化 实例化&#xff08;偏移量存在uniform中&#xff09;实例化数组&#xff08;偏移量存在顶点属性中&#xff09;小行星带 抗锯齿SSAA&#xff08;Super Sample Anti-aliasing&#xff09;MSAA&#xff08;Multi-Sampling Anti-aliasing&…

idea报错java: 非法字符: ‘\ufeff‘解决方案

解决方案步骤以及说明 BOM是什么&#xff1f;1. BOM的作用2. 为什么会出现 \ufeff 错误&#xff1f;3. 如何解决 \ufeff 问题&#xff1f; 最后重新编译&#xff0c;即可运行&#xff01;&#xff01;&#xff01; BOM是什么&#xff1f; \ufeff 是 Unicode 中的 BOM&#xff0…

open webui 介绍 是一个可扩展、功能丰富且用户友好的本地部署 AI 平台,支持完全离线运行。

AI MCP 系列 AgentGPT-01-入门介绍 Browser-use 是连接你的AI代理与浏览器的最简单方式 AI MCP(大模型上下文)-01-入门介绍 AI MCP(大模型上下文)-02-awesome-mcp-servers 精选的 MCP 服务器 AI MCP(大模型上下文)-03-open webui 介绍 是一个可扩展、功能丰富且用户友好的…

Log4j2远程命令执行(CVE-2021-44228)复现

这里选择使用vulfocue的靶场来进行复现 描述: Apache Log4j2 是一个基于 Java 的日志记录工具。该工具重写了 Log4j 框架&#xff0c;并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发&#xff0c;用来记录日志信息。 在大多数情况下&#xff0c;开发者可能会将用…

模型提示词

一 提示词 &#xff08;一&#xff09; 提示词&#xff08;Prompt&#xff09;是用户发送给大语言模型的问题、指令或请求&#xff0c;** 1 来明确地告诉模型用户想要解决的问题或完成的任务&#xff0c;是大语言模型理解用户需求并据此生成相关、准确回答或内容的基础。对于…

深度学习算法:从基础到实践

简介 深度学习作为人工智能领域的一个重要分支&#xff0c;近年来在多个领域取得了显著的成就。本文将从基础概念出发&#xff0c;探讨深度学习算法的核心原理&#xff0c;并介绍一些实际应用案例。 深度学习算法的核心概念 深度学习算法基于人工神经网络&#xff0c;通过构…

5.9 《GPT-4调试+测试金字塔:构建高可靠系统的5大实战策略》

5.4 测试与调试:构建企业级质量的保障体系 关键词:测试金字塔模型、GPT-4调试助手、LangChain调试模式、异步任务验证 测试策略设计(测试金字塔实践) #mermaid-svg-RblGbJVMnCIShiCW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill…

Visio绘图工具全面科普:解锁专业图表绘制新境界[特殊字符]

Visio绘图工具全面科普&#xff1a;解锁专业图表绘制新境界&#x1f31f; 在信息爆炸的时代&#xff0c;清晰、直观地呈现复杂信息变得至关重要。无论是绘制流程图&#x1f4ca;、组织结构图&#x1f465;&#xff0c;还是规划网络拓扑&#x1f5a7;&#xff0c;一款强大的绘图…

ShellScript脚本编程

语法基础 脚本结构 我们先从这个小demo程序来窥探一下我们shell脚本的程序结构 #!/bin/bash# 注释信息echo_str"hello world"test(){echo $echo_str }test echo_str 首先我们可以通过文本编辑器(在这里我们使用linux自带文本编辑神器vim)&#xff0c;新建一个文件…

你了解哪些Java限流算法?

大家好&#xff0c;我是锋哥。今天分享关于【你了解哪些Java限流算法?】面试题。希望对大家有帮助&#xff1b; 你了解哪些Java限流算法? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Java 中&#xff0c;限流算法广泛用于控制流量、避免过载和保护系统的稳…

prime-2 靶场笔记(vuInhub靶场)

前言&#xff1a; 在本次靶场环境中涉及的知识点&#xff0c;主要包含LFI和SMB以及Lxd组提权&#xff0c;具体内容包括主机探测、端口扫描、目录扫描、wpscan扫描、反弹shell、一句话木马、容器、linux各种提权和维持。 环境介绍&#xff1a; 本靶场使用了kali&#xff08;192…

SparseDrive---论文阅读

纯视觉下的稀疏场景表示 算法动机&开创性思路 算法动机&#xff1a; 依赖于计算成本高昂的鸟瞰图&#xff08;BEV&#xff09;特征表示。预测和规划的设计过于直接&#xff0c;没有充分利用周围代理和自我车辆之间的高阶和双向交互。场景信息是在agent周围提取&#xff…

旅游特种兵迪士尼大作战:DeepSeek高精准路径优化

DeepSeek大模型高性能核心技术与多模态融合开发 - 商品搜索 - 京东 随着假期的脚步日渐临近&#xff0c;环球影城等备受瞩目的主题游乐场&#xff0c;已然成为大人与孩子们心中不可或缺的节日狂欢圣地。然而&#xff0c;随之而来的庞大客流&#xff0c;却总让无数游客在欢乐的…

android rtsp 拉流h264 h265,解码nv12转码nv21耗时卡顿问题及ffmpeg优化

一、 背景介绍及问题概述 项目需求需要在rk3568开发板上面&#xff0c;通过rtsp协议拉流的形式获取摄像头预览&#xff0c;然后进行人脸识别 姿态识别等后续其它操作。由于rtsp协议一般使用h.264 h265视频编码格式&#xff08;也叫 AVC 和 HEVC&#xff09;是不能直接用于后续处…

运维面试题(十四)

6.将日志从一台服务器保存到另一台服务器中的方法 1.使用 rsync 同步日志文件 2.使用 scp 手动或脚本化传输 3.配置日志服务&#xff08;如 syslog 或 rsyslog &#xff09;远程传输  4.编写脚本定时上传&#xff1a;结合 cron 定时任务和传输工具&#xff0c;编…

永磁同步电机控制中,滑模观测器是基于反电动势观测转子速度和角度的?扩展卡尔曼滤波观测器是基于什么观测的?扩展卡尔曼滤波观测器也是基于反电动势吗?

滑模观测器在PMSM中的应用&#xff1a; 滑模观测器是一种非线性观测器&#xff0c;利用切换函数设计&#xff0c;使得状态估计误差迅速趋近于零&#xff0c;实现快速响应和对外部干扰的鲁棒性。 在永磁同步电机&#xff08;PMSM&#xff09;无传感器控制中&#xff0c;滑模观测…

【前端】Vue一本通 ESLint JSX

近几天更新完毕&#xff0c;不定期持续更新&#xff0c;建议关注收藏点赞。 目录 工具推荐vscode插件vue-devtoolsESLint JSX语法扩展简介设计模式快速入门 vue/cli脚手架使用vue指令 工具推荐 工欲善其事&#xff0c;必先利其器。 vscode插件 Vetur&#xff1a;vue代码高亮…

【adb】bat批处理+adb 自动亮屏,自动解锁屏幕,启动王者荣耀

准备adb 下载 需要确认是否安装了adb.exe文件,可以在: 任务管理器 -->详细信息–>找一下后台运行的adb 安装过anroid模拟器,也存在adb,例如:雷电安装目录 D:\leidian\LDPlayer9 单独下载adb 官方下载地址:[官方网址] 下载目录文件: 测试adb USB连接手机 首先在设置界…