ElasticSearch快速入门--实现分词搜索

分词题目搜索

使用Elasticsearch实现题目数据的存储和分词搜索,需要将数据库的数据同步到 Elasticsearch。

ElasticSearch入门

ElasticSearch(简称ES)是一个开源的分布式搜索和数据分析引擎,用Java开发并且是当前最流行的开源的企业级搜索引擎,能够达到近实时搜索,它专门设计用于处理大规模的文本数据和实现高性能的全文检索。

搜索引擎的排名

参考网站:https://db-engines.com/en/ranking/search+engine

生态介绍
  • ElasticSearch

核心全文搜索与分析引擎。利用分布式架构提供近乎实时的数据搜索、分析和可视化能力。负责存储、索引和搜索数据。

  • Logstash

服务器端数据处理管道 ,能够同时从多个源采集数据转换数据 ,并过滤、增强和传输到Elasticsearch。支持丰富的输入、过滤和输出插件。

  • Beats

轻量级的数据采集工具 ,每个Beat都是一个独立的守护进程,负责从系统或应用程序中收集数据,发送数据到LogstashElasticsearch

包括Filebeat: 收集日志文件。Metricbeat: 收集系统和服务的指标。Packetbeat: 监控网络流量。

  • Kibana

可视化和管理界面 ,为Elasticsearch数据提供可视化功能。用户可以轻松创建仪表板、图表和地图,直观展示和查询Elasticsearch中的数据

应用场景

只要用到搜索的场景,Elasticsearch几乎都可以是最好的选择。结合Kibana、Logstash、Beats,ElaticSearch可以用于全文检索、日志分析、商业智能场景。

全文检索

首先,Elasticsearch支持各类应用、网站等的全文搜索,包括淘宝、京东等电商平台的搜索

其次,它支持用户通过自定义打分、自定义排序、高亮等机制召回期望的结果数据,通过跨机房/跨机架感知、异地容灾等策略,为用户提供高可用、高并发、低延时、用户体验好的搜索服务。

许多知名企业,如阿里巴巴、腾讯、携程、滴滴出行、美团、字节跳动、贝壳找房等,都将Elasticsearch作为关键技术之一

日志分析

许多知名企业,如58集团、唯品会、日志易、国投瑞银等,都使用Elasticsearch来快速分析和处理大量的日志数据,从而对业务运行状况进行实时的监控和故障排查。

商业智能场景

大型业务数据给电子商务、移动App开发、广告媒体等领域的企业的数据收集和数据分析带来了巨大的挑战。而Elasticsearch具有结构化查询功能,能实现全文数据检索和聚合分析

核心概念
常用术语

对比MySQL来理解Elasticsearch,我们可以更直观地看出Elasticsearch与传统数据库之间的关系及差异。

索引
  • 索引是Elasticsearch中用于存储和管理相关数据的逻辑容器。相当于数据库中的一个表 ,它包含了多条具有相似结构的文档
  • 索引的名称可以由用户自定义,但必须全部小写。
json 复制代码
//创建索引并设置别名
PUT /my_index
{
  "aliases": {
    "alias_name": {}  // 创建一个别名 alias_name,指向 my_index
  }
}
//创建索引的同时设置 settings 和 mappings
PUT /my_index
{
  "settings": {
    ...
  },
  "mappings": {
   ...
  }	
}
文档

索引中的每条记录,类似于数据库中的行。以JSON格式的文档存储在索引内。每个索引具有唯一的名称,以便在执行搜索、更新和删除操作时进行引用。键是字段的名称,值是不同数据类型的字段。不同的数据类型包含但不限于字符串类型、数字类型、布尔类型、对象类型等。

json 复制代码
{
  "_index": "employee",
  "_id": "2",
  "_version": 1,
  "_seq_no": 1,
  "_primary_term": 1,
  "found": true,     //示查询时是否找到了对应的文档
  "_source": {      //文档原始json数据类型
    "name": "李四",
    "sex": 1,
    "age": 28,
    "address": "广州荔湾大厦",
    "remark": "java assistant"
  }
}
映射

类似关系型数据库中的Schema表结构。帮助控制字段的存储、索引和查询行为。用于定义索引中文档字段的数据类型及其处理方式

映射的定义如下所示:

json 复制代码
PUT /employee
{
  "mappings": {
    "properties": {
      "name": {
        "type": "keyword"
      },
      "sex": {
        "type": "integer"
      },
      "age": {
        "type": "integer"
      },
      "address": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "remark": {
        "type": "text",
        "analyzer": "ik_smart"
      }
    }
  }
}

扩展

集群:多个节点组成的群集,用于存储数据并提供搜索功能。。集群中的每个节点都可以处理数据。

分片(Shard): 为了实现横向扩展,ES 将索引拆分成多个分片,每个分片可以分布在不同节点上。

副本(Replica):分片的复制品,用于提高可用性和容错性。

全文检索

全文检索(Full-Text Search)是一种从大量文本数据中快速检索出包含指定词汇或短语的技术。允许用户输入一个或多个关键词,然后系统会在预先建立好的索引中查找包含这些关键词的文档或文档片段,并返回给用户。

设想一个关于全文检索的场景,比如搜索Java设计模式:

思考:用传统关系型数据库实现有什么问题?

如果是用MySQL存储文章 ,我们应该会使用这样的 SQL 去查询

mysql 复制代码
select * from t_blog where content like "%Java设计模式%"
#这种需要遍历所有的记录进行匹配,不但效率低,而且搜索结果不符合我们搜索时的期望。
实现原理

1)分词 : Elasticsearch的分词器会将输入文本拆解成独立的词条(tokens)方便进行索引和搜索。分词的具体过程包括以下几步:

  • 字符过滤: 去除特殊字符、HTML 标签或进行其他文本清理。
  • 分词: 根据指定的分词器(analyzer),将文本按规则拆分成一个个词条。例如,英文可以按空格拆分,中文使用专门的分词器处理。
  • 词汇过滤: 对分词结果进行过滤,如去掉常见但无意义的词,如"the"、"s"等)或进行词形归并( 如将动词变为原形 )。

Elasticsearch 内置了很多分词器,比如按照空格分词等,默认只支持英文,可以在官方文档了解。

2)对处理后的文本数据建立倒排索引,将单词映射到包含该单词的文档列表中,以便快速定位相关文档。

倒排索引

倒排索引的建立过程是先对文档进行分词处理 ,然后记录每个单词在哪些文档中出现,以及出现的位置信息。可以根据关键词或短语快速找到包含这些词语的文档, 比如创建文章的时候,中文分词后生成的倒排索引如下两列:

关键词 文章ID 是否命中索引
Java 1,2
设计模式 1,2,3,4
多线程 2
JavaScript 4

倒排索引的实现涉及到多个步骤

1)文档预处理:对文档进行分词处理,移除停用词,并进行词干提取等操作。

2)构建词典:将处理后的词汇添加到词典中,并为每个词汇分配一个唯一的ID。

3)创建倒排列表:对于词典中的每个词汇,创建一个倒排列表,记录该词汇在哪些文档中出现,以及出现的位置信息。

4)存储索引文件:将词典和倒排列表存储在磁盘上的索引文件中,通常会进行压缩处理以减小存储空间并提升查询效率。

5)查询处理:当用户发起搜索请求时,搜索引擎会从词典中查找每个关键词对应的倒排列表,快速定位到包含这些关键词的文档。

打分规则

实际应用Elasticsearch来实现搜索功能时,我们不仅要求能搜到内容,而且还要把和用户搜索最相关的内容展示在前面。这就需要Elasticsearch的打分规则

打分规则 (_Score) 是衡量每个文档与查询条件的匹配度的评分机制。搜索结果的默认排序方式是按相关性得分(_score)从高到低排

Elasticsearch 使用 BM25 算法 来计算每个文档的得分,它是基于词频、反向文档频率、文档长度等因素来评估。

打分的主要因素:

  1. 词频: 查询词在文档中出现的次数,出现次数越多,得分越高

  2. 反向文档频率 : 查询词在所有文档中出现的频率。词在越少的文档中出现,IDF值越高,得分越高。

  3. 文档长度: 较短的文档往往被认为更相关,因为查询词在短文档中占的比例更大。

下面举一个例子: 假设要在 Elasticsearch 中查询 AI 这个关键词,索引中有以下三个文档:

什么是反向文档频率?

举个例子:假如说ES中有 10 个文档,都包含了"AI"这个关键词,只有1个文档包含了"大模型"这个关键词。现在用户搜索"AI大模型",大概率会把后面这条文档搜出来,因为更稀有。

当然,以上只是简单举例,实际上ES 计算打分规则时,会有一套较为复杂的公式

查询语法

Elasticsearch支持多种查询语法,用于不同的场景和需求,主要包括査询 DSL、EQL、SQL 等。

  1. DSL查询是一种基于 JSON 的查询语言,和 http 请求最兼容,也是 Elasticsearch 中最常用的查询方式

https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl.html 忘了就查,不用背

json 复制代码
//增加文档
POST /my_index/_doc/1      //向索引 my_index 中插入id为1的文档
{
  "title": "Elasticsearch入门",
  "content": "学习如何使用Elasticsearch进行全文搜索",
  "tags": ["elasticsearch", "search"],	
  "userId": 1001,
  "createTime": "2025-03-23 10:00:00"
}
//查询所有文档	
GET /my_index/_search
{
  "query": {
    "match_all": {}   // 匹配所有文档
  }
}
//根据条件查询
GET /my_index/_search
{
  "query": {
    "match": {
      "title": "Elasticsearch" // 在title字段中搜索包含"Elasticsearch"的文档
    }
  }
}
//更新文档 (Update)
POST /my_index/_update/1    //更新id为1的文档
{
  "doc": {
    "tags": ["elasticsearch", "search", "update"], // 更新tags字段
    "editTime": "2025-03-23 19:00:00" // 添加或更新editTime字段
  }
}
//删除文档 (Delete)
DELETE /my_index/_doc/1

//根据条件删除文档
POST /my_index/_delete_by_query
{
  "query": {
    "match": {
      "title": "Elasticsearch"   // 删除title字段包含"Elasticsearch"的所有文档
    }
  }
}
//聚合查询 (Aggregation)
GET /my_index/_search    //统计文档中不同标签的数量
{
  "size": 0,     // 不返回具体文档,只返回聚合结果
  "aggs": {
    "tag_count": {
      "terms": {
        "field": "tags"   // 对tags字段进行分组统计
      }
    }
  }
}
//批量插入、更新和删除文档
POST /_bulk
{ "index": { "_index": "my_index", "_id": "2" } }
{ "title": "批量操作示例", "content": "演示Elasticsearch的批量API功能。", "tags": ["bulk", "api"] }
{ "update": { "_index": "my_index", "_id": "1" } }
{ "doc": { "editTime": "2025-03-23 20:00:00" } }
{ "delete": { "_index": "my_index", "_id": "3" } }
  1. EQL查询是一种用于检索时间序列 事件 的查询语言,常用于日志和安全监控场景。示例:查找特定事件
shell 复制代码
#查找 process.name 为"malware.exe"的所有进程事件,常用于安全检测中的恶意软件分析
process where process.name == "malware.exe"
  1. SQL查询:Elasticsearch 提供了类似传统数据库的 SQL 语法,对熟悉 SQL的用户来说非常方便。
mysql 复制代码
# 返回 users 索引中 age大于 30 的所有用户,并按年龄降序排序。
SELECT name, age FROM users WHERE age > 30 ORDER BY age DESC
查询条件

以 ES 的 DSL 语法为例,我整理了一些常用的查询条件

查询条件 介绍 示例 用途
match 全文检索,对查询字符串进行分词并匹配字段内容。适用于文本字段。 {"match": {"content": "空说是帅小伙"}} 全文检索,如搜索文章、评论等。
term 精确匹配,不进行分词,适用于非文本字段(如数字、日期) {"term": {"status": "active"}} 精确查找,如状态、ID、分类等。
terms 多值精确匹配,支持多个值的精确匹配。 {"terms": {"category": ["科技", "编程"]}} 快速筛选多个固定值,如分类、标签等。
range 范围查询,支持数值、日期等字段的范围匹配。 {"range": {"age": {"gte": 18, "lte": 30}}} 查询数值范围,如年龄、时间范围等。
bool 组合多个查询条件,支持 must(必须满足)、should(至少满足一个)、must_not(排除)。 ```json { "bool": { "must": {"match": {"title": "Java"}}, "must_not": {"term": {"status": "deleted"}} } }` 组合查询,如同时满足多个条件或排除部分结果。
wildcard 通配符查询,支持 *(匹配任意字符)和 ?(匹配单个字符)。 {"wildcard": {"name": "li*s"}} 模糊匹配,如模糊搜索用户名或编号。
exists 检查字段是否存在。 {"exists": {"field": "email"}} 过滤存在特定字段的文档,如非空校验。
match_phrase 短语匹配,保持查询词的顺序和连续性。 {"match_phrase": {"content": "Elasticsearch 教程"}} 匹配精确短语,如搜索特定语句或固定组合词。
multi_match 在多个字段进行全文检索。 ```json { "multi_match": { "query": "Java", "fields": ["title", "content"] } }` 跨字段搜索,如同时在标题和内容中搜索关键词。
fuzzy 模糊匹配允许拼写错误,如错别字 {"fuzzy": {"name": "Cahterine"}} 拼写纠错,如搜索用户可能输入的拼写错误。
ids 基于文档ID查询 { "ids":{ "values":["1","2","3"]} 适用于根据文档 ID 查找特定文档。
Elasticsearch 客户端
  1. HTTP API: Elasticsearch 提供了 RESTful HTTP API,用户可以通过直接发送 HTTP 请求来执行索引、搜索和管理集群的操作。官方文档

  2. Kibana: 是 Elasticsearch 官方提供的可视化工具,用户可以通过 Kibana 控制台使用查询语法(如 DSL)来执行搜索、分析和数据可视化。

  3. Java REST Client: 官方提供的 Java 客户端库,用于Java 程序与 Elasticsearch 进行通信,支持索引、查询、集群等操作。官方文档

  4. Spring Data Elasticsearch: Spring 全家桶的一员,与 Elasticsearch集成,官方文档

  5. Elasticsearch SOL CLI: 命令行工具,允许通过类 SQL语法直接在命令行中査询 Elasticsearch 数据,适用于熟悉 SQL的用户。

此外,Elasticsearch 当然不只有 Java 的客户端,Python、Node.js、Go 的客户端都是支持的。在选择客户端时,要注意版本号保持兼容。

ES数据同步方案

一般对于查询搜索功能,使用 ES 来模糊搜索,但是数据是存放在数据库 MySQL 里的,所以需要把 MySQL 中的数据和 ES 进行同步,保证数据一致(以 MySQL 为主)。

数据流向: MySQL=>ES(单向) 数据同步一般有 2 个过程: 全量同步(首次) + 增量同步(新数据)

总共有 4 种主流方案

  1. 定时任务

比如1分钟1次,找到 MySQL 中过去几分钟内( 至少是定时周期的2倍 )发生改变的数据,然后更新到 ES

这种方式简单易懂,开发维护相对容易。占用资源少,缺点就是有时间差,无法做到实时同步,对大数据量的更新处理不够高效。

  1. 双写

写数据到数据库时,必须也去写 ES,更新删除数据库同理。可以通过事务保证数据一致性 ,先保证 MySQL 写成功,因为如果ES 写入失败了,不会触发回滚,但是可以通过定时任务 +日志+告警进行检测和修复(补偿)。

优点就是业务逻辑直接控制数据同步。利用事务部分保证 MySQL 和 ES 的数据一致性,理论上可以接近实时更新 ES。

缺点就是影响性能 ,每次写 MySQL时,需要同时操作 ES,增加了业务写入延迟,此外还有一致性问题

  • 如果 ES 写入失败,MySQL 事务提交成功后,ES 可能会丢失数据,
  • 如果ES 写入成功,MySQL 事务提交失败,ES 无法回滚。因此必须额外设计监控、补偿机制来检测同步失败的情况,代码复杂度增加
  1. Logstash数据同步管道

一般要配合kafka消息队列 +beats采集器,从数据库同步到ES

这种方式基于配置文件,数据同步逻辑和业务代码解耦。且引入Kafka等消息队列实现异步数据同步,并可处理高吞吐量数据。

缺点就是灵活性差,复杂的业务逻辑可能难以在配置中实现,无法处理细粒度的定制化需求。且引入额外组件,维护成本高

  1. 监听 MysQL Binlog

有任何数据变更时都能够实时监听到,并且同步到 Elasticsearch。一般不需要自己监听,可以使用现成的技术,比如Canal

Canal的核心原理: 数据库每次修改时,会修改binlog文件,只要监听该文件的修改,就能第一时间得到消息并处理

优点就是真正的实时同步,MySQL数据变更的第一时间同步到 ES,且Binlog是数据库自带的日志功能,只需要新增监听逻辑。

缺点就是需要引入引入Canal这样的中间件,增加了系统的复杂性和维护成本。且如果 Canal 服务出现问题,数据可能会滞后或丢失,必须设计补偿机制。

综上对于一般项目,由于数据量不大,题目更新也不频繁,容忍丢失和不一致,所以选用方案一,实现成本最低

快速安装

官网地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.14/zip-windows.html (windows安装)

Elasticsearch 更新迭代非常快,所以安装时,一定要注意慎重选择版本号!

Window安装

下载地址: https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.14.3-windows-x86_64.zip

  1. ElasticSearch目录结构如下:
目录 描述
bin 脚本文件,包括启动elasticsearch,安装插件,运行统计数据等
config 配置文件目录,如elasticsearch配置、角色配置、jvm配置等。
jdk 7.x 以后特有,自带的 java 环境
data 默认的数据存放目录,包含节点、分片、索引、文档的所有数据,生产环境需要修改。
lib elasticsearch依赖的Java类库
logs 默认的日志文件存储路径,生产环境需要修改。
modules 包含所有的Elasticsearch模块,如Cluster、Discovery、Indices等。
plugins 已安装插件目录

2. 配置JDK环境

  • ES比较耗内存,建议虚拟机4G或以上内存,jvm1g以上的内存分配

  • 运行Elasticsearch,需安装并配置JDK。各个版本对Java的依赖 https://www.elastic.co/support/matrix#matrix_jvm

    • 7.0开始,内置了Java环境。ES的JDK环境变量生效的优先级配置顺序ES_JAVA_HOME>ES_HOME
    • ES_JAVA_HOME:用于指定Elasticsearch使用的Java运行时环境的路径。启动Elasticsearch时,会检查ES_JAVA_HOME环境变量并使用
    • ES_HOME:这个环境变量指定Elasticsearch的安装路径。它用于定位Elasticsearch的配置文件、插件和其他相关资源。
    • 可以参考ES的环境文件elasticsearch-env.bat

windows下,设置ES_JAVA_HOME和ES_HOME的环境变量

3. 配置ElasticSearch

编辑config/elasticsearch.yml文件

关闭security安全认证

ES 8 默认是开启Security的,初学者便于快速上手,可以关闭Security。

4. 启动ElasticSearch服务

解决启动日志乱码问题

复制代码
#打开config/jvm.options 文件--->末尾添加
-Dfile.encoding=GBK

进入bin目录,点击elasticsearch.bat件启动 ES 服务

注意:9300 端口为 Elasticsearch集群间组件的通信端口,9200 端口为浏览器访问的 http

打开浏览器(推荐使用谷歌浏览器),输入地址:http://localhost:9200,测试结果

Linux安装

准备linux安装环境: centos7

shell 复制代码
# 注意:ES不允许使用root账号启动服务,如果你当前账号是root,则需要创建一个专有账户
# 为elaticsearch创建用户
adduser fox
passwd fox

通过fox用户登录,下载ElasticSearch并解压

shell 复制代码
# centos7  通过fox用户进入
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.14.3-linux-x86_64.tar.gz
tar -xzf elasticsearch-8.14.3-linux-x86_64.tar.gz
cd elasticsearch-8.14.3/ 

# 将ES安装包的所有者和组更改为fox用户
chown -R fox:fox elasticsearch-8.14.3

配置JDK环境(可选)

shell 复制代码
# 进入fox用户主目录,比如/home/fox目录下,设置用户级别的环境变量
vim .bash_profile
#设置ES_JAVA_HOME和ES_HOME的路径
export ES_JAVA_HOME=/home/fox/elasticsearch-8.14.3/jdk/
export ES_HOME=/home/fox/elasticsearch-8.14.3
#执行以下命令使配置生效
source .bash_profile

修改config/elasticsearch.yml配置文件

shell 复制代码
vim elasticsearch.yml

#配置节点对外提供服务的地址以及集群内通信的ip地址,默认为回环地址127.0.0.1 和[::1]
#配置为0.0.0.0开启远程访问支持  
network.host: 0.0.0.0
#指定节点为单节点,可以绕过引导检查   初学者建议设置为此开发模式 
discovery.type: single-node

#初学者建议关闭security安全认证
xpack.security.enabled: false

配置JVM参数(可选

修改config/jvm.options配置文件,调整jvm堆内存大小

SHELL 复制代码
vim jvm.options -Xms4g -Xmx4g

配置的建议:

6)启动ElasticSearch服务

shell 复制代码
#注意:es默认不能用root用户启动
#fox用户下启动ES
bin/elasticsearch 

# -d 后台启动
bin/elasticsearch -d

打开本地浏览器(推荐使用谷歌浏览器),输入地址:http://192.168.65.47:9200 (换成linux环境对应的ip),测试结果如下:

开发模式和生产模式
  • 开发模式:开发模式是默认配置(未配置集群发现设置),如果用户只是出于学习目的,而引导检查会把很多用户挡在门外,所以ES提供了一个设置项discovery.type=single-node。此项配置为指定节点为单节点,可以绕过引导检查。
  • 生产模式:当用户修改了有关集群的相关配置会触发生产模式,在生产模式下,服务启动会触发ES的引导检查或者叫启动检查(bootstrap checks)
    • 引导检查就是在服务启动之前对一些重要的配置项进行检查
    • 引导检查包括对JVM大小、内存锁、虚拟内存、最大线程数、集群发现相关配置等相关的检查,如果某一项或者几项的配置不合理,ES会拒绝启动服务,并且在开发模式下的某些警告信息会升级成错误信息输出。
    • 这种设定虽然增加了用户的使用门槛,但是避免了日后产生更大的问题。
常用配置参数

参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/8.14/important-settings.html

  • cluster.name

当前节点所属集群名称,多个节点如果要组成同一个集群,那么集群名称一定要配置成相同。默认值elasticsearch,生产环境建议根据ES集群的使用目的修改成合适的名字。

  • node.name

当前节点名称,默认值当前节点部署所在机器的主机名,所以如果一台机器上要起多个ES节点的话,需要通过配置该属性明确指定不同的节点名称。

  • path.data

配置数据存储目录,比如索引数据等,默认值 $ES_HOME/data,生产环境下强烈建议部署到另外的安全目录,防止ES升级导致数据被误删除。

  • path.logs

配置日志存储目录,比如运行日志和集群健康信息等,默认值 $ES_HOME/logs,生产环境下强烈建议部署到另外的安全目录,防止ES升级导致数据被误删除。

  • bootstrap.memory_lock

配置ES启动时是否进行内存锁定检查,默认值true。

ES对于内存的需求比较大,一般生产环境建议配置大内存,如果内存不足,容易导致内存交换到磁盘,严重影响ES的性能。所以默认启动时进行相应大小内存的锁定,如果无法锁定则会启动失败。

如果该参数配置为true的话很可能导致无法锁定内存以致ES无法成功启动,此时可以修改为false。

  • network.host

节点对外提供服务的地址以及集群内通信的ip地址,默认值为当前节点所在机器的本机回环地址127.0.0.1 和[::1],这就导致默认情况下只能通过当前节点所在主机访问当前节点。

  • http.port

配置当前ES节点对外提供服务的http端口,默认 9200

  • transport.port

节点通信端口号,默认 9300

  • discovery.seed_hosts

配置参与集群节点发现过程的主机列表,说白一点就是集群中所有节点所在的主机列表,可以是具体的IP地址,也可以是可解析的域名。

  • cluster.initial_master_nodes

配置ES集群初始化时参与master选举的节点名称列表,必须与node.name配置的一致。ES集群首次构建完成后,应该将集群中所有节点的配置文件中的cluster.initial_master_nodes配置项移除,重启集群或者将新节点加入某个已存在的集群时切记不要设置该配置项。

可视化Kibana安装

Kibana是一个开源分析和可视化平台,旨在与Elasticsearch协同工作。

参考文档:https://www.elastic.co/guide/en/kibana/8.14/get-started.html

下载地址:https://www.elastic.co/cn/downloads/past-releases#kibana

  1. 下载并解压缩Kibana
shell 复制代码
#windows
https://artifacts.elastic.co/downloads/kibana/kibana-8.14.3-windows-x86_64.zip

#linux
wget https://artifacts.elastic.co/downloads/kibana/kibana-8.14.3-linux-x86_64.tar.gz
tar -zxvf kibana-8.14.3-linux-x86_64.tar.gz
cd kibana-8.14.3
  1. 修改Kibana.yml配置文件
shell 复制代码
vim config/kibana.yml

#指定Kibana服务器监听的端口号
server.port: 5601 
#指定Kibana服务器绑定的主机地址  
server.host: "0.0.0.0"  
#指定Kibana连接到的Elasticsearch实例的访问地址
elasticsearch.hosts: ["http://localhost:9200"]  
#将 Kibana 的界面语言设置为简体中文
i18n.locale: "zh-CN"   
  1. 运行Kibana

windows:直接执行kibana.bat

Linux:注意:kibana也需要非root用户启动

shell 复制代码
#启动kibana服务
bin/kibana
#后台启动,并将日志写入到logs/kibana.log
nohup bin/kibana > logs/kibana.log 2>&1 &

#查询kibana进程
netstat -tunlp | grep 5601
  1. 访问Kibana: http://localhost:5601
cat API
shell 复制代码
/_cat/allocation         #查看单节点的shard分配整体情况
/_cat/shards          #查看各shard的详细情况
/_cat/shards/{index}     #查看指定分片的详细情况
/_cat/master          #查看master节点信息
/_cat/nodes           #查看所有节点信息
/_cat/indices         #查看集群中所有index的详细信息
/_cat/indices/{index}      #查看集群中指定index的详细信息
/_cat/segments        #查看各index的segment详细信息,包括segment名, 所属shard, 内存(磁盘)占用大小, 是否刷盘
/_cat/segments/{index}#查看指定index的segment详细信息
/_cat/count           #查看当前集群的doc数量
/_cat/count/{index}   #查看指定索引的doc数量
/_cat/recovery        #查看集群内每个shard的recovery过程.调整replica。
/_cat/recovery/{index}#查看指定索引shard的recovery过程
/_cat/health          #查看集群当前状态:红、黄、绿
/_cat/pending_tasks   #查看当前集群的pending task
/_cat/aliases         #查看集群中所有alias信息,路由配置等
/_cat/aliases/{alias} #查看指定索引的alias信息
/_cat/thread_pool     #查看集群各节点内部不同类型的threadpool的统计信息,
/_cat/plugins         #查看集群各个节点上的plugin信息
/_cat/fielddata       #查看当前集群各个节点的fielddata内存使用情况
/_cat/fielddata/{fields}     #查看指定field的内存使用情况,里面传field属性对应的值
/_cat/nodeattrs              #查看单节点的自定义属性
/_cat/repositories           #输出集群中注册快照存储库
/_cat/templates              #输出当前正在存在的模板信息
安装中文分词插件
在线安装

以安装analysis-icu这个分词插件为例

analysis-icu功能:

  • 基于ICU(International Components for Unicode)库,提供高级的文本分析和处理功能。
  • 支持多语言和复杂的Unicode文本处理。
  • 包含ICU分词器(ICU Tokenizer)和ICU标准化过滤器(ICU Normalizer)。

analysis-icu应用场景:

  • 多语言文本分析,适用于处理各种语言的文本。
  • 支持Unicode标准化和处理复杂字符。
  • 提供高级的文本处理功能,如正则表达式替换、文本转换等。
shell 复制代码
#查看已安装插件
bin/elasticsearch-plugin list
#安装插件
bin/elasticsearch-plugin install analysis-icu
#删除插件
bin/elasticsearch-plugin remove analysis-icu
# 注意:安装和删除完插件后,需要重启ES服务才能生效。
测试分词效果
shell 复制代码
POST _analyze
{
    "analyzer":"icu_analyzer",
    "text":"中华人民共和国"
}
离线安装

本地下载相应的插件,解压,然后手动上传到elasticsearch的plugins目录,然后重启ES实例就可以了。

比如ik中文分词插件:https://github.com/medcl/elasticsearch-analysis-ik

注意:ik分词器插件和ES版本必须一一对应,否则会出现兼容性问题导致ES启动失败。

当前ik分词器插件最新版本还只支持到ES8.4.1,而我们使用的ES版本是8.14.3,安装后会出现兼容性问题。那如何解决?

可以从https://release.infinilabs.com/analysis-ik/stable/ 下载ES8.14.3对应版本的分词器

测试分词效果

shell 复制代码
#ES的默认分词设置是standard,会单字拆分
POST _analyze
{
    "analyzer":"standard",
    "text":"中华人民共和国"
}

#ik_smart:会做最粗粒度的拆
POST _analyze
{
    "analyzer": "ik_smart",
    "text": "中华人民共和国"
 }

#ik_max_word:会将文本做最细粒度的拆分
POST _analyze
{
    "analyzer":"ik_max_word",
    "text":"中华人民共和国"
}

创建索引时可以指定IK分词器作为默认分词器

json 复制代码
# 创建索引,指定默认分词器
PUT /employee
{
    "settings" : {
        "index" : {
            "analysis.analyzer.default.type": "ik_max_word"  //这里指定了ik_max_word类型索引
        }
    }
}

# 查看索引setting信息
GET /employee/_settings

也可以针对字段配置IK分词器

json 复制代码
//创建索引
PUT /index
// 指定映射
POST /index/_mapping
{
  "properties": { //这是一个包含字段定义的JSON对象。在这个例子中,它只包含了一个字段content
    "content": {  //索引中要定义的字段名
   
        //指定content字段的数据类型为text。在Elasticsearch中,text类型用于全文搜索的文本字段,可以被分词器(analyzer)处理成多个词条(tokens)用于索引和搜索。
      "type": "text", 
       
  //指定在索引(写入)content字段时使用的分词器为ik_max_word。ik_max_word是IK分词器插件提供的一个分词器,它会对文本进行最细粒度的切分
      "analyzer": "ik_max_word",

//指定在搜索(查询)content字段时使用的分词器为ik_smart。ik_smart是IK分词器的另一种分词模式,它尝试对文本进行更智能的切分,以提高搜索的准确率 
      "search_analyzer": "ik_smart"
    }
  }
}

//索引文档,也就是插入文档,分别向索引 index 中添加了四个文档
POST /index/_create/1
{"content":"美国留给伊拉克的是个烂摊子吗"}
POST /index/_create/2
{"content":"公安部:各地校车将享最高路权"}
POST /index/_create/3
{"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}
POST /index/_create/4
{"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"}

//带高亮的查询,用于搜索所有 content 字段中包含"中国"这个词的所有文档
POST /index/_search
{
  "query": {
    "match": {
      "content": "中国"
    }
  },
  "highlight": {
    "pre_tags": [
      "<tag1>",
      "<tag2>"
    ],
    "post_tags": [
      "</tag1>",
      "</tag2>"
    ],
    "fields": {
      "content": {}
    }
  }
}

后端开发

ES搭建

目标:安装 Elasticsearch 和 Kibana,能够在 Kibana 査看到 Elasticsearch 存储的数据。

由于项目用的Spring Boot 2.x版本,对应的 Spring Data Elasticsearch 客户端版本是 4.x,支持的 Elasticsearch是 7.x,建议7.17的版本很稳定

1.安装 Elasticsearch

安装完成后进入 es 目录cmd并执行启动命令

shell 复制代码
.\bin\elasticsearch.bat

#用 CURL 测试是否启动成功
curl -X GET "localhost:9200/?pretty"
2.安装 Kibana

注意,只要是同一套技术,所有版本必须一致!此处都用 7.17 版本!

安装完成后进入 kibana 目录并执行启动命令,访问 http://localhost:5601/,即可开始使用。

cmd 复制代码
.\bin\kibana.bat

但 kibana 默认是英文,不变阅读,可以修改 config/kibana.yml 中的国际化配置,注意,目前 Kibana 面板没有增加权限校验,所有人都能访问,所以请勿在线上直接部署!

测试

利用 Kibana 的开发工具来操作 Elasticsearch 的数据,比如查询:

验证下分词器的效果,比如使用标准分词器,效果如图,英文被识别为了一个词,但中文未被识别成一个词,而是分开的

json 复制代码
POST /_analyze
{
  "analyzer": "standard", 
  "text": "空说帅 giegie,haha"
}
3.安装IK 中文分词器(ES 插件)

开源地址:https://github.com/medcl/elasticsearch-analysis-ik

直接按照官方指引安装即可,注意下载和我们 Elasticsearch 一致的版本,可以在这里找到各版本的插件包:https://release.infinilabs.com/analysis-ik/stable/

在 ES 安装目录下执行

shell 复制代码
.\bin\elasticsearch-plugin.bat install https://release.infinilabs.com/analysis-ik/stable/elasticsearch-analysis-ik-7.17.23.zip


#重启ES即可
.\bin\elasticsearch.bat

IK分词器插件为我们提供了两个分词器: ik_smartik_max_word

  • 前者是智能分词,尽量选择最像一个词的拆分方式,比如"好学生"会被识别为一个词。
  • 后者尽可能地分词,可以包括组合词,比如"好学生"会被识别为3个词: 好学生、好学、学生

测试

json 复制代码
POST /_analyze
{
  "analyzer": "ik_smart", 
  "text": "人工智能正在崛起"
}

有时候分词不准,这个时候可以利用官方提供的插件支持自定义词典。可以按照官方文档配置。

索引设计
设计索引

为了将MySQL题目表 数据导入到ES中并实现分词搜索,需要为索引定义mapping映射,用于定义字段的类型、分词器及其索引方式。

相当于数据库,建表时我们要考虑索引,同样ES建立索引时,要考虑到字段选取、分词器、字段格式等问题。

基于我们数据库的表结构和需求,我们可以定义title、content、answer等字段使用分词搜索,同时为其他字段指定适当的类型。映射如下

json 复制代码
{
  "mappings": {
    "properties": {
      // 标题字段,使用ik_max_word分词器进行索引分析,ik_smart分词器进行搜索分析
      "title": {
        "type": "text",      // 数据类型为文本
        "analyzer": "ik_max_word",       // 索引时使用的分词器,ik_max_word会对文本进行细粒度分词
        "search_analyzer": "ik_smart",   // 搜索时使用的分词器,ik_smart会对文本进行粗粒度分词
        "fields": {
          //子字段作用:允许同一个字段根据不同的目的以不同的方式被索引和搜索  
          "keyword": {           // 定义一个子字段,用于精确匹配,比如过滤、排序或聚合操作,希望整个字段值作为一个整体来处理,而不是被分词
            "type": "keyword",   // 其数据类型为关键字,不会被分词
            "ignore_above": 256   // 忽略超过256个字符的值,因为标题一般不会很长,很少精确匹配
          }
        }
      },
      // 内容字段,使用ik_max_word分词器进行索引分析,ik_smart分词器进行搜索分析
      "content": {
        "type": "text",                 // 数据类型为文本
        "analyzer": "ik_max_word",     // 索引时使用的分词器,细粒度分词
        "search_analyzer": "ik_smart"   // 搜索时使用的分词器,粗粒度分词
      },
      // 标签字段,数据类型为关键字,适合精确匹配
      "tags": {
        "type": "keyword"   // 数据类型为关键字,不会被分词
      },
      // 答案字段,使用ik_max_word分词器进行索引分析,ik_smart分词器进行搜索分析
      "answer": {
        "type": "text",              // 数据类型为文本
        "analyzer": "ik_max_word",       // 细粒度分词
        "search_analyzer": "ik_smart"   // 粗粒度分词
      },
      // 用户ID字段,数据类型为长整型
      "userId": {
        "type": "long" // 数据类型为长整型
      },
      // 编辑时间字段,数据类型为日期,格式为yyyy-MM-dd HH:mm:ss
      "editTime": {
        "type": "date", // 数据类型为日期
        "format": "yyyy-MM-dd HH:mm:ss" // 日期格式
      },
      // 创建时间字段,数据类型为日期,格式为yyyy-MM-dd HH:mm:ss
      "createTime": {
        "type": "date", // 数据类型为日期
        "format": "yyyy-MM-dd HH:mm:ss" // 日期格式
      },
      // 更新时间字段,数据类型为日期,格式为yyyy-MM-dd HH:mm:ss
      "updateTime": {
        "type": "date", // 数据类型为日期
        "format": "yyyy-MM-dd HH:mm:ss" // 日期格式
      },
      // 是否删除字段,数据类型为关键字,适合精确匹配
      "isDelete": {
        "type": "keyword" // 数据类型为关键字,不会被分词
      }
    }
  }
}

为什么不显示指定id 字段?

ES中,每个文档都有一个唯一的_id字段来标识文档,不需要显式定义 id 字段,因为ES会自动生成 id,在插入数据时,你可以手动指定id

由于id 是内部的系统字段,默认作为主键使用,因此在mappings中通常不需要显式定义。

如果你想让某个字段( 如 userid )作为id ,可以在插入文档时指定该字段的值作为 id 。比如:

json 复制代码
PUT /index/_doc/<custom_id>
{
  "userId": 1001,
  "title": "Example"
}
新建索引

可以通过如下命令创建索引,在 Kibana开发者工具中执行、或者用 CURL 调用 Elasticsearch 执行均可

下面的注释可以用AI消除掉,然后到可视化平台执行

json 复制代码
PUT /question_v1     //创建 
{
  // 定义索引的别名(alias)
  "aliases": {
    "question": {}  // 创建一个名为 "question" 的别名,指向当前索引 "question_v1"
  },
   "mappings": {   
    "properties": {
      // 标题字段,使用ik_max_word分词器进行索引分析,ik_smart分词器进行搜索分析
      "title": {
        "type": "text",      // 数据类型为文本
        "analyzer": "ik_max_word",       // 索引时使用的分词器,ik_max_word会对文本进行细粒度分词
        "search_analyzer": "ik_smart",   // 搜索时使用的分词器,ik_smart会对文本进行粗粒度分词
        "fields": {
          //子字段作用:允许同一个字段根据不同的目的以不同的方式被索引和搜索  
          "keyword": {           // 定义一个子字段,用于精确匹配,比如过滤、排序或聚合操作,希望整个字段值作为一个整体来处理,而不是被分词
            "type": "keyword",   // 其数据类型为关键字,不会被分词
            "ignore_above": 256   // 忽略超过256个字符的值,因为标题一般不会很长,很少精确匹配
          }
        }
      },
      // 内容字段,使用ik_max_word分词器进行索引分析,ik_smart分词器进行搜索分析
      "content": {
        "type": "text",                 // 数据类型为文本
        "analyzer": "ik_max_word",     // 索引时使用的分词器,细粒度分词
        "search_analyzer": "ik_smart"   // 搜索时使用的分词器,粗粒度分词
      },
      // 标签字段,数据类型为关键字,适合精确匹配
      "tags": {
        "type": "keyword"   // 数据类型为关键字,不会被分词
      },
      // 答案字段,使用ik_max_word分词器进行索引分析,ik_smart分词器进行搜索分析
      "answer": {
        "type": "text",              // 数据类型为文本
        "analyzer": "ik_max_word",       // 细粒度分词
        "search_analyzer": "ik_smart"   // 粗粒度分词
      },
      // 用户ID字段,数据类型为长整型
      "userId": {
        "type": "long" // 数据类型为长整型
      },
      // 编辑时间字段,数据类型为日期,格式为yyyy-MM-dd HH:mm:ss
      "editTime": {
        "type": "date", // 数据类型为日期
        "format": "yyyy-MM-dd HH:mm:ss" // 日期格式
      },
      // 创建时间字段,数据类型为日期,格式为yyyy-MM-dd HH:mm:ss
      "createTime": {
        "type": "date", // 数据类型为日期
        "format": "yyyy-MM-dd HH:mm:ss" // 日期格式
      },
      // 更新时间字段,数据类型为日期,格式为yyyy-MM-dd HH:mm:ss
      "updateTime": {
        "type": "date", // 数据类型为日期
        "format": "yyyy-MM-dd HH:mm:ss" // 日期格式
      },
      // 是否删除字段,数据类型为关键字,适合精确匹配
      "isDelete": {
        "type": "keyword" // 数据类型为关键字,不会被分词
      }
    }
  }
}

alias别名的作用?

零停机切换

根据需求创建一个新的索引。例如,如果当前索引名为 index_v1,则可以创建一个新索引 index_v2

json 复制代码
PUT /index_v2
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_smart"
      }
    }
  }
}

将旧索引中的数据复制到新索引中。可以使用 Elasticsearch 的 _reindex API 实现。

json 复制代码
POST /_reindex
{
  "source": {
    "index": "index_v1"  // 源索引
  },
  "dest": {
    "index": "index_v2"  // 目标索引
  }
}

使用别名将查询流量从旧索引切换到新索引。假设当前别名 my_alias 指向 index_v1,现在将其切换到 index_v2

json 复制代码
POST /_aliases
{
  "actions": [
    { "remove": { "index": "index_v1", "alias": "my_alias" } },  // 移除旧索引的别名
    { "add": { "index": "index_v2", "alias": "my_alias" } }      // 添加新索引的别名
  ]
}

确认新索引运行正常后,可以删除旧索引以释放存储空间。实现无缝切换

相关推荐
T06205142 分钟前
【面板数据】地级市及区县人口空心化数据(2000-2024年)
大数据
Aktx20FNz1 小时前
iFlow CLI 完整工作流指南
大数据·elasticsearch·搜索引擎
LaughingZhu2 小时前
Anthropic 收购 Oven 后,Claude Code 用运行时写了一篇护城河文章
大数据·人工智能·经验分享·搜索引擎·语音识别
学习3人组2 小时前
TortoiseGit冲突解决实战上机练习
大数据·elasticsearch·搜索引擎
Ln5x9qZC22 小时前
Flink SQL 元数据持久化实战
大数据·sql·flink
OYpBNTQXi2 小时前
Flink Agents 源码解读 --- (6) --- ActionTask
大数据·flink
A__tao3 小时前
Elasticsearch Mapping 一键生成 Go Struct,支持嵌套解析
elasticsearch·es
中金快讯3 小时前
济民健康医疗服务占比提升至46%!业务结构调整初见成效
大数据·人工智能
lizhihai_993 小时前
股市学习心得-尾盘半小时买入法
大数据
大大大大晴天️3 小时前
Hudi 生产问题排障-乱序Upsert入湖数据丢失
大数据·flink·hudi