技术分享
Elasticsearch
00 分钟
2024-4-11
2024-5-6
type
status
date
May 6, 2024 02:49 AM
slug
summary
category
tags
password
icon

ES概述

介绍

  • elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容。
  • elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域,而elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。
    • notion image

倒排索引

倒排索引的概念是基于MySQL这样的正向索引而言的。

正向索引

notion image
  • 如果是根据id查询,那么直接走索引,查询速度非常快。但如果是基于title做模糊查询,只能是逐行扫描数据,流程如下:
      1. 用户搜索数据,条件是title符合"%手机%"
      1. 逐行获取数据,比如id为1的数据
      1. 判断数据中的title是否符合用户搜索条件
      1. 如果符合则放入结果集,不符合则丢弃。回到步骤1
逐行扫描,也就是全表扫描,随着数据量增加,其查询效率也会越来越低。当数据量达到数百万时,就是一场灾难。

倒排索引

  • 倒排索引中有两个非常重要的概念:
      1. 文档Document):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息。
      1. 词条Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条。
  • 创建倒排索引是对正向索引的一种特殊处理,流程如下:
      1. 将每一个文档的数据利用算法分词,得到一个个词条。
      1. 创建表,每行数据包括词条、词条所在文档id、位置等信息。
      1. 因为词条唯一性,可以给词条创建索引,例如hash表结构索引。
notion image
  • 倒排索引的搜索流程如下(以搜索"华为手机"为例):
      1. 用户输入条件"华为手机"进行搜索。
      1. 对用户输入内容分词,得到词条:华为手机
      1. 拿着词条在倒排索引中查找,可以得到包含词条的文档id:1、2、3。
      1. 拿着文档id到正向索引中查找具体文档。
虽然要先查询倒排索引,再查询倒排索引,但是无论是词条、还是文档id都建立了索引,查询速度非常快!无需全表扫描。
notion image

正向和倒排

那么为什么一个叫做正向索引,一个叫做倒排索引呢?
  1. 正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程
  1. 倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程
是不是恰好反过来了?
那么两者方式的优缺点是什么呢?
优点
缺点
正向索引
• 可以给多个字段创建索引 • 根据索引字段搜索、排序速度非常快
根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。
倒排索引
根据词条搜索、模糊搜索时,速度非常快
• 只能给词条创建索引,而不是字段 • 无法根据字段做排序

es中的一些概念

文档和字段

elasticsearch是面向文档(Document)存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中,而Json文档中往往包含很多的字段(Field),类似于数据库中的列。
notion image

索引和映射

索引(Index),就是相同类型的文档的集合。
例如:
  • 所有用户文档,就可以组织在一起,称为用户的索引;
  • 所有商品的文档,可以组织在一起,称为商品的索引;
  • 所有订单的文档,可以组织在一起,称为订单的索引;
notion image
因此,我们可以把索引当做是数据库中的表。
数据库的表会有约束信息,用来定义表的结构、字段的名称、类型等信息。因此,索引库中就有映射(mapping),是索引中文档的字段约束信息,类似表的结构约束。

es与mysql

MySQL
Elasticsearch
说明
Table
Index
索引(index),就是文档的集合,类似数据库的表(table)
Row
Document
文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式
Column
Field
字段(Field),就是JSON文档中的字段,类似数据库中的列(Column)
Schema
Mapping
Mapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema)
SQL
DSL
DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD
是不是说,我们学习了elasticsearch就不再需要mysql了呢?并不是如此,两者各自有自己的擅长支出:
  • Mysql:擅长事务类型操作,可以确保数据的安全和一致性
  • Elasticsearch:擅长海量数据的搜索、分析、计算
因此在企业中,往往是两者结合使用:
  • 对安全性要求较高的写操作,使用mysql实现
  • 对查询性能要求较高的搜索需求,使用elasticsearch实现
  • 两者再基于某种方式,实现数据的同步,保证一致性
notion image

安装es和kibana

部署单点es

在浏览器输入:http://192.168.10.100:9200,即可看到elasticsearch的响应结果:
notion image

部署单点kibana

kibana启动一般比较慢,需要多等待一会,可以通过命令:docker logs -f kibana查看运行日志,当查看到下面的日志,说明成功:
notion image
此时,在浏览器输入地址访问:http://192.168.10.100:5601,即可看到结果。
  • kibana中提供了一个DevTools界面:这个界面中可以编写DSL来操作elasticsearch。并且对DSL语句有自动补全功能。
notion image

安装IK分词器

  • 扩展词典
      1. 打开IK分词器config目录:
        1. notion image
      1. 在IKAnalyzer.cfg.xml配置文件内容添加:
        1. 新建ext.dicstopword.dic,并在ext.dic中添加一些扩展词,在stopword.dic中添加停用词。
        1. 重启es和kibana。
          1. notion image
        💡
        【注意】:ext.dicstopword.dic文件的编码必须是 UTF-8 格式,严禁使用Windows记事本编辑。

    索引库操作

    索引库就类似数据库mapping映射就类似表的结构。我们要向es中存储数据,必须先创建“库”和“表”。

    mapping映射属性

    • mapping是对索引库中文档的约束,常见的mapping属性包括:
      • type:字段数据类型,常见的简单类型有:
        • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
        • 数值:long、integer、short、byte、double、float、
        • 布尔:boolean
        • 日期:date
        • 对象:object
      • index:是否创建索引,默认为true
      • analyzer:使用哪种分词器
      • properties:该字段的子字段
    • 示例:
      • 对应的每个字段映射(mapping):
      • age:类型为 integer;参与搜索,因此需要index为true;无需分词器
      • weight:类型为float;参与搜索,因此需要index为true;无需分词器
      • isMarried:类型为boolean;参与搜索,因此需要index为true;无需分词器
      • info:类型为字符串,需要分词,因此是text;参与搜索,因此需要index为true;分词器可以用ik_smart
      • email:类型为字符串,但是不需要分词,因此是keyword;不参与搜索,因此需要index为false;无需分词器
      • score:虽然是数组,但是我们只看元素的类型,类型为float;参与搜索,因此需要index为true;无需分词器
      • name:类型为object,需要定义多个子属性
        • name.firstName;类型为字符串,但是不需要分词,因此是keyword;参与搜索,因此需要index为true;无需分词器
        • name.lastName;类型为字符串,但是不需要分词,因此是keyword;参与搜索,因此需要index为true;无需分词器

    索引库的CRUD

    这里统一使用Kibana编写DSL的方式来演示。

    创建索引库和映射

    • 基本语法:
      • 请求方式:PUT
      • 请求路径:/索引库名,可以自定义
      • 请求参数:mapping映射
    • 格式:
      • 示例:
        • notion image

      查询索引库

      • 基本语法
        • 请求方式:GET
        • 请求路径:/索引库名
        • 请求参数:无
      • 格式GET /索引库名
      • 示例
        • notion image

      修改索引库

      倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引,这简直是灾难。因此索引库一旦创建,无法修改mapping
      虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响
      • 语法说明
        • 示例:
          • notion image

        删除索引库

        • 语法:
          • 请求方式:DELETE
          • 请求路径:/索引库名
          • 请求参数:无
        • 格式:DELETE /索引库名
        • 示例:
          • notion image

        文档操作

        新增文档

        • 语法:
          • 示例:
            • 响应:
              • notion image

            查询文档

            • 语法:GET /{索引库名称}/_doc/{id}
            • 示例GET /frank/_doc/1
            • 响应
              • notion image

            修改文档

            • 修改有两种方式:
                1. 全量修改:直接覆盖原来的文档
                1. 增量修改:修改文档中的部分字段
            全量修改
            • 全量修改是覆盖原来的文档,其本质是:
              • 根据指定的id删除文档
              • 新增一个相同id的文档
              • 💡
                注意:如果根据id删除时,id不存在,第二步的新增也会执行,也就从修改变成了新增操作了。
            • 语法:
              • 示例:
                • 响应:
                  • notion image
                增量修改
                增量修改是只修改指定id匹配的文档中的部分字段。
                • 语法:
                  • 示例
                    • 响应
                      • notion image

                    删除文档

                    • 语法:DELETE /{索引库名}/_doc/{id}
                    • 示例DELETE /frank/_doc/1
                    • 响应
                      • notion image

                    RestAPI

                    • 其中的Java Rest Client又包括两种:
                      • Java Low Level Rest Client
                      • Java High Level Rest Client(推荐)
                    • mapping映射分析
                      • 创建索引库,最关键的是mapping映射,而mapping映射要考虑的信息包括:
                        • 字段名
                        • 字段数据类型
                        • 是否参与搜索
                        • 是否需要分词
                        • 如果分词,分词器是什么?
                        其中:
                      • 字段名、字段数据类型,可以参考数据表结构的名称和类型
                      • 是否参与搜索要分析业务来判断,例如图片地址,就无需参与搜索
                      • 是否分词呢要看内容,内容如果是一个整体就无需分词,反之则要分词
                      • 分词器,我们可以统一使用ik_max_word
                      • 几个特殊字段说明:
                        • location:地理坐标,里面包含精度、纬度
                          • notion image
                        • all:一个组合字段,其目的是将多字段的值 利用copy_to合并,提供给用户搜索
                          • notion image
                    • 初始化RestClient
                        1. 引入es的RestHighLevelClient依赖
                          1. 因为SpringBoot默认的ES版本是7.6.2,所以我们需要覆盖默认的ES版本
                            1. 初始化RestHighLevelClient

                          创建索引库

                          步骤分为三步:
                          1. 创建Request对象。因为是创建索引库的操作,因此RequestCreateIndexRequest
                          1. 添加请求参数,其实就是DSLJSON参数部分。因为json字符串很长,这里是定义了静态字符串常量MAPPING_TEMPLATE,让代码看起来更加优雅。
                          1. 发送请求,client.indices()方法的返回值是IndicesClient类型,封装了所有与索引库操作有关的方法。
                          notion image

                          删除索引库

                          判断索引库是否存在

                          RestClient操作文档

                          新增文档

                          • 可以看到与创建索引库类似,同样是三步走:
                              1. 创建Request对象
                              1. 准备请求参数,也就是DSL中的JSON文档
                              1. 发送请求
                          notion image

                          查询文档

                          删除文档

                          修改文档

                          notion image

                          批量导入文档

                          • 案例需求:利用BulkRequest批量将数据库数据导入到索引库中。步骤如下:
                              1. 利用mybatis-plus查询酒店数据
                              1. 将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)
                              1. 利用JavaRestClient中的BulkRequest批处理,实现批量新增文档
                          notion image

                          评论
                          Loading...