当前位置:   article > 正文

Elasticsearch的作用以及整合springboot_elasticsearchrepository注解式开发聚合

elasticsearchrepository注解式开发聚合

目录

1.初识elasticsearch

1.1.了解ES

1.1.1.elasticsearch的作用

1.1.2.ELK技术栈

ELK技术栈简介

Elasticsearch能实现什么

Elasticsearch特点

1.1.3.elasticsearch和lucene

1.1.5.总结

1.2.倒排索引

1.2.1.正向索引

1.2.2.倒排索引

1.2.3.正向和倒排

1.3.es的一些概念

1.3.1.文档和字段

1.3.2.索引和映射

1.3.3.mysql与elasticsearch

1.4.1.安装

1.4.2.分词器

1.4.3.总结

常用Elasticsearch管理操作

1. 查看健康状态

1.1 健康状态含义说明

2. 查看节点信息

3. 查看Elasticsearch中的全部索引

2.索引库操作

2.1.DSL操作ES-RESTful风格

2.2.DSL操作索引库

2.2.1 PUT 添加索引

2.2.2 GET 查询索引

2.2.3 DELETE 删除索引

2.2.4 POST 打开/关闭索引库

2.3.DSL操作映射

2.3.1.mapping映射属性

Elasticsearch中的数据类型

2.3.2创建索引库并设置映射

语法格式

举例

2.3.3查询索引库映射

语法格式

举例

2.3.4增加映射字段

语法格式

举例

2.4.DSL操作文档

2.4.1 添加文档

2.4.1.1指定id

语法格式

举例

2.4.1.2 不指定id

语法格式

举例

2.4.2 查询文档

2.4.2.1 查询单个

2.4.2.2 查询全部

2.4.3 修改文档

语法格式

举例

2.4.4 删除文档

语法格式

举例

2.5.ES高级查询 DSL

测试数据

2.5.1.查询所有(match_all)

2.5.2.关键词查询(term)

2.5.3.多关键词查询(terms)

2.5.4.范围查询(range)

2.5.5.前缀查询(prefix)

2.5.6.通配符与正则表达式查询(wildcard/regexp)

2.5.7.多id查询(ids)

2.5.8.模糊查询(fuzzy)

2.5.9.布尔查询(bool) 重要!!!!!

2.5.10.match匹配查询 重要!!!!

2.5.11.multi_match query 多字段匹配查询

2.5.12.match_phrase query短语搜索

2.5.13.query_string query

2.5.14.simple_query_string

2.5.15.查询是否包含某个字段(exists)

2.5.16.高亮

2.5.17.指定返回条数(size)

2.5.18.分页查询(from)

2.5.19.指定字段排序(sort)

2.5.20.指定返回字段(_source)

更多的查询命令:

ES官网点击直达

2.6.聚合查询(Aggregation aggs)

2.6.1.根据某个字段分组

2.6.2.求最大值/最小值/平均值

SpringBoot整合ES

一、基本概念

ElasticsearchTemplate

QueryBuilders、NativeSearchQuery

@Document 和 @Field 注解

@Field中提到的FieldType 枚举

实体类

Mapper接口

索引库操作

创建索引及映射

删除索引

判断索引是否存在

文档操作

添加数据

根据ID查询

查询全部

高亮查询

分页查询

排序

时间范围

同字段多条件匹配查询(or)

boostingQuery

constantScoreQuery


1.初识elasticsearch

1.1.了解ES

1.1.1.elasticsearch的作用

elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容

例如:

在GitHub搜索代码

在电商网站搜索商品

在百度搜索答案

1.1.2.ELK技术栈

ELK技术栈简介

ELK其实并不是一款软件,而是一整套解决方案,是三个软件产品的首字母缩写,Elasticsearch,Logstash 和 Kibana。这三款软件都是开源软件,通常是配合使用,而且又先后归于 Elastic.co 公司名下,故被简称为ELK技术栈。

  • Elasticsearch:Elasticsearch是一个实时的分布式搜索和分析引擎,它可以用于全文搜索,结构化搜索以及分析。它是一个建立在全文搜索引擎Apache Lucene基础上的搜索引擎,使用Java语言编写。

  • Kibana(发音为/kiːˈbɑːnə/):Kibana是一个免费且开放的用户界面,能够让您对Elasticsearch数据进行可视化。Kibana是一款基于Apache开源协议的可视化Web管理平台。它可以在Elasticsearch的索引中查找,交互数据,并生成各种维度的表图。

  • Logstash:Logstash 是具有实时流水线能力的开源的数据收集引擎,能够从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。使用JRuby语言编写。其作者是世界著名的运维工程师乔丹西塞 (JordanSissel)

Elasticsearch能实现什么
  • 分布式的搜索引擎 分布式:Elasticsearch自动将海量数据分散到多台服务器上去存储和检索 搜索:百度、谷歌,站内搜索

  • 全文检索 提供模糊搜索等自动度很高的查询方式,并进行相关性排名,高亮等功能

  • 数据分析引擎(分组聚合) 电商网站,最近一周笔记本电脑这种商品销量排名top10的商家有哪些?新闻网站,最近1个月访 问量排名top3的新闻板块是哪些

  • 对海量数据进行近实时的处理 海量数据的处理:因为是分布式架构,Elasticsearch可以采用大量的服务器去存储和检索数据,自 然而然就可以实现海量数据的处理 近实时:Elasticsearch可以实现秒级别的数据搜索和分析

Elasticsearch特点
  • 安装方便:

  • 没有其他依赖,下载后安装非常方便;只用修改几个参数就可以搭建起来一个集群

    JSON:输入/输出格式为 JSON,快捷方便

  • RESTful:基本所有操作 ( 索引、查询、甚至是配置 ) 都可以通过 HTTP 接口进行

  • 分布式:节点对外表现对等(每个节点都可以用来做入口) 加入节点自动负载均衡

  • 多租户:

    可根据不同的用途分索引,可以同时操作多个索引,支持超大数据: 可以扩展到 PB 级(数据量超出万亿级别的信息)的结构化和非结构化数据 海量数据的近实时处理

1.1.3.elasticsearch和lucene

elasticsearch底层是基于lucene来实现的。

Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目,由DougCutting于1999年研发。官网地址:Apache Lucene - Welcome to Apache Lucene

elasticsearch的发展历史:

  • 2004年Shay Banon基于Lucene开发了Compass

  • 2010年Shay Banon 重写了Compass,取名为Elasticsearch。

1.1.5.总结

什么是elasticsearch?

  • 一个开源的分布式搜索引擎,可以用来实现搜索、日志统计、分析、系统监控等功能

什么是elastic stack(ELK)?

  • 是以elasticsearch为核心的技术栈,包括Logstash、kibana、elasticsearch

什么是Lucene?

  • 是Apache的开源搜索引擎类库,提供了搜索引擎的核心API

1.2.倒排索引

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

1.2.1.正向索引

那么什么是正向索引呢?例如给下表(tb_goods)中的id创建索引:

如果是根据id查询,那么直接走索引,查询速度非常快。

但如果是基于title做模糊查询,只能是逐行扫描数据,流程如下:

1)用户搜索数据,条件是title符合"%手机%"

2)逐行获取数据,比如id为1的数据

3)判断数据中的title是否符合用户搜索条件

4)如果符合则放入结果集,不符合则丢弃。回到步骤1

逐行扫描,也就是全表扫描,随着数据量增加,其查询效率也会越来越低。当数据量达到数百万时,就是一场灾难。

1.2.2.倒排索引

倒排索引中有两个非常重要的概念:

  • 文档(Document):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息

  • 词条(Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条

创建倒排索引是对正向索引的一种特殊处理,流程如下:

  • 将每一个文档的数据利用算法分词,得到一个个词条

  • 创建表,每行数据包括词条、词条所在文档id、位置等信息

  • 因为词条唯一性,可以给词条创建索引,例如hash表结构索引

如图:

倒排索引的搜索流程如下(以搜索"华为手机"为例):

1)用户输入条件"华为手机"进行搜索。

2)对用户输入内容分词,得到词条:华为手机

3)拿着词条在倒排索引中查找,可以得到包含词条的文档id:1、2、3。

4)拿着文档id到正向索引中查找具体文档。

如图:

虽然要先查询倒排索引,再查询正向索引,但是无论是词条、还是文档id都建立了索引,查询速度非常快!无需全表扫描。

1.2.3.正向和倒排

那么为什么一个叫做正向索引,一个叫做倒排索引呢?

  • 正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程

  • 倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程

是不是恰好反过来了?

那么两者方式的优缺点是什么呢?

正向索引

  • 优点:

    • 可以给多个字段创建索引

    • 根据索引字段搜索、排序速度非常快

  • 缺点:

    • 根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。

倒排索引

  • 优点:

    • 根据词条搜索、模糊搜索时,速度非常快

  • 缺点:

    • 只能给词条创建索引,而不是字段

    • 无法根据字段做排序

1.3.es的一些概念

elasticsearch中有很多独有的概念,与mysql中略有差别,但也有相似之处。

1.3.1.文档和字段

elasticsearch是面向文档(Document)存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中:

而Json文档中往往包含很多的字段(Field),类似于数据库中的列。

1.3.2.索引和映射

索引(Index),就是相同类型的文档的集合。

例如:

  • 所有用户文档,就可以组织在一起,称为用户的索引;

  • 所有商品的文档,可以组织在一起,称为商品的索引;

  • 所有订单的文档,可以组织在一起,称为订单的索引;

因此,我们可以把索引当做是数据库中的表。

数据库的表会有约束信息,用来定义表的结构、字段的名称、类型等信息。因此,索引库中就有映射(mapping),是索引中文档的字段约束信息,类似表的结构约束。

1.3.3.mysql与elasticsearch

我们统一的把mysql与elasticsearch的概念做一下对比:

MySQLElasticsearch说明
TableIndex索引(index),就是文档的集合,类似数据库的表(table)
RowDocument文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式
ColumnField字段(Field),就是JSON文档中的字段,类似数据库中的列(Column)
SchemaMappingMapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema)
SQLDSLDSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD

是不是说,我们学习了elasticsearch就不再需要mysql了呢?

并不是如此,两者各自有自己的擅长支出:

  • Mysql:擅长事务类型操作,可以确保数据的安全和一致性

  • Elasticsearch:擅长海量数据的搜索、分析、计算

因此在企业中,往往是两者结合使用:

  • 对安全性要求较高的写操作,使用mysql实现

  • 对查询性能要求较高的搜索需求,使用elasticsearch实现

  • 两者再基于某种方式,实现数据的同步,保证一致性

1.4.1.安装

 请参考:ES的安装以及使用-CSDN博客

1.4.2.分词器

 请参考:ES的安装以及使用-CSDN博客

1.4.3.总结

  1. "我爱你中国"为例, 默认的分词器会直接分为 "我" "爱" "你" "中" "国"
  2. IK分词器 ik_smart算法
  3. ik_smart算法会将"我爱你中国"分为 "我爱你" "中国"
  4. IK分词器ik_max_word算法
  5. ik_max_word算法会将"我爱你中国"分为 "我爱你" "爱你" "中国"
  6. // 查看分词器 默认方式 直接复制到控制台执行查看结果
  7. POST /_analyze
  8. {
  9. "text": "我爱你中国"
  10. }
  11. // 查看分词器 智能切分 直接复制到控制台执行查看结果
  12. POST /_analyze
  13. {
  14. "tokenizer": "ik_smart",
  15. "text": "我爱你中国"
  16. }
  17. // 查看分词器 最细切分 直接复制到控制台执行查看结果
  18. POST /_analyze
  19. {
  20. "tokenizer": "ik_max_word",
  21. "text": "我爱你中国"
  22. }

分词器的作用是什么?

  • 创建倒排索引时对文档分词

  • 用户搜索时,对输入的内容分词

IK分词器有几种模式?

  • ik_smart:智能切分,粗粒度

  • ik_max_word:最细切分,细粒度

IK分词器如何拓展词条?如何停用词条?

  • 利用config目录的IkAnalyzer.cfg.xml文件添加拓展词典和停用词典

  • 在词典中添加拓展词条或者停用词条

常用Elasticsearch管理操作

1. 查看健康状态

命令:其中v代表参数,表示返回的结果包含标题头。

GET /_cat/health?v

结果含义如下:

含义表头数据
编号epoch1640140938
时间戳timestamp02:42:18
集群名称clusterdocker-cluster
健康状态statusgreen
节点总数node.total1
数据节点数node.data1
总分片数shards5
主分片数量pri5
备份分片数量relo0
正在初始化的分片init0
未分配的分片unassign0
正在等待执行的任务pending_tasks0
挂起任务的等待时间max_task_wait_time-
活动的分片的占有百分比active_shards_percent100.0%
1.1 健康状态含义说明

status值包括:green、yellow、red

  • green:每个索引的primary shard和replica shard都是active的。

  • yellow:每个索引的primary shard都是active的,但部分的replica shard不是active的。

  • red:不是所有的索引的primary shard都是active状态的。

2. 查看节点信息

命令:其中v代表参数,表示返回的结果包含标题头。

GET /_cat/nodes?v

结果含义如下:

含义表头数据
ES主机地址ip172.17.0.5
堆占用率heap.percent13
内存占用率ram.percent96
CPU占用率cpu2
每分钟平均运行命令load_1m0.46
每5分钟平均运行命令load_5m0.21
每15分钟平均运行命令load_15m0.20
ES节点权限node.roledilm
是否是主节点master*
ES节点名称namedd99a098c1f0

3. 查看Elasticsearch中的全部索引

命令:

GET /_cat/indices?v

结果含义如下:

含义表头数据
健康状态healthgreen
索引是否可用statusopen
索引名称index.kibana_1
索引唯一键uuid3opvkLJPQdaDCYuEBGZFRA
主分片数量pri1
副本分片数量rep0
索引中文档总数docs.count16
索引中已删除文档数docs.deleted0
索引总计占用空间store.size23kb
索引主分片占用空间pri.store.size23kb

2.索引库操作

索引库就类似数据库表,mapping映射就类似表的结构。

我们要向es中存储数据,必须先创建“库”和“表”。

2.1.DSL操作ES-RESTful风格

2.2.DSL操作索引库

  1. # 新增索引库语法
  2. PUT 索引库名
  3. # 查询索引库
  4. GET 索引库名
  5. # 删除索引库
  6. DELETE 索引库名
  7. # 关闭索引库(注意:关闭索引库不能更改数据)
  8. POST 索引库名/_close
  9. # 开放索引库
  10. POST 索引库名/_open
  11. # settings 参数
  12. 1.number_of_shards:分片数量,类似于数据库里面分库分表,一经定义不可更改。主要响应写操作
  13. 2.number_of_replicas:副本数,用于备份分片的,和分片里面的数据保持一致,主要响应读操作,副本越多读取就越快。
  14. 3.分布式索引一定要注意分片数量不能更改,所以在创建的时候一定要预先估算好数据大小,一般在8CPU16G的机器上一个分片不要超过300g。索引会根据分片的配置来均匀的响应用户请求
  15. 4.如果调整了分片数那就要重建索引。
  16. 如下:
  17. PUT /test
  18. {
  19. "settings" : {
  20. "number_of_shards" : 1, //分片
  21. "number_of_replicas" : 1 //分片副本
  22. }
  23. }

2.2.1 PUT 添加索引

  1. 添加索引
  2. PUT index

2.2.2 GET 查询索引

  1. 查询索引
  2. GET index

2.2.3 DELETE 删除索引

  1. 删除索引
  2. DELETE index

删除之后再看的话就是404

2.2.4 POST 打开/关闭索引库

  1. 关闭索引库
  2. POST index/_close

注:当索引进入关闭状态,是不能添加文档的

  1. 打开索引库
  2. POST index/_open

2.3.DSL操作映射

ES 中的 Mapping 相当于传统数据库中的表定义,它有以下作用:

  • 定义索引中的字段的名字。

  • 定义索引中的字段的类型,比如字符串,数字等。

  • 定义索引中的字段是否建立倒排索引。

一个 Mapping 是针对一个索引中的 Type 定义的:

  • ES 中的文档都存储在索引的 Type 中

  • ES 7.0 之前,一个索引可以有多个 Type,所以一个索引可拥有多个 Mapping

  • ES 7.0 之后,一个索引只能有一个 Type,所以一个索引只对应一个 Mapping

通过下面语法可以获取一个索引的 Mapping 信息:

GET index/_mapping

2.3.1.mapping映射属性

Mapping在Elasticsearch中是非常重要的一个概念。决定了一个index中的field使用什么数据格式存储,使用什么分词器解析,是否有子字段等。

一旦映射已确定,不可修改。field数据格式不可变,选择的分词器不可变,是否创建索引不可变。可以新增新的field映射。

mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:

    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)

    • 数值:long、integer、short、byte、double、float、

    • 布尔:boolean

    • 日期:date

    • 对象:object

  • index:是否创建索引,默认为true

  • analyzer:使用哪种分词器

  • properties:该字段的子字段

Elasticsearch中的数据类型

Elasticsearch中的数据类型有很多,在这里只介绍常用的数据类型。只有text类型才能被分词。其他类型不能分词。

字符串-text:可以分词,不支持聚合(统计)

分词的数据,内容较为复杂,统计没有意义

 字符串-keyword:不会分词,将全部内容作为一个词条,支持聚合(统计)

例如:有个文档(相当于数据库一条数据),其中一个字段的值是华为手机
text: 华为、手机
keyword: 华为手机

类型类型名称
文本(字符串)text
整数byte、short、integer、long
浮点型float、double
布尔类型boolean
日期类型date
数组类型array {a:[]}
对象类型object {a:{}}
不分词的字符串(关键字)keyword
地理位置坐标值geo_point

例如下面的json文档

{
    "age": 19,
    "weight": 52.1,
    "isMarried": false,
    "info": "Java讲师",
    "email": "1234567@qq.com",
    "score": [99.1, 99.5, 98.9],
    "name": {
        "firstName": "弈",
        "lastName": "星"
    }
}

对应的每个字段映射(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;无需分词器

2.3.2创建索引库并设置映射

语法格式

# 创建索引库并设置映射语法
PUT person
{
 "mappings": {
   "properties": {
     "属性名":{
       "type": "数据类型"
     },
     ...
   }
 }
}

举例
  1. #创建索引库并且设置映射(创建person索引库,映射两个字段name、age)
  2. PUT person
  3. {
  4. "mappings": {
  5. "properties": {
  6. "name":{
  7. "type": "text"
  8. },
  9. "age":{
  10. "type": "integer"
  11. }
  12. }
  13. }
  14. }

2.3.3查询索引库映射

语法格式
  1. # 查询索引库映射语法
  2. GET 索引库名/_mapping
举例
  1. # 查询索引库映射
  2. GET person/_mapping

2.3.4增加映射字段

语法格式
  1. # 增加映射字段语法
  2. PUT 索引库名/_mapping
  3. {
  4. "properties": {
  5. "新增属性名":{
  6. "type": "数据类型"
  7. }
  8. }
  9. }
举例
  1. #增加映射字段
  2. PUT person/_mapping
  3. {
  4. "properties":{
  5. "sex":{
  6. "type":"keyword"
  7. }
  8. }
  9. }

注意:ES不能单独修改映射字段名称或类型,不能单独删除某个字段,如果需要修改,直接删除整个索引库再重建

2.4.DSL操作文档

2.4.1 添加文档

2.4.1.1指定id
语法格式
  1. # 添加文档,指定id
  2. POST 索引库名/_doc/指定id
  3. {
  4. "属性名":属性值,
  5. ...
  6. }
举例
  1. POST person/_doc/1
  2. {
  3. "name":"张三",
  4. "age":18,
  5. "sex":"男"
  6. }

2.4.1.2 不指定id
语法格式
  1. # 添加文档,不指定id
  2. POST 索引库名/_doc
  3. {
  4. "属性名":属性值,
  5. ...
  6. }
举例
  1. POST person/_doc
  2. {
  3. "name":"翠花",
  4. "age":20,
  5. "sex":"女"
  6. }

2.4.2 查询文档

2.4.2.1 查询单个
  1. # 查询单个
  2. GET person/_doc/1

2.4.2.2 查询全部
  1. # 查询全部
  2. GET person/_search

2.4.3 修改文档

语法格式
  1. # 修改一条文档数据
  2. PUT 索引库名/_doc/指定id
  3. {
  4. "属性名":属性值,
  5. ...
  6. }
举例
  1. # 修改一条文档数据
  2. PUT person/_doc/1
  3. {
  4. "name":"如花",
  5. "age":20,
  6. "sex":"女"
  7. }

  1. # 再次查看
  2. GET person/_doc/1

2.4.4 删除文档

语法格式
  1. # 删除一条文档数据
  2. DELETE 索引库名/_doc/指定id
举例
  1. #删除一条文档数据
  2. DELETE person/_doc/1

  1. # 删除之后再查看
  2. GET person/_doc/1

2.5.ES高级查询 DSL

*①keyword一般用于关键字/词;text存储一段文本。本质区别是text会分词,keyword不会分词;*

*②所有类型中只有text类型会分词,其余都不分词;*

*③默认情况ES使用标准分词器。其分词逻辑为:中文单字分词、英文单词分词。*

DSL由叶子查询子句和复合查询子句两种子句组成。

测试数据

  1. // 为了便于后续测试创建如下索引
  2. PUT products
  3. {
  4. "settings":{
  5. "number_of_shards": 1,
  6. "number_of_replicas": 0
  7. },
  8. "mappings":{
  9. "properties": {
  10. "id":{
  11. "type":"integer"
  12. },
  13. "title":{
  14. "type":"keyword"
  15. },
  16. "price":{
  17. "type":"double"
  18. },
  19. "createtime":{
  20. "type":"date"
  21. },
  22. "description":{
  23. "type":"text"
  24. }
  25. }
  26. }
  27. }
  28. // 注:discription字段以下形式即为指定分词器
  29. "description":{
  30. "type":"text",
  31. "analyzer": "ik_max_word"
  32. }
  33. // 并插入如下数据
  34. POST /products/_doc/1
  35. {
  36. "id":1,
  37. "title":"小浣熊",
  38. "price":0.5,
  39. "createtime":"2022-11-11",
  40. "description":"小浣熊很好吃!!"
  41. }
  42. POST /products/_doc/2
  43. {
  44. "id":2,
  45. "title":"唐僧肉",
  46. "price":1.0,
  47. "createtime":"2022-11-11",
  48. "description":"唐僧肉真不错!!很好吃!!"
  49. }
  50. POST /products/_doc/8
  51. {
  52. "id":8,
  53. "title":"大辣片",
  54. "price":1.0,
  55. "createtime":"2022-11-11",
  56. "description":"大辣片好好吃!!很好吃!!"
  57. }
  58. POST /products/_doc/
  59. {
  60. "title":"大鸡腿",
  61. "price":10,
  62. "createtime":"2022-11-11",
  63. "description":"good chicken"
  64. }
  65. POST /products/_doc/
  66. {
  67. "title":"豌豆",
  68. "price":1.5,
  69. "createtime":"2022-11-11",
  70. "description":"豌豆很好吃!!"
  71. }
  72. POST /products/_doc/
  73. {
  74. "title":"鱼豆腐",
  75. "price":3.5,
  76. "createtime":"2022-11-11",
  77. "description":"鱼豆腐nice!!很好吃!!"
  78. }

2.5.1.查询所有(match_all)

match_all关键字:返回索引中的全部文档。

  1. GET /products/_search
  2. {
  3. "query":{
  4. "match_all": {}
  5. }
  6. }
  7. 注:既然是match_all后面肯定不需要限定任何条件了;但是为了满足json格式所以这里要加个"{}"

Boot中操作

QueryBuilders.matchAllQuery();

2.5.2.关键词查询(term)

重复三遍:文本匹配不要用term!文本匹配不要用term!文本匹配不要用term!(要用match)

term关键词:用来使用关键词查询。

①term搜索映射中的keyword类型应当使用全部内容搜索(如“大辣片”);

②text类型默认ES使用标准分词器;其分词逻辑为 对英文单词分词、对中文单字分词。

  1. #keyword搜索完整关键词是能够搜到的
  2. GET /products/_search
  3. {
  4. "query":{
  5. "term": {
  6. "title": "鱼豆腐"
  7. }
  8. }
  9. }
  10. 注:上述描述json格式的K-V都可以换成如下。
  11. "title":{
  12. "value":"鱼豆腐"
  13. }
  14. #默认分词器下text搜索完整内容也是搜不到的
  15. GET /products/_search
  16. {
  17. "query":{
  18. "term": {
  19. "description": "豌豆很好吃!!"
  20. }
  21. }
  22. }
  23. #默认分词器下text搜索单个汉字是能搜到的
  24. GET /products/_search
  25. {
  26. "query":{
  27. "term": {
  28. "description": "好"
  29. }
  30. }
  31. }
  32. #默认分词器下text搜索单个英文单词也是能搜到的
  33. GET /products/_search
  34. {
  35. "query":{
  36. "term": {
  37. "description": "nice"
  38. }
  39. }
  40. }

 Boot中操作

QueryBuilders.termQuery("字段名", "值");

2.5.3.多关键词查询(terms)

terms关键词:用于某个关键词匹配多个值的查询。和 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配。

  1. GET /products/_search
  2. {
  3. "query":{
  4. "terms": {
  5. "title": [
  6. "大鸡腿",
  7. "大辣片"
  8. ]
  9. }
  10. }
  11. }

 Boot中操作

QueryBuilders.termsQuery("字段名", "值1", "值2");

2.5.4.范围查询(range)

range关键字:用来指定查询范围内的文档

  1. #查询加个范围
  2. GET /products/_search
  3. {
  4. "query":
  5. {
  6. "range": {
  7. "price": {
  8. "gte": 5,
  9. "lte": 10
  10. }
  11. }
  12. }
  13. }

 Boot中操作

QueryBuilders.rangeQuery("范围搜索字段").gte("2020-01-09").lte("2020-01-09");

2.5.5.前缀查询(prefix)

prefix关键字:用来检索含有指定前缀的关键词的相关文档。

  1. #针对keyword类型是可以前缀查询到的
  2. GET /products/_search
  3. {
  4. "query":{
  5. "prefix": {
  6. "title": {
  7. "value": "小浣"
  8. }
  9. }
  10. }
  11. }
  12. #针对text类型如果是英文的话也是可以前缀查到的
  13. GET /products/_search
  14. {
  15. "query":{
  16. "prefix": {
  17. "description": {
  18. "value": "goo"
  19. }
  20. }
  21. }
  22. }

 Boot中操作

QueryBuilders.prefixQuery("字段名","值")

2.5.6.通配符与正则表达式查询(wildcard/regexp)

wildcard 和 regexp 查询的工作方式与 prefix 查询完全一样,它们也需要扫描倒排索引中的词列表才能找到所有匹配的词,然后依次获取每个词相关的文档 ID ,与 prefix 查询的唯一不同是:它们能支持更为复杂的匹配模式。

wildcard关键字:通配符查询。 ?用来匹配一个任意字符 *用来匹配多个任意字符。

  1. #对于text类型。这样是能查到的
  2. GET /products/_search
  3. {
  4. "query":{
  5. "wildcard": {
  6. "description": {
  7. "value": "goo?"
  8. }
  9. }
  10. }
  11. }
  12. #这样是查不到的
  13. GET /products/_search
  14. {
  15. "query":{
  16. "wildcard": {
  17. "description": {
  18. "value": "go?"
  19. }
  20. }
  21. }
  22. }
  23. 注:因为good是description字段的一个分词。

Boot中操作

  1. QueryBuilders.wildcardQuery("字段名", "值*");
  2. QueryBuilders.regexpQuery("字段名", "值");

2.5.7.多id查询(ids)

ids关键字:值为数组类型,用来根据一组id获取多个对应的文档。

注:这里相当于指定字段就是docid,感觉用的不是很多了吧

  1. #注:这里就是限定死查询某些docid的数据,只能是docid。
  2. GET /products/_search
  3. {
  4. "query": {
  5. "ids": {
  6. "values":["1","8"]
  7. }
  8. }
  9. }

 Boot中操作

QueryBuilders.idsQuery().addIds("id1","id2",...)

2.5.8.模糊查询(fuzzy)

fuzzy关键字:用来模糊查询含有指定关键字的文档。

注意:fuzzy模糊 最大模糊错误必须在0~2之间

①搜索关键词长度为2不允许存在模糊 ②搜索关键词长度为3~5允许一次模糊 ③搜索关键词长度大于5最大2次模糊

  1. #这样是可以查询到title为“小浣熊”的数据的
  2. GET /products/_search
  3. {
  4. "query": {
  5. "fuzzy": {
  6. "title":"小浣猫"
  7. }
  8. }
  9. }

 Boot中操作

QueryBuilders.fuzzyQuery("字段名", "值"); 

2.5.9.布尔查询(bool) 重要!!!!!

bool关键字:用来组合多个条件实现复杂查询,*相当于逻辑操作*。bool查询可以嵌套组合任意其他类型的查询,甚至继续嵌套bool查询也是可以的

实际语法为:bool下面套filter/must/should/must_not实现逻辑效果(bool包含四种子句)。

①must:相当于&& 要求同时成立; ②should:1)相当于逻辑或的关系; 2)影响评分机制,会把匹配的更多的文档评分提高。 ③must_not:相当于! 取非(逻辑非); ④filter: 可以将上述term、range等诸多条件都放在filter里面

注:filter可以放到bool条件下面,同样bool条件也可以放在filter下面。

  1. #must 同时满足条件
  2. GET /products/_search
  3. {
  4. "query": {
  5. "bool": {
  6. "must": [
  7. {
  8. "term":{"title":"小浣熊"}
  9. },
  10. {
  11. "range": {
  12. "price": {
  13. "gte": 10,
  14. "lte": 20
  15. }
  16. }
  17. }
  18. ]
  19. }
  20. }
  21. }
  22. #should 满足一个条件即可
  23. GET /products/_search
  24. {
  25. "query": {
  26. "bool": {
  27. "should": [
  28. {
  29. "term":{"title":"小浣熊"}
  30. },
  31. {
  32. "range": {
  33. "price": {
  34. "gte": 10,
  35. "lte": 20
  36. }
  37. }
  38. }
  39. ]
  40. }
  41. }
  42. }
  43. #查询 msg_content 字段不为空的消息
  44. GET es_qidian_msg_202401/_search
  45. {
  46. "size":100,
  47. "query":{
  48. "bool":{
  49. "must_not":[
  50. {
  51. "term":{
  52. "msg_content":""
  53. }
  54. }
  55. ]
  56. }
  57. }
  58. }
  59. #进一步组合也都是可以的
  60. GET /products/_search
  61. {
  62. "bool": {
  63. "filter":[
  64. {"term":{"key1":value}}
  65. {"range":{"key2":{"gt":value1,"lt":value2}}}
  66. ]
  67. "must": { "term": { }},
  68. "must_not": { "term": { }},
  69. "should":
  70. [
  71. { "term": { }},
  72. { "term": { }}
  73. ]
  74. }
  75. }
  76. 注:must可以是数组,即[];也可以不是数组,即{}.

2.5.10.match匹配查询 重要!!!!

match:不仅会显示精确匹配的结果也会显示相似匹配的结果,非常强大。

原理:query可以输入关键词也可以输入一段文本。它会根据你实际查询的字段的类型决定是否对query内容进行分词。①如果你查询的字段是分词的,它就会对你query的内容进行分词然后再去搜。②如果该字段是不分词的就将查询条件作为整体进行查询。

match支持以下参数:

  • query : 指定匹配的值

  • operator : 匹配条件类型

  • and : 条件分词后都要匹配

  • or : 条件分词后有一个匹配即可(默认)

  • minmum_should_match : 最低匹配度,即条件在倒排索引中最低的匹配度,

    可以使用百分比或固定数字。百分比代表query搜索条件中词条百分比,如果无法整除,向下匹配(如,query条件有3个单词,如果使用百分比提供精准度计算,那么是无法除尽的,如果需要至少匹配两个单词,则需要用67%来进行描述。如果使用66%描述,ES则认为匹配一个单词即可。)。固定数字代表query搜索条件中的词条,至少需要匹配多少个。

  1. #其本质是拿‘浣’去搜,现在就能匹配到数据;然后再拿‘猫’去搜。
  2. GET /products/_search
  3. {
  4. "query": {
  5. "match": {
  6. "description": "浣猫"
  7. }
  8. }
  9. }
  10. # 如果需要同时包含 “浣” 和 “猫”, 默认是or
  11. GET /products/_search
  12. {
  13. "query": {
  14. "match": {
  15. "description": "浣 猫",
  16. "operator": "and"
  17. }
  18. }
  19. }

2.5.11.multi_match query 多字段匹配查询

多字段查询:可以根据字段类型,决定是否使用分词查询,得分最高的在前面 注意:字段类型分词,将查询条件分词之后进行查询,如果该字段不分词就会将查询条件作为整体进行查询。

  1. # description 或 title 中包含‘浣熊’
  2. POST /products/_search
  3. {
  4. "query":{
  5. "multi_match":{
  6. "query":"浣熊",
  7. "fields":["description","title"]
  8. }
  9. }
  10. }

2.5.12.match_phrase query短语搜索

短语搜索(match phrase)会对搜索文本进行文本分析,然后到索引中寻找搜索的每个分词并要求分词相邻,你可以通过调整slop参数设置分词出现的最大间隔距离。match_phrase 会将检索关键词分词。

2.5.13.query_string query

允许我们在单个查询字符串中指定AND | OR | NOT条件,同时也和 multi_match query 一样,支持多字段搜索。和match类似,但是match需要指定字段名,query_string是在所有字段中搜索,范围更广泛。 注意: 查询字段分词就将查询条件分词查询,查询字段不分词将查询条件不分词查询

2.5.14.simple_query_string

类似Query String,但是会忽略错误的语法,同时只支持部分查询语法,不支持AND OR NOT,会当作字符串处理。支持部分逻辑:

  • “+” 替代 “AND”

  • “|” 替代 “OR”

  • “-” 替代 “NOT”

2.5.15.查询是否包含某个字段(exists)

exists 过滤可以用于查找文档中是否包含指定字段或没有某个字段

  1. #查询包含“id”字段的数据
  2. GET /products/_search
  3. {
  4. "query": {
  5. "exists": {"field":"id"}
  6. }
  7. }

 Boot中操作

ExistsQueryBuilder existsQueryBuilder = QueryBuilders.existsQuery("字段");

2.5.16.高亮

什么是高亮显示呢?

我们在百度,京东搜索时,关键字会变成红色,比较醒目,这叫高亮显示

高亮显示的实现分为两步:

  • 1)给文档中的所有关键字都添加一个标签,例如<em>标签

  • 2)页面给<em>标签编写CSS样式

高亮的语法

  1. GET products/_search
  2. {
  3.   "query": {
  4.     "match": {
  5.       "FIELD""TEXT" // 查询条件,高亮一定要使用全文检索查询
  6.     }
  7.   },
  8.   "highlight": {
  9.     "fields": { // 指定要高亮的字段
  10.       "FIELD": {
  11.         "pre_tags""<em>",  // 用来标记高亮字段的前置标签
  12.         "post_tags""</em>" // 用来标记高亮字段的后置标签
  13.       }
  14.     }
  15.   }
  16. }

注意:

  • 高亮是对关键字高亮,因此搜索条件必须带有关键字,而不能是范围这样的查询。

  • 默认情况下,高亮的字段,必须与搜索指定的字段一致,否则无法高亮

  • 如果要对非搜索字段高亮,则需要添加一个属性:required_field_match=false 

2.5.17.指定返回条数(size)

size关键字:指定查询结果中返回指定条数的数据。注:默认返回10条。

注:size的书写位置没有顺序,最前面、中间、后面都是可以的;符合json规范就成。

  1. #满足条件的有三条,这里限定只返回2
  2. GET /products/_search
  3. {
  4. "query": {
  5. "match": {
  6. "description": "this is"
  7. }
  8. },
  9. "size":2
  10. }

2.5.18.分页查询(from)

from关键字:用来指定起始返回位置,和size连用可以实现分页效果。

  1. #第一把
  2. GET /products/_search
  3. {
  4. "query": {
  5. "match_all": {}
  6. },
  7. "from": 0,
  8. "size":5
  9. }
  10. #翻页第二把
  11. GET /products/_search
  12. {
  13. "query": {
  14. "match_all": {}
  15. },
  16. "from": 5,
  17. "size":5
  18. }

2.5.19.指定字段排序(sort)

注意:sort和最外层的query平齐!!!!

  1. #desc:降序
  2. #asc:升序
  3. GET /products/_search
  4. {
  5. "query": {
  6. "match_all": {}
  7. },
  8. "sort": [
  9. {
  10. "price": {
  11. "order": "desc"
  12. }
  13. }
  14. ]
  15. }

2.5.20.指定返回字段(_source)

_source关键字:是一个数组,在数组中指定展示哪些字段。

注意:这里的“_source”也是和最外层的“query”平齐的

  1. GET /products/_search
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "_source": ["title","price"]
  7. }

更多的查询命令:

ES官网点击直达

2.6.聚合查询(Aggregation aggs)

简单来讲类似于sql中的group by。

注:text类型是不支持聚合的。

  1. 为了便于测试创建如下索引
  2. PUT fruit
  3. {
  4. "mappings": {
  5. "properties": {
  6. "title":{
  7. "type":"keyword"
  8. },
  9. "price":{
  10. "type":"double"
  11. },
  12. "description":{
  13. "type":"text",
  14. "analyzer": "ik_max_word"
  15. }
  16. }
  17. }
  18. }
  19. GET fruit
  20. #并插入如下数据
  21. POST fruit/_bulk
  22. {"index":{}}
  23. {"title":"面包","price":19.9,"description":"小面包很好吃"}
  24. {"index":{}}
  25. {"title":"大白兔","price":29.9,"description":"大白兔奶糖好吃"}
  26. {"index":{}}
  27. {"title":"豌豆","price":19.9,"description":"豌豆非常好吃"}
  28. {"index":{}}
  29. {"title":"旺仔小馒头","price":19.9,"description":"旺仔小曼斗很甜"}
  30. {"index":{}}
  31. {"title":"大辣片","price":9.9,"description":"大辣片很诱人"}
  32. {"index":{}}
  33. {"title":"脆司令","price":19.9,"description":"脆司令很管饿"}
  34. {"index":{}}
  35. {"title":"喜之郎果冻","price":19.9,"description":"小时候的味道"}

2.6.1.根据某个字段分组

语法:其语法就是在query平齐的位置加上一个aggs。

  1. #如下为一个实例。
  2. #其中"shuozhuo_price_group"为此次聚合的结果随便取的一个名字;这个名字是我们自定义的。
  3. #terms也是写死的。其含义是基于那个字段进行分组。
  4. GET /fruit/_search
  5. {
  6. "query": {
  7. "match_all": {}
  8. },
  9. "aggs": {
  10. "shuozhuo_price_group": {
  11. "terms": {
  12. "field": "price"
  13. }
  14. }
  15. }
  16. }
  17. #仅返回结果,不返回原始数据
  18. GET /fruit/_search
  19. {
  20. "query": {
  21. "match_all": {}
  22. },
  23. "size":0, #
  24. "aggs": {
  25. "shuozhuo_price_group": {
  26. "terms": {
  27. "field": "price"
  28. }
  29. }
  30. }
  31. }

 返回结果如下:

整个返回中的aggregations字段就是聚合结果;

buckets是一个数组表示的就是聚合后的数组;

注:如果只想返回聚合结果不想返回查询数据的话,利用size就好了。

2.6.2.求最大值/最小值/平均值

  1. #最大值
  2. GET /fruit/_search
  3. {
  4. "query": {
  5. "match_all": {}
  6. },
  7. "size":0,
  8. "aggs": {
  9. "shuozhuo_max_price": {
  10. "max": {
  11. "field": "price"
  12. }
  13. }
  14. }
  15. }
  16. #最小值
  17. GET /fruit/_search
  18. {
  19. "query": {
  20. "match_all": {}
  21. },
  22. "size":0,
  23. "aggs": {
  24. "shuozhuo_min_price": {
  25. "min": {
  26. "field": "price"
  27. }
  28. }
  29. }
  30. }
  31. #平均值
  32. GET /fruit/_search
  33. {
  34. "query": {
  35. "match_all": {}
  36. },
  37. "size":0,
  38. "aggs": {
  39. "shuozhuo_avg_price": {
  40. "avg": {
  41. "field": "price"
  42. }
  43. }
  44. }
  45. }
  46. #求和
  47. GET /fruit/_search
  48. {
  49. "query": {
  50. "match_all": {}
  51. },
  52. "size":0,
  53. "aggs": {
  54. "shuozhuo_sum_price": {
  55. "sum": {
  56. "field": "price"
  57. }
  58. }
  59. }
  60. }

SpringBoot整合ES

整合boot依赖

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.7.14</version>
  5. </parent>
  6. <dependencies>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.alibaba.fastjson2</groupId>
  13. <artifactId>fastjson2</artifactId>
  14. <version>2.0.37</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-test</artifactId>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.projectlombok</groupId>
  22. <artifactId>lombok</artifactId>
  23. </dependency>
  24. </dependencies>

application.yml配置

  1. spring:
  2. elasticsearch:
  3. username: elastic
  4. password: 123456
  5. # 集群就用逗号隔开
  6. uris: http://127.0.0.1:9201
  7. # username: xxx
  8. # password: yyy
  9. # connection-timeout: 1
  10. # read-timeout: 30

再自己写个启动类,单元测试类测试

一、基本概念

ElasticsearchTemplate

ElasticsearchTemplate是Spring对ES api的封装,提供大量的类完成各种操作。

QueryBuilders、NativeSearchQuery

springboot中使用QueryBuilders、NativeSearchQuery实现复杂查询

1) QueryBuilders

QueryBuilders是ES中的查询条件构造器
QueryBuilders.boolQuery          #子方法must可多条件联查
QueryBuilders.termQuery          #精确查询指定字段
QueryBuilders.matchQuery         #按分词器进行模糊查询
QueryBuilders.rangeQuery         #按指定字段进行区间范围查询

 2) NativeSearchQuery 原生的查询条件类,用来和ES的一些原生查询方法进行搭配,实现一些比较复杂的查询,最终进行构建.build 可作为ElasticsearchTemplate. queryForPage的参数使用

  1. //构建Search对象
  2. NativeSearchQuery build = new NativeSearchQueryBuilder()
  3. //条件
  4. .withQuery(queryBuilder)
  5. //排序
  6. .withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC))
  7. //高亮
  8. .withHighlightFields(name, ms)
  9. //分页
  10. .withPageable(PageRequest.of(pageNum - 1, pageSize))
  11. //构建
  12. .build();
  13. AggregatedPage<Goods> aggregatedPage = elasticsearchTemplate.queryForPage(build, Goods.class,new Hig());
  14. //queryForPage 参数一: NativeSearchQuery 封装的查询数据对象
  15. 参数二: es对应索引实体类
  16. 参数三: 调用高亮工具类
  17. 大于等于 .from .gte
  18. 小于等于 .to .lte

@Document 和 @Field 注解

用来加上实体类上面,描述索引库信息和属性类型分词器等信息

  1. @Persistent
  2. @Inherited
  3. @Retention(RetentionPolicy.RUNTIME)
  4. @Target({ElementType.TYPE})
  5. public @interface Document {
  6. String indexName(); //索引名称,好比MySQL的数据库名
  7. @Deprecated
  8. String type() default ""; //类型 ,当前版本已弃用
  9. /**
  10. * Use server-side settings when creating the index.
  11. * 翻译过来就是:创建索引时使用服务器端设置。
  12. * 这里默认为false,如果改为true,表示在Spring创建索引时,Spring不会在创建的索引中设置以下设
  13. * 置:shards、replicas、refreshInterval和indexStoreType。这些设置将是 Elasticsearch 默认
  14. * 值(服务器配置),也就是说,我们自定义的某些配置将不会生效。
  15. */
  16. boolean useServerConfiguration() default false;
  17. short shards() default 1; // 默认分区数
  18. short replicas() default 1;// 默认每个分区的备份数
  19. String refreshInterval() default "1s"; //索引默认的刷新时间间隔
  20. String indexStoreType() default "fs"; //索引文件存储类型
  21. /**
  22. * Configuration whether to create an index on repository bootstrapping.
  23. */
  24. boolean createIndex() default true; //当spring容器启动时,如果索引不存在,则自动创建索引
  25. VersionType versionType() default VersionType.EXTERNAL;//默认的版本管理类型
  26. }
  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.FIELD)
  3. @Documented
  4. @Inherited
  5. public @interface Field {
  6. @AliasFor("name")
  7. String value() default "";
  8. @AliasFor("value")
  9. String name() default "";
  10. //上面两个注解,可互为别名使用。
  11. //主要的作用就是指定我们创建索引时,当前字段在索引中的名称,如果不设置,它会默认使用实体类里
  12. // 面使用了@Field这个注解的属性名作为索引字段名。例如:
  13. // class User{
  14. //
  15. // @Field(name = "name" * 或者:value = "name"* )
  16. // private String userName;
  17. // }
  18. // 如上,如果设置了name(或value)值,那么索引里面对应userName的字段名就是“name”,否则就是
  19. // “userName”
  20. FieldType type() default FieldType.Auto; //自动检测索引字段的数据类型,可以根据实际情况自己设置。
  21. DateFormat format() default DateFormat.none;//日期时间格式化,默认不做任何处理
  22. String searchAnalyzer() default "";//检索时的分词策略
  23. String analyzer() default "";//创建索引时指定分词策略
  24. }

@Field中提到的FieldType 枚举

  1. public enum FieldType {
  2. Auto, //根据内容自动判断
  3. Text, //索引全文字段,如产品描述。这些字段会被分词器进行分词处理。
  4. Keyword, //用于索引结构化内容(如电子邮件地址,主机名,状态码,邮政编码等)的字段。他们通常用于过滤、排序、聚合。关键字字段只能根据期确切的值进行搜索。标记为keyword的字段不会被分词器分词处理
  5. Long, //
  6. Integer, //
  7. Short, //
  8. Byte, //
  9. Double, //
  10. Float, //
  11. Half_Float, //
  12. Scaled_Float, //
  13. Date, //
  14. Date_Nanos, //
  15. Boolean, //
  16. Binary, //
  17. Integer_Range, //
  18. Float_Range, //
  19. Long_Range, //
  20. Double_Range, //
  21. Date_Range, //
  22. Ip_Range, //
  23. Object, //
  24. Nested, //
  25. Ip, //可以索引和存储IPV4和IPv6地址
  26. TokenCount, //
  27. Percolator, //
  28. Flattened, //
  29. Search_As_You_Type //
  30. }

实体类

这里使用大家熟悉的Oracle中的Emp员工表做演示

  1. /**
  2. * @TableName emp
  3. */
  4. @Data
  5. @AllArgsConstructor
  6. @NoArgsConstructor
  7. @Builder
  8. /**
  9. * indexName:索引名称 唯一
  10. * shards(默认为1):对应DSL中创建索引 settings中的 number_of_shards
  11. * 是指索引要做多少个主分片,只能在创建索引时指定,后期无法修改。
  12. * 主分片,每个文档都存储在一个分片中,当你存储一个文档的时候,系统会首先存储在主分片中,
  13. * 然后会复制到不同的副本中。默认情况下,一个索引有1个主分片。
  14. * 你可以在事先制定分片的数量,当分片一旦建立,分片的数量则不能修改。
  15. * replicas(默认为1):对应DSL中创建索引 settings中的 number_of_replicas
  16. * 是指每个分片有多少个副本,后期可以动态修改
  17. * 副本分片,每一个分片有零个或多个副本。副本主要是主分片的复制,可以 增加高可用性,提高性能。
  18. * 默认情况下,一个主分配有一个副本,但副本的数量可以在后面动态的配置增加。
  19. * 副本必须部署在不同的节点上,不能部署在和主分片相同的节点上。
  20. *
  21. * 在Elasticsearch中,使用Spring Data Elasticsearch的@Document注解会生成一个名为_class的字段。
  22. * 这个字段用于标记被索引文档的完整类名,以确保在搜索时能够正确地反序列化文档到正确的Java类。
  23. *
  24. * createIndex:在使用mapper接口操作ES时 会自动帮你创建索引
  25. * 如果你实体类有对应的mapper接口(继承了ElasticsearchRepository) 并注入使用,
  26. * 而又需要使用ElasticsearchRestTemplate来创建索引 就必须设置为false 不然会创建两次索引 导致报错。
  27. * 如果你仅使用ElasticsearchRestTemplate创建索引 但是没有用到mapper接口 则不需要设置这个属性。
  28. * 如果直接操作mapper保存数据 不自己用代码创建索引 它会自动帮你创建 createIndex设置什么值都一样 都会帮你创建
  29. *
  30. * 简单省事:直接使用mapper接口操作就行 无需自己写代码创建索引了
  31. */
  32. @Document(indexName = "idx_emp",shards = 1,replicas = 0,createIndex = false)
  33. public class Emp implements Serializable {
  34. /*
  35. @Id如果需要使用Mapper来操作 就必须加这个注解 不然报错 找不到id
  36. template添加数据时 不指定id 会自动随机一个id 指定后 员工id作为文档id
  37. mapper添加数据时 会以员工id作为文档id
  38. 文档数据id 重复的id会覆盖之前的数据
  39. */
  40. @Id
  41. /*
  42. @Field
  43. 如果你的索引创建使用的是ElasticsearchRestTemplate 则必须写该属性 且 必须加上type属性指定类型 不然无法生成映射
  44. 如果你使用的mapper接口 那么可以省略该注解 会自动识别
  45. */
  46. @Field(type = FieldType.Integer)
  47. private Integer empno;
  48. /**
  49. * type:指定数据类型
  50. * analyzer分词器 可以不写
  51. * ik_max_word:会做 最细 粒度的拆分,把能拆分的词都拆出来
  52. * ik_smart:会做 最粗 粒度的拆分,贪心算法,尽可能把词分得长
  53. */
  54. @Field(type = FieldType.Text,analyzer = "ik_max_word")
  55. private String ename;
  56. @Field(type = FieldType.Keyword)
  57. private String job;
  58. @Field(type = FieldType.Integer)
  59. private Integer mgr;
  60. @Field(type = FieldType.Date)
  61. private String hiredate;
  62. @Field(type = FieldType.Double)
  63. private Double sal;
  64. @Field(type = FieldType.Double)
  65. private Double comm;
  66. @Field(type = FieldType.Integer)
  67. private Integer deptno;
  68. private static final long serialVersionUID = 1L;
  69. }

Mapper接口

使用后会自动创建索引,需要就写 不需要不写

  1. import com.zhibang.entity.Emp;
  2. import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
  3. public interface EmpMapper extends ElasticsearchRepository<Emp,Integer> {
  4. }

索引库操作

以下均在测试类中操作,需注入ElasticsearchTemplate,使用Mapper则注入Mapper接口(无需注册组件)

创建索引及映射
  1. @Test
  2. public void 创建索引(){
  3. IndexOperations index = restTemplate.indexOps(Emp.class);
  4. // 如果索引存在则会报错 也可以先判断后创建
  5. boolean b = index.create();
  6. if(b){
  7. System.out.println("创建索引库成功");
  8. // 生成映射
  9. Document mapping = index.createMapping();
  10. // 创建映射
  11. boolean b1 = index.putMapping();
  12. System.out.println(b?"创建映射成功":"创建映射失败");
  13. }
  14. }
  15. // 方式2 直接使用Mapper接口操作 会自动创建
删除索引
  1. @Test
  2. public void 删除索引(){
  3. IndexOperations index = restTemplate.indexOps(Emp.class);
  4. boolean b = index.delete();
  5. System.out.println(b?"删除成功":"删除失败");
  6. }
判断索引是否存在
  1. @Test
  2. public void 判断索引是否存在(){
  3. IndexOperations index = restTemplate.indexOps(Emp.class);
  4. boolean b = index.exists();
  5. System.out.println(b?"存在":"不存在");
  6. }

文档操作

添加数据
  1. @Test
  2. public void 添加数据(){
  3. Emp emp = Emp.builder().empno(1001).job("开发").mgr(8888).sal(5000d).
  4. ename("李四").hiredate("2020-1-1").comm(100d).deptno(10).build();
  5. try {
  6. // 这里我用try 是因为springboot整合的ES版本为7.17.11 我的客户端是8.12.2 不匹配会报错 但并不影响使用
  7. // 目前(20244月)最新版本依赖也才到7 如果不希望报错 需使用对应版本的ES客户端
  8. // 这里保存数据 可以直接存储对象或集合
  9. restTemplate.save(emp);
  10. // 方式2
  11. //empMapper.save(emp);
  12. }catch (Exception e){}
  13. }
根据ID查询
  1. @Test
  2. public void 根据文档id查询数据(){
  3. // 方式1
  4. Emp emp = restTemplate.get("1001", Emp.class);
  5. System.out.println(emp);
  6. // 方式2
  7. Emp emp2 = empMapper.findById("1001").get();
  8. System.out.println(emp2);
  9. }
查询全部
  1. @Test
  2. public void 查询全部(){
  3. // 方式1
  4. Iterator<Emp> emps = empMapper.findAll().iterator();
  5. // 自己转集合
  6. List<Emp> list = new ArrayList<>();
  7. while(emps.hasNext()){
  8. list.add(emps.next());
  9. }
  10. list.forEach(System.out::println);
  11. // 方式2
  12. NativeSearchQuery build = new NativeSearchQueryBuilder()
  13. .withQuery(QueryBuilders.matchAllQuery()).build();
  14. SearchHits<Emp> search = restTemplate.search(build, Emp.class);
  15. for (SearchHit<Emp> e : search) {
  16. Emp emp = e.getContent();
  17. System.out.println(emp);
  18. }
  19. }
高亮查询
  1. public SearchHits<Entity> search(String keyword) {
  2. MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("firstname", keyword);
  3. //高亮
  4. HighlightBuilder highlightBuilder = new HighlightBuilder();
  5. highlightBuilder.field("firstname");
  6. highlightBuilder.requireFieldMatch(false);//多个高亮关闭
  7. highlightBuilder.preTags("<span style='color:red'>");
  8. highlightBuilder.postTags("</span>");
  9. NativeSearchQuery query = new NativeSearchQueryBuilder()
  10. .withQuery(matchQueryBuilder)
  11. .build();
  12. query.setHighlightQuery(new HighlightQuery(highlightBuilder));
  13. SearchHits<Entity> search = restTemplate.search(query, Entity.class);
  14. return search;
  15. }
分页查询
  1. public SearchHits<Entity> selectByPage(int page, int size) {
  2. NativeSearchQuery query = new NativeSearchQueryBuilder()
  3. .withPageable(PageRequest.of(page - 1, size))
  4. .build();
  5. SearchHits<Entity> search = restTemplate.search(query, Entity.class);
  6. return search;
  7. }
排序
  1. public SearchHits<Entity> selectByAgeDesc() {
  2. NativeSearchQuery query = new NativeSearchQueryBuilder()
  3. .withSort(SortBuilders.fieldSort("age").order(SortOrder.DESC))
  4. .build();
  5. SearchHits<Entity> search = restTemplate.search(query, Entity.class);
  6. return search;
  7. }
时间范围
  1. public SearchHits<Entity> selectByRangeTime(String begin, String end) {
  2. NativeSearchQuery query = new NativeSearchQueryBuilder()
  3. .withSort(SortBuilders.fieldSort("createTime")
  4. .order(SortOrder.DESC))
  5. .withFilter(QueryBuilders.rangeQuery("createTime")
  6. .timeZone("+08:00")
  7. .format("yyyy-MM-dd HH:mm:ss")
  8. .gt(begin)
  9. .lt(end))
  10. .build();
  11. SearchHits<Entity> search = restTemplate.search(query, Entity.class);
  12. return search;
  13. }
同字段多条件匹配查询(or)
  1. public SearchHits<Entity> searchAll() {
  2. TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("age", "21", "31");
  3. Query query = new NativeSearchQueryBuilder().withQuery(termsQueryBuilder).build();
  4. SearchHits<Entity> search = restTemplate.search(query, Entity.class);
  5. return search;
  6. }
boostingQuery
  1. public SearchHits<Entity> boostingQuery() {
  2. NativeSearchQuery query = new NativeSearchQueryBuilder()
  3. .withQuery(
  4. QueryBuilders.boostingQuery(
  5. QueryBuilders.termQuery("age", "31"), //希望包含的
  6. QueryBuilders.termQuery("account_number", "51") //包含降低得分
  7. ).negativeBoost(0.2f)//设置满足negativeQuery精度
  8. ).build();
  9. SearchHits<Entity> search = restTemplate.search(query, Entity.class);
  10. return search;
  11. }
constantScoreQuery
  1. public SearchHits<Entity> constantScoreQuery() {
  2. NativeSearchQuery query = new NativeSearchQueryBuilder()
  3. .withQuery(
  4. QueryBuilders.constantScoreQuery(
  5. QueryBuilders.termQuery("account_number", "51")
  6. ).boost(1.2f)
  7. ).build();
  8. SearchHits<Entity> search = restTemplate.search(query, Entity.class);
  9. return search;
  10. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/785744
推荐阅读
相关标签
  

闽ICP备14008679号