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
Database7.X版本前有Type,对比数据库中的表,新版取消了
TableIndex
RowDocument
ColumnField

分片、副本、元数据

  • 分片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会利用倒排索引来快速查找包含查询标记的文档,并计算相关性得分。
  • 常见的分词器,如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 表达的查询时使用的类,例如在构建查询和使用聚合的场景

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提供了多种集群发现机制,如多播发现、单播发现、云发现等。
  • 查看节点角色
    • 集群中有多个节点角色的时候,就需要手动设定、配置节点的角色
    • 不手动设置节点角色,默认节点角色如下所示
    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
        
  • 总结
    • 一个节点可以充当一个或多个角色,默认三个角色都有
    • 每种节点类型都有不同的功能和用途在生产环境中,通常的配置是将这些节点类型组合使用,实现高可用性和高性能
    • 建议
      • 小规模集群不需严格区分角色;
      • 大规模集群则可以分开角色,并发量大可以增加独立协调节点和数据节点,提升处理能力
      • 节点的数量和规模取决于数据量、性能需求和可用资源等因素
      • 一个典型的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 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的发行说明和文档,了解新版本的特性和已知问题,并根据实际需求选择合适的版本。
  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 安装Java Elasticsearch是基于Java开发的,因此需要先安装Java。 使用以下命令安装Java: ``` sudo apt-get install openjdk-8-jdk ``` 2. 下载Elasticsearch 可以从Elasticsearch官网下载最新版本的Elasticsearch。 使用以下命令下载Elasticsearch: ``` wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.9.3-linux-x86_64.tar.gz ``` 3. 解压缩Elasticsearch 使用以下命令解压缩Elasticsearch: ``` tar -zxvf elasticsearch-7.9.3-linux-x86_64.tar.gz ``` 4. 启动Elasticsearch 进入Elasticsearch目录,使用以下命令启动Elasticsearch: ``` cd elasticsearch-7.9.3/bin ./elasticsearch ``` 5. 访问Elasticsearch 使用浏览器访问以下URL来验证Elasticsearch是否正常运行: ``` http://localhost:9200/ ``` 6. 配置Elasticsearch 可以在Elasticsearch的配置文件中进行配置。 默认配置文件位于Elasticsearch目录下的`config/elasticsearch.yml`。 可以使用以下命令编辑配置文件: ``` sudo nano config/elasticsearch.yml ``` 在配置文件中可以修改以下参数: - cluster.name:指定集群的名称。 - node.name:指定节点的名称。 - network.host:指定节点监听的IP地址。 - http.port:指定节点监听的端口。 修改完配置文件后,需要重新启动Elasticsearch才能生效。 7. 安装Elasticsearch插件 Elasticsearch提供了很多插件,可以根据需要安装。 使用以下命令安装Elasticsearch-head插件: ``` ./elasticsearch-plugin install mobz/elasticsearch-head ``` 安装完成后,可以使用以下URL来访问Elasticsearch-head插件: ``` http://localhost:9200/_plugin/head/ ``` 8. 管理Elasticsearch 可以使用以下命令来管理Elasticsearch: - 启动Elasticsearch:`./elasticsearch` - 停止Elasticsearch:`./elasticsearch -d` - 查看Elasticsearch进程:`ps -ef | grep elasticsearch` - 查看Elasticsearch日志:`tail -f logs/elasticsearch.log`

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值