Elasticsearch 学习笔记

Elasticsearch 学习笔记

简介

Elasticsearch(简称:ES) 是一个免费且开放的分布式搜索和分析引擎,适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。Elasticsearch 在 Apache Lucene 的基础上开发而成,由 Elasticsearch N.V.(即现在的 Elastic)于 2010 年首次发布。Elasticsearch 以其简单的 REST 风格 API、分布式特性、速度和可扩展性而闻名,是 Elastic Stack 的核心组件;Elastic Stack 是一套适用于数据采集、扩充、存储、分析和可视化的免费开源工具。人们通常将 Elastic Stack 称为 ELK Stack(代指 Elasticsearch、Logstash 和 Kibana),目前 Elastic Stack 包括一系列丰富的轻量型数据采集代理,这些代理统称为 Beats,可用来向 Elasticsearch 发送数据。

官方网站:https://www.elastic.co/cn/

官方英文文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/getting-started.html

官方中文文档:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

Elasticsearch 用途

  • 应用程序搜索
  • 网站搜索
  • 企业搜索
  • 日志处理和分析
  • 基础设施指标和容器监测
  • 应用程序性能监测
  • 地理空间数据分析和可视化
  • 安全分析
  • 业务分析

Elasticsearch 基本概念

  • 索引(Index):索引是具有相同结构的文档集合。在 Elasticsearch 中,索引是个非常重要的内容,对于 Elasticsearch 的大部分操作都是基于索引来完成的。它类似于关系数据库中的数据库。每个索引可以包含多个文档和类型。索引可以分为分片,每个分片可以分布在不同的节点上。

  • 类型(Type):Elasticsearch 中的类型类似数据库中的表。但是从 7.0 版本开始,Elasticsearch 不再支持 Type 的概念,不同的类型使用单独的索引来管理。所有的文档类型都默认使用_doc

  • 文档(Document):文档类似于关系数据库中的一行记录。每个文档都有一个唯一标识符(ID),并且有一个 JSON 格式的数据内容。

  • 映射(Mapping):映射定义了索引中每个字段的数据类型和属性。ElasticSearch 会根据映射将数据存储在倒排索引中。

  • 倒排索引:ElasticSearch 使用倒排索引来实现文档搜索。它将文档中的每个单词都存储到一个排序后的列表中,并将单词所出现的文档 ID 与之关联。这样,就可以通过关键字来快速查找匹配的文档。

    举例:比如搜索关键词“小米手机”,保存记录中有1.南方小米、2.东北大米、3.小米手机

    ES 会对搜索的关键词进行分词,分词后匹配如下:

    关键词 ID
    1,3
    1,2,3
    3
    3

    从表中,可以看到,每个分词对应着一组 ID。然后 ES 会对这些匹配的 ID 进行评分,即按照 ID 的出现次数。从分词表中可以看出 ID 为 3 的匹配次数最多。最终 ES 会按照评分从高到低排序查询出数据,即[3.小米手机, 1.南方小米, 2.大米]。

  • 分片(shard):分片是将一个索引(index)拆分成多个部分的过程,每个部分称为一个分片。每个分片包含部分索引数据和索引元数据,这些分片可以在不同的节点上存储和处理,从而提高性能和可扩展性。分片包含主分片和副本分片,每个索引默认都有一个主分片和一个副本分片,并且放到不同的节点上。

    • 主分片(primary shard):主分片是索引的原始分片,包含索引的一部分数据。每个主分片在一个节点上维护,可以被分配到集群中的任何节点上。这有点儿类似关系型数据库的水平分库分表,或类似 Redis 的集群模式,通过减少单点存储的数据量来达到提高性能的目的。**注意:主分片数量一旦确定就无法再修改了,如果必须要修改只能重新创建索引,并将原索引的数据迁移到新索引中。虽然 Elasticsearch 提供了自动迁移的 API,但如果数据量过大,迁移会非常耗时。因此,建议一开始就规划好分片数量,尽可能避免后期修改。**
    • 副本分片(replica shard):副本分片是主分片的复制品,每个主分片可以有一个或多个副本。当主分片的数据发生变化,Elasticsearch 会自动将数据同步到副本分片上。当主分片失效,Elasticsearch 会自动选举一个副本分片作为主分片,以达到容错的目的。正常情况下,副本分片会作为只读分片提供查询。这有点类似关系型数据库的主从模式,通过主从达到读写分离的目的,当主节点故障,则从节点自动提升为主节点。

    主分片和副本分片被创建时,Elasticsearch 会自动将它们放到不同的节点上,以防止机器节点故障后,副本分片无法被提升为主分片。

    分片划分建议

    主分片的大小最好控制在 30GB 以内,即每个分片存储的数据不要超过 30G,并且主分片的最大数量最好不好超过 100 个。主分片的数量确定可以参考这个公式预估索引数据大小 / 每个分片限制大小

    比如:预计索引的数据有 500GB,每个索引控制在 30GB。

    分片数量 = 500 / 30 = 16

    即:可以定义 16 个主分片。

    这里只是一个参考,实际划分还要参考硬件性能、并发量等条件。另外,尽量避免单个索引的数量过大,如果数据量本身就很大,可以定义多个索引来存储。比如日志信息,日志是每时每刻都在产生的,可以设定一个时间范围,比如每个月的日志使用一个单独的索引,即索引定义为logs_<年>_<月>。这样做的好处是避免了单个索引的数据量过大,并且当集群扩展节点时,数据会分配到新的节点存储,这样也能达到平衡的目的。

安装 Elasticsearch

Elasticsearch 有简单安装和集群安装两种方式。如果只是想简单体验 Elasticsearch 的功能,可以下载一个 Elasticsearch 的安装包进行安装即可。或使用 Docker 镜像进行安装。

但在实际使用中,Elasticsearch 一般都使用的是集群环境。因此,本章节介绍怎么使用 Docker 搭建一个 Elasticsearch 的集群环境。使用 Docker 安装 Elasticsearch 集群需要先安装 Docker 和 Docker Compose 环境。

本次安装的 Elasticsearch 版本是 7.17.7,因为在安装 IK 分词器时发现,IK 分词器的版本只到 7.17.7。

安装前准备

使用 Docker 安装 Elasticsearch,需要先下载一个镜像,然后运行这个镜像。从镜像运行的容器中复制出 Elasticsearch 所需的配置文件。后面会以编排的形式将配置文件挂载上去。

  • 下载镜像

    1
    docker pull elasticsearch:7.17.7
  • 使用镜像运行容器

    1
    docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.17.7
  • 查看运行的镜像

    1
    docker ps -a

    命令执行结果如下:

    1
    2
    3
    -- console log --
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    3277e5f102ab elasticsearch:7.17.7 "/tini -- /usr/local…" 18 seconds ago Up 13 seconds 0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9300->9300/tcp, :::9300->9300/tcp elasticsearch
  • 进入容器

    1
    docker exec -it <容器ID> /bin/bash

    重点:成功进入容器后需要查询几个关键的信息。

    • 查询目录所属用户

      使用ll命令查看当前目录,返回如下信息

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      -- console log --
      drwxrwxr-x 1 root root 58 Mar 24 02:33 ./
      drwxr-xr-x 1 root root 27 Jan 31 05:40 ../
      -rw-r--r-- 1 root root 220 Jan 31 05:40 .bash_logout
      -rw-r--r-- 1 root root 3771 Jan 31 05:40 .bashrc
      drwxrwxr-x 3 elasticsearch root 17 Mar 24 02:33 .cache/
      -rw-r--r-- 1 root root 807 Jan 31 05:40 .profile
      -r--r--r-- 1 root root 3860 Jan 31 05:33 LICENSE.txt
      -r--r--r-- 1 root root 642830 Jan 31 05:35 NOTICE.txt
      -r--r--r-- 1 root root 2710 Jan 31 05:33 README.asciidoc
      drwxrwxr-x 1 elasticsearch root 6 Jan 31 05:39 bin/
      drwxrwxr-x 1 elasticsearch root 36 Mar 24 02:33 config/
      drwxrwxr-x 1 elasticsearch root 19 Mar 24 02:33 data/
      dr-xr-xr-x 1 root root 17 Jan 31 05:38 jdk/
      dr-xr-xr-x 3 root root 4096 Jan 31 05:38 lib/
      drwxrwxr-x 1 elasticsearch root 37 Mar 24 02:33 logs/
      dr-xr-xr-x 61 root root 4096 Jan 31 05:38 modules/
      drwxrwxr-x 1 elasticsearch root 6 Jan 31 05:35 plugins/

      这里主要关注三个重要的信息,config、data、logs 这三个目录的所属用户是elasticsearch。这里是个大坑,后面我们在编排服务时,挂载目录的所属用户要和这里的所属用户保持一致,否则启动会提示权限错误。

    • 查看用户的 id 信息

      1
      id elasticsearch

      命令返回结果如下:

      1
      2
      -- console log --
      uid=1000(elasticsearch) gid=1000(elasticsearch) groups=1000(elasticsearch),0(root)

      这里的 uid 的值是 1000,这个值一定要记好。后面会用到这个值。

    • 查询当前路径

      1
      pwd

      命令返回结果如下:

      1
      2
      -- console log --
      /usr/share/elasticsearch

      这个路径也要记录下来,后面也会用到。确定好路径之后,可以使用exit命令退出容器。

  • 复制配置文件目录到宿主机

    这一步是将容器下的配置目录复制到宿主机上,这里就用到了前面查询到的/usr/share/elasticsearch路径。

    1
    2
    3
    4
    5
    # 新建用于保存配置文件的临时目录
    mkdir -p ~/elasticsearch/example

    # 复制容器中的配置文件到宿主机
    docker cp <容器ID>:/usr/share/elasticsearch/config ~/elasticsearch/example/config
  • 停止并删除 Elasticsearch 容器

    前面启动容器只是为了获取配置文件,配置文件复制出来以后,容器就可以停止了。

    1
    docker rm $(docker stop <容器ID>)

修改 elasticsearch.yml 配置文件

单节点启动的配置文件比较简单,我们需要将其修改成集群模式的配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 集群名称,所有集群节点的名称要一致。
cluster.name: es-cluster
# 节点名称,每个节点使用不同的命名,比如:es-node1、es-node2、es-node3
node.name: es-node1
# 是否可以成为master节点
node.master: true
# 是否允许该节点存储数据,默认开启
node.data: true
# 网络绑定
network.host: 0.0.0.0
# 设置对外服务的http端口
http.port: 9200
# 设置节点间交互的tcp端口
transport.port: 9300
# 集群发现,此处配置除了自己以外的其他节点。
discovery.seed_hosts:
- es-node2
- es-node3
# 指定可以成为 mater 节点的 hostname 或者 ip,这些配置将会在第一次选举中进行计算
cluster.initial_master_nodes:
- es-node1
- es-node2
- es-node3
# 支持跨域访问
http.cors.enabled: true
http.cors.allow-origin: "*"
# 安全认证
xpack.security.enabled: false
#http.cors.allow-headers: "Authorization"

编排服务

由于搭建的是集群,所以最好是将每个节点的配置、数据、日志等分开保存。

  • 创建主从节点目录

    1
    2
    3
    4
    5
    6
    7
    8
    # 分别创建节点的数据文件目录
    mkdir -p ~/elasticsearch/node1/data ~/elasticsearch/node2/data ~/elasticsearch/node3/data

    # 分别创建三个节点的日志文件目录
    mkdir -p ~/elasticsearch/node1/logs ~/elasticsearch/node2/config ~/elasticsearch/node3/logs

    # 创建插件目录,由于插件是各个节点共享的,因此只创建一个目录即可。
    mkdir -p ~/elasticsearch/plugins
  • 复制上一小节编写好的配置文件到节点目录

    1
    2
    3
    cp -r ~/elasticsearch/example/config ~/elasticsearch/node1/config
    cp -r ~/elasticsearch/example/config ~/elasticsearch/node2/config
    cp -r ~/elasticsearch/example/config ~/elasticsearch/node3/config

    复制完成后,分别修改三个节点的配置。主要的修改项如下:

    • node.name:集群节点名称,它将作为节点的标识存在,最好是每个节点使用不同的名称。
    • discovery.seed_hosts:集群节点发现,此处配置除了自己以外的其他节点。可以是 hostname 或 IP:9300,这里的 9300 是集群交互端口,不写会默认使用 9300,如果你使用的是 IP 地址,建议还是写上。
  • 给新建的目录授权

    这里为了后续的操作方便,可以直接给elasticsearch目录授权。另外还需要给新建的目录指定所属用户,这里就用到了前面查询到的 uid。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 设置权限
    chmod -R o+xrw ~/elasticsearch

    # 指定data目录的所属用户
    chown 1000 ~/elasticsearch/node1/data
    chown 1000 ~/elasticsearch/node2/data
    chown 1000 ~/elasticsearch/node3/data

    # 指定logs目录的所属用户
    chown 1000 ~/elasticsearch/node1/logs
    chown 1000 ~/elasticsearch/node2/logs
    chown 1000 ~/elasticsearch/node3/logs

    # 指定日志目录的所属用户
    chown 1000 ~/elasticsearch/node1/config
    chown 1000 ~/elasticsearch/node2/config
    chown 1000 ~/elasticsearch/node3/config

    # 指定插件目录的所属用户
    chown 1000 -R ~/elasticsearch/plugins

    此处使用的是递归授权,即 elasticsearch 目录及其子目录和文件,授予其他用户的执行和读写权限。另外,使用 chown 指定所属用户之后,使用ll命令查看时,发现目录的所属用户并不是elasticsearch。这是因为宿主机上不存在这个用户,但是它会有一个用户与容器中的elasticsearch用户对应。因此,只要保证宿主机的用户和容器中的用户uid一致就可以了。

  • 新建 Docker 网络

    这一步的目的是让后面创建的所有容器都基于这个网络运行。

    1
    docker network create -d bridge elasticsearch_network

    此处创建了一个桥接网络,后面的 Elasticsearch 和 Kibana 编排时,都使用这个网络。这样容器之间就可以互联互通了。如若不然,就必须将所有的服务都写入同一个编排文件中。

    如果想要查看已经创建的网络,可以使用下面的命令:

    1
    docker network inspect <网络名称>
  • 编写编排文件

    elasticsearch目录下新建一个elasticsearch-compose.yml文件。编写内容如下:

    elasticsearch-compose.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    version: "3"
    services:
    es-node1:
    container_name: es-node1
    hostname: es-node1
    image: elasticsearch:7.17.7
    restart: always
    user: root
    ports:
    - 9200:9200
    - 9300:9300
    # 指定使用的网络
    networks:
    - elasticsearch_network
    volumes:
    - ~/elasticsearch/node1/config:/usr/share/elasticsearch/config
    - ~/elasticsearch/node1/data:/usr/share/elasticsearch/data
    - ~/elasticsearch/node1/logs:/usr/share/elasticsearch/logs
    - ~/elasticsearch/plugins:/usr/share/elasticsearch/plugins
    environment:
    - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    - "TZ=Asia/Shanghai"
    privileged: true
    stdin_open: true
    tty: true

    es-node2:
    container_name: es-node2
    hostname: es-node2
    image: elasticsearch:7.17.7
    restart: always
    ports:
    - 9201:9200
    - 9301:9300
    # 指定使用的网络
    networks:
    - elasticsearch_network
    volumes:
    - ~/elasticsearch/node2/config:/usr/share/elasticsearch/config
    - ~/elasticsearch/node2/data:/usr/share/elasticsearch/data
    - ~/elasticsearch/node2/logs:/usr/share/elasticsearch/logs
    - ~/elasticsearch/plugins:/usr/share/elasticsearch/plugins
    environment:
    - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    - "TZ=Asia/Shanghai"
    privileged: true
    stdin_open: true
    tty: true

    es-node3:
    container_name: es-node3
    hostname: es-node3
    image: elasticsearch:7.17.7
    restart: always
    ports:
    - 9202:9200
    - 9302:9300
    # 指定使用的网络
    networks:
    - elasticsearch_network
    volumes:
    - ~/elasticsearch/node3/config:/usr/share/elasticsearch/config
    - ~/elasticsearch/node3/data:/usr/share/elasticsearch/data
    - ~/elasticsearch/node3/logs:/usr/share/elasticsearch/logs
    - ~/elasticsearch/plugins:/usr/share/elasticsearch/plugins
    environment:
    - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    - "TZ=Asia/Shanghai"
    privileged: true
    stdin_open: true
    tty: true

    # 开启外部网络访问,此处开启的是一开始创建好的桥接网络
    networks:
    elasticsearch_network:
    external: true

    注意:JVM 内存的配置不要设置的太小,否则集群无法启动。我这里配置的是最低要求,实际使用时,可以根据情况自行调整。一般调整策略为:(宿主机总内存 / 实例数量 / 2) + 1,计算结果取整数。比如宿主机内存是 8G,部署了 3 个节点实例,实际计算 2.3333,取整数为 2,则我这里每个节点的最大内存不要超过 2GB。最小内存取最大内存的一半即可,但是不要低于 512M。

启动集群

1
docker-compose -f elasticsearch-compose.yml up -d

启动完成后,分别使用 9200、9201、9202 三个端口访问 Elasticsearch。如果都能正常访问,则说明搭建成功。也可以访问下面的地址来查看集群状态。

http://<IP>:<端口>/_cluster/health?pretty,成功访问后返回如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"cluster_name": "es-cluster",
"status": "green",
"timed_out": false,
"number_of_nodes": 3,
"number_of_data_nodes": 3,
"active_primary_shards": 3,
"active_shards": 6,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 100
}

其中"status": "green"是指集群状态正常。number_of_nodes是指当前活动的节点数。

安装 Kibana

Kibana 是一个开源的分析与可视化平台,它可用于管理 Elasticsearch。

注意:Kibana 的版本最好和 Elasticsearch 的版本保持一致。

安装前准备

此处的步骤和安装 Elasticsearch 时的步骤,大致相同,都需要先运行一个临时容器,然后从中复制出配置文件。

  • 下载 Kibana 镜像

    1
    2
    # 再次声明,Kibana 的版本最好与 ElasticSearch 保持一致。
    docker pull kibana:7.17.7
  • 运行一个临时容器

    1
    docker run -d --name kibana -p 5601:5601 kibana:7.17.7
  • 进入容器

    1
    docker exec -it <容器ID> /bin/bash
    • 查看目录及权限

      1
      2
      # 有些容器不能使用 ll 命令,如果不能用,可以使用 ls -l
      ls -l

      命令执行结果如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      -- console log --
      total 1152
      -rw-rw-r-- 1 kibana root 3860 Jan 30 12:30 LICENSE.txt
      -rw-rw-r-- 1 kibana root 1128786 Jan 30 12:30 NOTICE.txt
      -rw-rw-r-- 1 kibana root 3970 Jan 30 12:30 README.txt
      drwxrwxr-x 2 kibana root 94 Jan 30 12:30 bin
      drwxrwxr-x 1 kibana root 24 Jan 30 12:44 config
      drwxrwxr-x 1 kibana root 18 Mar 24 04:10 data
      drwxrwxr-x 6 kibana root 108 Jan 30 12:30 node
      drwxrwxr-x 682 kibana root 20480 Jan 30 12:30 node_modules
      -rw-rw-r-- 1 kibana root 740 Jan 30 12:30 package.json
      drwxrwxr-x 2 kibana root 6 Jan 30 12:30 plugins
      drwxrwxr-x 9 kibana root 131 Jan 30 12:30 src
      drwxrwxr-x 3 kibana root 79 Jan 30 12:30 x-pack
    • 查看目录的完整路径

      1
      pwd

      命令执行结果如下:

      1
      2
      -- console log --
      /usr/share/kibana
    • 查看 kibana 的 uid

      1
      id kibana

      命令执行结果如下:

      1
      2
      -- console log --
      uid=1000(kibana) gid=1000(kibana) groups=1000(kibana),0(root)

    将上面查询到的结果记录下来,后面会用到。

  • 复制配置文件目录到宿主机

    1
    2
    3
    4
    5
    # 新建用于保存配置文件的临时目录
    mkdir -p ~/kibana/example

    # 复制容器中的配置文件目录到宿主机临时目录
    docker cp <容器ID>:/usr/share/kibana/config ~/kibana/example/config

    复制完配置文件之后,临时容器就可以删除了,否则后面再启动新实例的时候,会有端口冲突。

修改 kibana.yml 配置文件

kibana.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ---------- 服务配置 ----------
# Kibana 服务名
server.name: kibana
# 服务IP
server.host: "0.0.0.0"
# 服务端口
server.port: 5601
# Kibana 停止超时时间,当 Kibana 需要关闭或重启时,需要等待 ES 确认。这里是等待的多少秒后关闭。
# 如果 ES 集群响应缓慢,这里设置的时间最好长一点。因为超过这个时间,Kibana就不会再等待了。
# 当然也不要太长。默认是5秒。
server.shutdownTimeout: "5s"

# ---------- Elasticsearch ----------
# 设置 Elasticsearch 集群主机列表
# 如果编排 ES 服务时指定了 hostname,则这里可以用 hostname,否则可以使用IP地址。
# 如果使用的是宿主机IP,则这里的端口是容器对外暴露的端口。否则为容器内端口。
elasticsearch.hosts:
["http://es-node1:9200", "http://es-node2:9200", "http://es-node3:9200"]
# 这个配置项,基于 Docker 部署会有。即:开启对容器内 ES 的监控。默认值为 true
monitoring.ui.container.elasticsearch.enabled: true

# ---------- 其他配置 ----------
# 国际化,这里用的 Docker 镜像已经集成了语言包。如果是裸机安装,需要先安装语言包,才能国际化。
i18n.locale: "zh-CN"

Kibana 的配置项很多,这里只列举了一些关键参数。如果想要使用其他相关功能,可以查阅官方文档。

编排服务

  • 创建相关目录

    1
    2
    # 创建数据文件目录
    mkdir -p ~/kibana/data
  • 复制编写好的配置文件到正式目录

    1
    cp -r ~/kibana/example/config ~/kibana/config
  • 给目录授权

    这一步可以借鉴前面的 Elasticsearch 授权说明。

    1
    2
    3
    4
    5
    6
    # 给目录授权
    chmod -R o+xrw ~/kibana

    # 指定所属用户
    chown 1000 ~/kibana/config
    chown 1000 ~/kibana/data
  • 查看已经运行的 Elasticsearch 容器的网络名

    1
    docker inspect <容器ID> --format='{{range $key,$value:=.NetworkSettings.Networks}}{{$key}} {{end}}'

    命令执行结果如下:

    1
    2
    -- console log --
    elasticsearch_default

    在书写编排文件时,要让 kibana 加入到这个网络,否则无法使用 hostname 访问集群节点。

  • 编写编排文件

    kibana目录下新建一个kibana-compose.yml文件,编写内容如下:

    kibana-compose.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    version: "3"
    services:
    kibana:
    container_name: kibana
    hostname: kibana
    image: kibana:7.17.7
    restart: always
    ports:
    - 5601:5601
    # 配置使用的网络
    networks:
    - elasticsearch_network
    volumes:
    - ~/kibana/config:/usr/share/kibana/config
    - ~/kibana/data:/usr/share/kibana/data
    environment:
    - "TZ=Asia/Shanghai"
    privileged: true
    stdin_open: true

    # 开启外部网络访问,此处开启的是一开始创建好的桥接网络
    networks:
    elasticsearch_network:
    external: true

启动 kibana

1
docker-compose -f kibana-compose.yml up -d

容器创建后,可以使用下面的命令查看是否启动成功。

1
2
3
4
5
# 查看容器运行状态,如果 STATUS 始终是 UP,则说明容器启动成功。
docker ps -a

# 查看容器运行日志,如果没有报错信息,则说明 Kibana 运行良好。
docker logs -f <容器ID>

确保一切正常之后,在浏览器输入:http://<IP 地址>:5061/,就可以访问 Kibana 管理界面了。

新建工作区

新建工作区的目的是便于管理。当多个项目使用同一个 Elasticsearch 时,可以通过新建工作区来隔离。

进入菜单/Management/Stack Management,在新打开的页面中找到Kibana标签下的工作区选项。点击右上角的创建工作区按钮。按照表单要求填写即可。

开发工具

Kibana 提供了一个非常好用的开发工具。日常的一些 ES 操作都可以在上面完成。

开发工具位置:菜单/Management/开发工具

索引

索引对于 Elasticsearch 存储来说是最基本的单元。所有的数据都是存储在某个索引上的。

新建索引

简单索引创建

1
PUT /demo_user_info

命令执行结果如下:

1
2
3
4
5
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "demo_user_info"
}

此时我们就创建了一个名为demo_user_info的索引。

这里需要注意,一个工作区内不能出现同名的索引。如果我们使用上面的指令执行多次,那么从第二次开始会报错。另外,索引从操作上来将不是必须提前创建的,我们也可以在创建文档的时候创建。比如下面这样:

1
2
3
4
PUT /demo_user_info/_doc
{
userName: "hello"
}

此时,Elasticsearch 会自动帮我们创建一个demo_user_info的索引,并往索引中插入一条数据。

创建索引并设置分片和副本

1
2
3
4
5
6
7
PUT /demo_user_info
{
"settings": {
"number_of_shards": 2,
"number_of_replicas": 3
}
}

参数说明:

  • number_of_shards:分片数量
  • number*of_replicas:副本数量,这里需要说明的是,副本总数量 = 分片数量 * 设定的副本数量。比如:分片数量为 2,副本数量为 3,则副本总数量 = 2 _ 3 = 6 个。由此可以看出,这里指定的副本数量是指每个主分片有几个副本。

修改索引

索引不能修改主分片数量,其他修改可以通过相应的指令来修改。

修改副本数量

1
2
3
4
5
6
PUT /demo_user_info/_settings
{
"settings": {
"number_of_replicas": 4
}
}

修改映射

以修改userName为例。

1
2
3
4
5
6
7
8
PUT /demo_user_info/_mapping
{
"properties": {
"userName": {
"type": "keyword"
}
}
}

删除索引

1
DELETE /my-index

迁移分片

对于索引不能修改的设置,可以通过新建索引,然后进行索引迁移的办法来实现。

1
2
3
4
5
6
7
8
9
POST _reindex
{
"source": {
"index": "old-index"
},
"dest": {
"index": "new-index"
}
}

使用举例

  • 关闭索引的写操作

    关闭写操作的目的是为了在迁移的过程中,防止有新的写入,导致迁移后的数据不完整。

    1
    2
    3
    4
    PUT /demo_user_info/_settings
    {
    "blocks.write": true
    }

    参数说明:

    • blocks.write:写入锁。true-上锁;false-解锁。
  • 创建新索引

    1
    2
    3
    4
    5
    6
    7
    PUT /demo_user_info-2
    {
    "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
    }
    }
  • 迁移数据到新索引

    1
    2
    3
    4
    5
    6
    7
    8
    9
    POST _reindex
    {
    "source": {
    "index": "demo_user_info"
    },
    "dest": {
    "index": "demo_user_info-2"
    }
    }

    数据迁移完毕后,测试没有问题再删除旧的索引。

索引别名

索引别名是一个可以指向多个索引的别名,它允许用户使用别名来查询索引,这在索引迁移和合并查询时非常有效。但是需要注意,一对多的别名在读写时,一方面性能不好,另一方面可能导致数据不一致。因此,除非必要,否则尽可能使用一对一的别名。

还是以上面的索引迁移为例,我们可以在一开始设计索引时就定义好一个别名,比如user_info,它指向一个具体的索引demo_user_info

1
2
3
4
5
6
7
8
9
10
11
POST /_aliases
{
"actions": [
{
"add": {
"index": "demo_user_info",
"alias": "user_info"
}
}
]
}

待数据迁移完毕后,将别名指向新的索引。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /_aliases
{
"actions": [
{
"remove": {
"index": "demo_user_info",
"alias": "user_info"
}
},
{
"add": {
"index": "demo_user_info-2",
"alias": "user_info"
}
}
]
}

这样,我们在查询索引时,就可以一直使用别名user_info来查询。避免索引迁移后进行大量的修改。

映射

Elasticsearch 的映射(Mapping)是指用于定义索引中字段的数据类型、分词器等属性的结构。映射由多个字段映射组成,每个字段映射定义了一个字段的名称、数据类型、分词器、索引方式、存储方式等属性。映射在索引创建时定义,可以用于约束和规范数据,以提高搜索效率和精度。

在 Elasticsearch 中,每个索引都有一个映射,映射中包含了索引中所有字段的定义。下面是一个映射的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"content": {
"type": "text"
},
"author": {
"type": "keyword"
},
"timestamp": {
"type": "date"
}
}
}
}

在这个映射中,包含了 4 个字段映射:

  • title:文档标题字段,数据类型为 text。
  • content:文档内容字段,数据类型为 text。
  • author:作者字段,数据类型为 keyword。
  • timestamp:时间戳字段,数据类型为 date。

每个字段映射可以包含多个属性,常用的属性包括:

  • type:字段的数据类型,例如 text、keyword、date 等。
  • analyzer:用于对文本字段进行分词的分词器。
  • index:指定字段是否需要被索引,例如设置为 false 的字段不会被索引。
  • store:指定字段是否需要被存储,例如设置为 true 的字段会被存储在磁盘上,方便进行检索。
  • format:指定日期字段的格式。

映射的作用主要有两个:

  1. 约束数据:映射可以规范字段的数据类型、分词器等属性,从而约束数据的输入和格式,避免输入错误或无效数据的出现,提高搜索的准确性和精度。
  2. 提高搜索效率:映射可以指定字段的索引方式、存储方式等属性,从而提高搜索效率和速度,避免不必要的计算和 IO 操作。

需要注意的是,和主分片一样,映射一旦定义后,就不能够再修改。因此,在设计映射时需要考虑到数据的需求和未来的扩展性,避免在后期需要修改映射的情况。如果需要修改映射并且保证每个文档都有新的映射,只能够通过重新创建索引的方式来实现。

创建映射

通常情况下,映射会在创建索引时一起被创建出来。但如果已经有索引了,也可以再次创建,只不过新增的映射不会作用在历史数据上。

  • 创建索引时同步创建映射

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    PUT /my-index
    {
    "mappings": {
    "properties": {
    "fieldName": {
    "type": "text"
    }
    }
    }
    }
  • 在已有的索引上创建映射

    1
    2
    3
    4
    5
    6
    7
    8
    PUT /my-index/_mapping
    {
    "properties": {
    "fieldName": {
    "type": "text"
    }
    }
    }

创建索引使用到的参数也不用刻意去记,当第一个文档路径被成功创建之后,Elasticsearch 会根据数据结构自动推断出映射。之后,我们只需要根据自己的需求,修改对应的参数即可,比如:分词设置、分析器设置等。

另外,每个字段中还可以再定义properties配置,以此来构建一个复杂的数据结构。

修改映射

注意:这里的修改只是修改了字段的索引方式,其它不能修改。索引的 Mapping 字段只能追加,不能删除和类型修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PUT /my-index/_mapping
{
"properties": {
"fieldName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}

从执行指令上来看,不难发现修改映射和添加映射一样,都是使用的 PUT 方法。当映射不存在时会创建一个新的映射,当映射存在时会对其进行修改。

小结

结合上面的内容不难看出,在 Elasticsearch 中,所有涉及到结构层面的东西是不能修改的。比如主分片、映射等,因为这些修改会导致数据不完整,因此不支持修改。如果想要修改,只能够通过重建索引来实现。

建议:在使用 Elasticsearch 之前,应当规划好索引并且设计好数据结构。因为就算是 Elasticsearch 支持索引的迁移,这也会给运维的过程增加很多负担,因为每次的索引迁移都需要关闭索引的写入,这也就导致一段时间内,某些功能将不可用。

除此之外,对于数据量非常庞大,并且允许冷热分离的索引,建议采用一对多别名的方式来使用。可以使用时间维度将数据分成多个索引,随着时间的增长逐步增加。然后将别名与一定时间范围内的索引进行绑定来控制查询范围,比如只允许查询三个月内的数据,其他数据只能后台查询。

文档

Elasticsearch 的文档类似关系型数据库中的一行记录,是日常开发过程中使用最多的操作。因此,文档的操作也是 Elasticsearch 学习的重点。

创建文档

要创建一个文档,需要向 Elasticsearch 的一个索引中添加一个 JSON 格式的文档。虽然 Elasticsearch 支持在第一次创建文档时同步创建索引。但如果想要对索引进行设置,比如主分片数量、固定映射字段等操作,就必须先创建好文档再写入数据,因为同步创建索引时使用的是 Elasticsearch 默认值。

下面是一个创建文档的简单示例:

1
2
3
4
5
PUT /my_index/_doc/1
{
"title": "Elasticsearch文档",
"content": "Elasticsearch 是一个分布式的全文搜索和分析引擎,它能够帮助用户存储、搜索和分析海量的数据。"
}

这个例子中,使用了 PUT 请求将一个 JSON 格式的文档添加到名为“my_index”的索引中,该文档的 ID 为“1”。文档包含两个字段:“title”和“content”。

在创建文档时,可以选择为文档指定一个唯一的 ID,或者让 Elasticsearch 自动生成一个唯一的 ID。如果您未指定文档 ID,则 Elasticsearch 会自动生成一个唯一的 ID。

除了使用 PUT 请求之外,还可以使用 POST 请求创建文档。例如:

1
2
3
4
5
POST /my_index/_doc
{
"title": "Elasticsearch文档",
"content": "Elasticsearch 是一个分布式的全文搜索和分析引擎,它能够帮助用户存储、搜索和分析海量的数据。"
}

在这种情况下,Elasticsearch 会自动生成一个唯一的 ID,并将文档添加到名为“my_index”的索引中。

注意,如果尝试添加一个具有相同 ID 的文档,则 Elasticsearch 会将新文档替换旧文档。如果您希望将文档添加到索引中而不是替换旧文档,则可以使用 POST 请求,并将“_id”字段设置为一个新的唯一值。

在 Elasticsearch 中,PUT 和 POST 请求都可以用来创建新文档,但它们之间有一些重要的区别:

  • PUT 请求必须指定文档 ID,而 POST 请求可以让 Elasticsearch 自动生成文档 ID。
  • PUT 请求是幂等的,即重复调用同一个 PUT 请求多次不会导致数据的变化,而 POST 请求不是幂等的。

版本号

每个文档都有一个版本号,使用版本号参数可以达到并发控制的效果。

查询版本号

1
GET /my_index/_doc/1

这里查询出 ID 为 1 的文档,返回内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_version": 8,
"_seq_no": 8,
"_primary_term": 1,
"found": true,
"_source": {
"title": "Elasticsearch文档ssss",
"content": "Elasticsearch 是一个分布式的全文搜索和分析引擎,它能够帮助用户存储、搜索和分析海量的数据。"
}
}

这里有三个重要的信息:

  • _version:它是 Elasticsearch 的内部版本号,是 Elasticsearch 在创建或更新文档时自动分配的,也是 Elasticsearch 内部控制幂等的机制,不能作为乐观锁来使用。
  • _seq_no:文档序列号,这是一个外部版本,每次修改文档序列号都会增加。它可以作为乐观锁来控制并发操作。
  • _primary_term:文档所在的分片号,Elasticsearch 的索引是支持分片的,数据放在哪个分片上是有 Elasticsearch 决定的。因此,使用序列号控制并发操作时,需要向 Elasticsearch 说明文档在哪个分片上。

比如我们在修改数据的时候,使用版本号来控制并发,如下:

1
2
3
4
5
PUT /my_index/_doc/1?if_seq_no=8&if_primary_term=1
{
"title": "Elasticsearch文档ssss",
"content": "Elasticsearch 是一个分布式的全文搜索和分析引擎,它能够帮助用户存储、搜索和分析海量的数据。"
}

命令执行后,返回数据如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_version": 9,
"result": "updated",
"_shards": {
"total": 3,
"successful": 3,
"failed": 0
},
"_seq_no": 9,
"_primary_term": 1
}

当再次执行命令时,返回结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict, required seqNo [8], primary term [1]. current document has seqNo [9] and primary term [1]",
"index_uuid": "qNAAFgvPRpWhEjea30PAow",
"shard": "0",
"index": "my_index"
}
],
"type": "version_conflict_engine_exception",
"reason": "[1]: version conflict, required seqNo [8], primary term [1]. current document has seqNo [9] and primary term [1]",
"index_uuid": "qNAAFgvPRpWhEjea30PAow",
"shard": "0",
"index": "my_index"
},
"status": 409
}

这是会看到报错信息,其中有一段信息内容为version conflict, required seqNo [8], primary term [1]. current document has seqNo [9] and primary term [1]。这段话的大致意思是请求的序列号为 8,但当前文档的序列号是 9。这和我们在使用关系型数据库时,通过查询版本号控制幂等几乎是一样的。

修改文档

注意:上面提到创建文档之后,再次使用命令进行操作会对文档进行修改。这里的修改实际上是覆盖数据。

比如我们执行

1
2
3
4
PUT /my_index/_doc/1
{
"title": "Elasticsearch文档ssss"
}

那么 ID 为 1 的文档将会被新文档覆盖,当再次查询时,会发现content字段没有了。因此我们在修改文档时,尽可能使用部分修改,即只修改列举出的字段。尽可能不要使用覆盖操作。

Elasticsearch 支持两种文档的修改方式,并且更新只能使用 POST 方式,另外从示例中可以看出,局部修改时也可以使用序列号来进行并发控制。

  • 局部文档更新

    1
    2
    3
    4
    5
    6
    POST /my_index/_update/1?if_seq_no=15&if_primary_term=1
    {
    "doc": {
    "title": "Elasticsearch文档局部更新2"
    }
    }
  • 使用脚本更新文档

    1
    2
    3
    4
    5
    6
    POST /my_index/_update/1?if_seq_no=16&if_primary_term=1
    {
    "script": {
    "source": "ctx._source.title = 'Elasticsearch文档脚本更新'"
    }
    }

    Elasticsearch 脚本使用的是Painless语言,它的语法类似Groovy语言,是 Java 的扩展脚本。因此这里可以直接使用它的语法来做更深入的操作。

    比如:我们在修改的时候,文档内所有的英文改成大写。

    1
    2
    3
    4
    5
    6
    POST /my_index/_update/1?if_seq_no=17&if_primary_term=1
    {
    "script": {
    "source": "ctx._source.title = 'Elasticsearch文档脚本更新'.toUpperCase()"
    }
    }

    这里可以看到,字符串后面调用了一个toUpperCase()方法。

按条件修改

除了上面提到的根据 ID 修改文档外,也可以根据条件来修改。

1
2
3
4
5
6
7
8
9
10
11
POST /my_index/_update_by_query
{
"query": {
"match": {
"title.keyword": "Elasticsearch文档2"
}
},
"script": {
"source": "ctx._source.title = ctx._source.title + '条件修改'"
}
}

条件修改是一个非常危险的操作,并且一旦修改文档就无法恢复。尤其是该条件字段在 Elasticsearch 中被分词了,这将会导致所有分词匹配的数据都会被修改。

因此,如果想要使用条件修改就一定要将条件进行精准匹配。如果字段被分词可以在查询字段的后面加上.keyword来精准查询,如果字段没有被分词,可以将match替换成term

另外,按条件修改只能通过脚本方式修改,不支持局部更新的方式来修改。如果想要修改多个字段,可以使用 params。比如下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /my_index/_update_by_query
{
"query": {
"match": {
"title.keyword": "Elasticsearch文档2"
}
},
"script": {
"source": "ctx._source.title = params.title; ctx._source.content = params.content",
"params": {
"title": "Elasticsearch文档2条件修改",
"content": "Elasticsearch 是一个分布式的全文搜索和分析引擎"
}
}
}

params 中定义了修改的参数,然后在 source 中使用语法拼接,或在 source 中使用数组来定义每一个需要更新的字段。

删除文档

删除文档时,可以根据 ID 来删除,也可以根据条件来删除。

  • 根据 ID 删除

    1
    DELETE /my_index/_doc/1
  • 按条件删除

    1
    2
    3
    4
    5
    6
    7
    8
    POST /my_index/_delete_by_query
    {
    "query": {
    "match": {
    "title.keyword": "Elasticsearch文档2"
    }
    }
    }

    条件删除是一个非常危险的操作,并且一旦删除文档就无法恢复。尤其是该条件字段在 Elasticsearch 中被分词了,这将会导致所有分词匹配的数据都会被删除。

    因此,如果想要使用条件删除就一定要将条件进行精准匹配。如果字段被分词可以在查询字段的后面加上.keyword来精准查询,如果字段没有被分词,可以将match替换成term

查询文档

以下是 Elasticsearch 常用的一些查询类型:

  • match 查询:该查询将在指定的字段中搜索包含给定单词或短语的文档。它支持模糊匹配和距离计算,并且可以与不同的运算符(如 AND 和 OR)结合使用。
  • term 查询:该查询将在指定字段中查找包含指定术语的文档。它是精确匹配,不会分词查询字符串,而是在原始文本上执行匹配。
  • range 查询:该查询将返回指定范围内的文档。可以指定数字、日期和其他类型的范围。
  • bool 查询:该查询将允许你组合多个查询条件,使用布尔运算符进行联合,例如 AND、OR 和 NOT。
  • prefix 查询:该查询将在指定字段中搜索以给定前缀开头的文档。
  • wildcard 查询:该查询将在指定字段中搜索匹配给定通配符模式的文档。
  • fuzzy 查询:该查询将在指定字段中搜索与给定单词类似的文档,支持模糊匹配。
  • match_phrase 查询:该查询将在指定字段中搜索包含给定短语的文档,但短语必须以相同的顺序和连续出现。
  • match_all 查询:该查询将返回所有文档,可以用于不带任何搜索条件的查询,但是需要指定索引名称。
  • multi_match 查询:该查询将在多个字段中搜索包含指定单词或短语的文档。

下面开始说明一些常用的查询案例

查询所有

1
2
3
4
5
6
GET /my_index/_search
{
"query": {
"match_all": {}
}
}

也可以直接使用

1
GET /my_index/_search

查询时返回指定字段

1
2
3
4
GET /my_index/_search
{
"_source": ["title", "content"]
}

单条件查询

比如查询title字段:

1
2
3
4
5
6
7
8
GET /my_index/_search
{
"query": {
"match": {
"title": "Elasticsearch"
}
}
}

多条件 AND 查询

比如查询titlecontent都包含某个值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "Elasticsearch"
}
},
{
"match": {
"content": "Elasticsearch"
}
}
]
}
}
}

多条件 OR 查询

multi_match:多匹配方式。

1
2
3
4
5
6
7
8
9
GET /my_index/_search
{
"query": {
"multi_match": {
"query": "1",
"fields": ["title", "content"]
}
}
}

should:布尔方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /my_index/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "1"
}
},
{
"match": {
"content": "1"
}
}
]
}
}
}

范围查询

比如文档中有一个price字段,查询价格在25.0050.00的数据。

1
2
3
4
5
6
7
8
9
10
11
GET /my_index/_search
{
"query": {
"range": {
"price": {
"gte": 25,
"lte": 50
}
}
}
}

分页查询

1
2
3
4
5
GET /my_index/_search
{
"from": 0,
"size": 10
}

参数说明:

  • from:页索引,即:(页码 - 1) * 页大小。
  • size:页大小。

查询排序

比如按照价格降序

1
2
3
4
5
6
7
8
9
10
GET /my_index/_search
{
"sort": [
{
"price": {
"order": "desc"
}
}
]
}

查询总记录数

1
GET /my_index/_count

模糊查询

模糊查询有很多种方式,这里介绍两个常用的。但由于模糊查询对性能的损耗较高,通常情况下不建议模糊查询,而尽可能给予分词搜索。

  • 使用通配符进行模糊查询

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    GET /my_index/_search
    {
    "query": {
    "wildcard": {
    "content.keyword": {
    "value": "*se?rch*"
    }
    }
    }
    }

    匹配说明:

    *:表示忽略匹配的内容,也可以理解为模糊位置。

    ?:是占位符,比如*se?rch*中,serch中间有一个字符可以任意。有几个?表示有几个任意字符。

  • 使用相似度进行模糊查询

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    GET /my_index/_search
    {
    "query": {
    "fuzzy": {
    "content": {
    "value": "海量",
    "fuzziness": 1
    }
    }
    }
    }

    重要参数说明:

    • fuzziness:fuzziness 参数用于控制模糊查询的容错率。它指定了查询时能够容忍的最大编辑距离,即允许查询中的单词和目标词之间的最大差异量。其中 1 表示容忍一个字符的差异,值越大匹配度越高,但相对的查询出的数据越不精准。

分词器

Elasticsearch 安装完成后,默认只有一个分词器standard。这是一个标准分词器,它可以对英文进行很好的分词处理。但是如果使用中文查询,他会将每一个字分成一个词,这对 Elasticsearch 的损耗相当大,因此需要安装一个中文分词器来处理。

常用的分词是 ik 中文分词器。

ik 分词器有以下几种常用的分词方式:

  • ik_smart:智能分词,可以将一些较复杂的词汇进行正确地拆分。
  • ik_max_word:细粒度分词,会将所有可能的词语都进行切分,速度较慢,但精度较高。
  • ik_word:粗粒度分词,会将一些常见的词语组合在一起,速度较快,但精度较低。
  • ik_pinyin:拼音分词,将汉字转换成拼音,并进行切分。
  • ik_synonym:同义词分词,根据自定义的同义词词典进行分词。
  • ik_english:英文分词,对英文文本进行分词。

安装 IK 分词器

分词器的版本要和 Elasticsearch 的版本一致,否则无法启动。

下载插件包

  • 下载分词器包

    1
    wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.7/elasticsearch-analysis-ik-7.17.7.zip

    如果使用wget下载比较慢,也可以下载到本地电脑,然后上传到服务器。

安装分词器

  • 解压分词器包到插件目录

    这里将插件包解压到了插件目录下的ik目录,ik目录无需提前创建,解压时会自动创建。

    1
    unzip ~/elasticsearch-analysis-ik-7.17.7.zip -d ~/elasticsearch/plugins/ik/
  • 给 ik 目录授权

    1
    chmod o+xrw -R ~/elasticsearch/plugins/ik/
  • 指定 ik 目录的所属用户

    前面我们已经给插件目录设置所属用户了,由于 ik 目录是后创建的,所以需要重新设置一次。

    1
    chown 1000 -R ~/elasticsearch/plugins/ik/
  • 重新启动 Elasticsearch 集群

    1
    docker-compose -f ~/elasticsearch/elasticsearch-compose.yml restart

    重启后,可以使用watch docker ps监控一段时间,如果一切正常说明重启成功。

  • 检查分词器是否生效

    选择任意一个 Elasticsearch 节点容器进入。

    1
    docker exec -it <容器ID> /bin/bash

    成功进入容器后,使用elasticsearch-plugin命令查看当前的插件列表。

    1
    elasticsearch-plugin list

    命令执行结果如下:

    1
    2
    -- console log --
    ik

    到这里可以看到,已经安装了一个 ik 插件。

使用案例

我们可以使用 Elasticsearch de _analyze命令来分析一段话,来测试中文分词的具体效果。

1
2
3
4
5
GET _analyze
{
"analyzer": "ik_smart",
"text": "高性能的全文搜索引擎。"
}

命令执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"tokens": [
{
"token": "高性能",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
},
{
"token": "的",
"start_offset": 3,
"end_offset": 4,
"type": "CN_CHAR",
"position": 1
},
{
"token": "全文",
"start_offset": 4,
"end_offset": 6,
"type": "CN_WORD",
"position": 2
},
{
"token": "搜索引擎",
"start_offset": 6,
"end_offset": 10,
"type": "CN_WORD",
"position": 3
}
]
}

从执行结果可以看到,关键词被分成了一个完整的词,而不是一个字一个词。

如果使用默认的standard分词器,会看到中文被分成了一个字一个词。


Elasticsearch 学习笔记
https://kael.52dev.fun/2023/04/21/Elastic Search 学习笔记/
作者
Kael
发布于
2023年4月21日
许可协议
BY (KAEL)