zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

ElasticSearch学习总结(基础篇,可学习,可复习)

2023-04-18 16:17:22 时间

推荐:前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。。 点击跳转到网站

最近一周都在学习ElasticSearch,之前也零零散散的学过一点,这次下定决心花一周的时间将之前学的知识总结一下,顺便接着再往下学习,所以写篇博客总结一下最近一周的成果,本篇属于ElasticSearch的基础篇,后面会继续深入学习。也希望这篇拙作可以帮助到诸位大佬,如有不足之处,还望诸佬不吝赐教,倾囊相授。
在这里插入图片描述

ElasticSearch概述

ElasticSearch、简称ES,ES是一个开源的高扩展分布式全文检索引擎,它可以近乎实时的存储,检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别(大数据时代)的数据,ES也使用Java开发使用Lucene作为其核心来实现所有索引和搜索的功能,但是他的目的是通过简单的RestFul API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

在这里插入图片描述

ES和Solr的差别


ElasticSearch简介

ElasticSearch是一个实时分布式搜索和分析引擎,它让你以前所未有的速度处理大数据成为可能

它用于全文搜索、结构化、分析以及将这三者混合使用

维基百科使用ElasticSearch提供全文搜索并高亮关键字,以及输入实时搜索(search-asyou-type)和搜索纠错等搜索建议功能……

ElasticSearch是一个基于Apache Lucene的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进,性能最好的,功能最全的搜索引擎库

但是,Lucene只是一个库,想要使用它,你必须使用java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的

ElasticSearch也使用java开发并使用Lucene作为其核心来实现所有索引和搜索功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单!

Solr简介

Solr是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器,Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展、并对索引、搜索性能进行了优化!

Solr可以独立运行,运行在Jetty、Tomcat等这些Servlet容器中,Solr索引的实现方法很简单,==用POST方法向Solr服务器发送一个描述Field及其内容的XML文档,Solr根据xml文档添加,删除,更新索引,==Solr搜索只需要发送HTTP GET请求,然后对Solr返回xml、json等格式的查询结果进行解析,组织页面布局,Solr不提供构建UI的功能,Solr提供了一个管理界面,通过管理界面可以查询Solr的配置和运行情况。

Solr是基于Lucene开发企业级搜索服务器,实际上就是封装Lucene

Solr是一个独立的企业级搜索应用服务器,它对外提供类似与web-service的API接口,用户可以通过http请求,向搜索引擎服务器提交一定格式的文件,生成索引,也可以通过提交查找请求,并得到返回结果!

ElasticSearch 和 Solr

  • 当单纯的对已有数据进行搜索时,Solr更快!
  • 当实时建立索引时,Solr会产生IO阻塞,查询性能较差,ElasticSearch具有明显的优势
  • 随着数据量的增加,Solr的搜索效率会变得更低,而ElasticSearch却没有明显的的变化

在这里插入图片描述

ElasticSearch vs Solr

  1. ES基本是开箱即用(解压就可以用),非常简单,Solr安装稍微复杂一点
  2. Solr利用Zookeeper进行分布式管理。而ElasticSearch自身带有分布式协调管理功能
  3. Solr支持更多格式的数据,比如JSON、XML、CSV,而ElasticSearch仅支持json文件格式
  4. Solr官方提供的功能更多,而ElasticSearch本身更注重核心功能,高级功能多有第三方插件提供,例如,图形化界面,Kibana友好支撑
  5. Solr查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用;
    • ES建立索引快(即查询慢),即实时性查询快,用于facebook新浪等搜索
    • Solr是传统搜索应用的有利解决方案,但ElasticSearch更适用于新兴的实时搜索应用

​ 6.Solr比较成熟,有一个更大,更成熟的用户,开发和贡献者社区,而ElasticSearch相对开发维护者少,更新太快,学习成本较高

ElasticSearch安装

Java开发,ElasticSearch的版本和我们之后对应的java的核心jar包,版本对应,java环境正常!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mguUJz9K-1651155173754)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713142610947.png)]

2、熟悉目录

bin  启动文件
config 配置文件
	log4j2 日志配置文件
	jvm.options java虚拟机相关的配置
	ElasticSearch ElasticSearch配置文件  默认端口9200  !跨域

lib 相关jar包
modules 功能模块
plugins 插件

3、启动 ,访问9200 elasticsearch.bat

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hvjH7edi-1651155173755)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713144003204.png)]

4、访问测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4VFvisvM-1651155173755)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713144028466.png)]

安装可视化界面 es head的插件

1、下载地址https://github.com/mobz/elasticsearch-head

2、启动

npm install 安装依赖
npm run start 启动

3、连接测试发现,存在跨域问题:配置es

http.cors.enabled: true
http.cors.allow-origin: "*"

4、重启es ,再次连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Bojfd3t-1651155173756)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713145738003.png)]

初学,可以把es当做一个数据库!(可以建立索引(库),文档(库中的数据))

这个head我们就把它当做数据展示工具!我们后面所有的查询,Kibana

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9qCTeh3e-1651155173756)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713151440274.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h1w4b7dI-1651155173756)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713151454041.png)]

安装Kibana

Kibana是一个针对ElasticSearch的开源分析及可视化平台,用来搜索,查看交互存储在ElasticSearch索引中的数据,使用Kibana,可以通过各种图表进行高级数据分析及展示,Kibana让海量数据更容易理解,基于浏览器的用户界面可以快速创建仪表板实时显示ElasticSearch查询动态,设置Kibana非常简单,无序编码或者额外的基础架构,几分钟内就可以完成Kibana安装并启动ElasticSearch索引检测。

官网:https://www.elastic.co/cn/kibana

Kibana版本要和ES版本一致

启动测试

1、目录结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QEjXUbuZ-1651155173756)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713152549141.png)]

2、启动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KBLrcrQy-1651155173756)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713154656280.png)]

3、开发工具!(POST、curl、head、谷歌浏览器插件)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4RfsXVS0-1651155173757)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713154748647.png)]

之后的所有的操作都在这里编写

4、汉化!自己修改Kibana.yml ! zh-CN

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B7mvu4EY-1651155173758)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713155323919.png)]

在这里插入图片描述

ES核心概念

概述

集群、节点、索引、类型、文档、分片、映射是什么?

elasticSearch是面向文档,关系型数据库 和 ElasticSearch 客观的对比!一切都是JSON

Relational DBElasticSearch
数据库(database)索引(indices)
表(tables)types
行(rows)documents
字段(columns)fields

elasticsearch(集群)中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型下又包含多个文档(行),每个文档重女又包含多个字段(列)

物理设计:

ElasticSearch在后台把每个索引划分为多个分片,每分分片可以在集群中的不同服务器间迁移

逻辑设计:

一个索引类型中,包含多个文档,比如说文档1,文档2,当我们索引一篇文档时,可以通过这样的一个顺序找到它:索引–>类型–>文档ID。通过这个组合我们就能索引到某个具体的文档,注意:ID不必是整数,实际上它是个字符串

文档

之前说ElasticSearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档,ElasticSearch,文档有几个重要属性:

  • 自我包含,一篇文档同时包含字段和对应的值,也就是同时包含key:value
  • 可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的
  • 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在ElasticSearch中,对于字段是非常灵活的,有时候,我们可以忽略改字段,或者动态的添加一个新的字段
  • 尽管我们可以随意的新增或者忽略某个字段,但是,每个字段的类型非常重要,比如一个年龄字段类型,可以是字符串也可以是整型,因为ElasticSearch会保存字段和类型之间的映射及其他的设置,这种映射具体到每个映射的每种类型,这也是为什么在ElasticSearch中,类型有时候也称为映射类型。

类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MDMRSIJ-1651155173758)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713161855351.png)]

索引(就是一个数据库)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y66I0uqv-1651155173758)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713161917384.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPIwsRcA-1651155173758)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713162026321.png)]

倒排索引

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jKteBMXA-1651155173758)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713162331257.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1KoSBtMF-1651155173758)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713162348827.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1WgAH3DU-1651155173759)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713162424186.png)]

在这里插入图片描述

IK分词器

什么是IK分词器

分词:即把一段中文或者别的划分成一个个的关键字,我们把搜索时会把自己的信息进行分词,会把数据库中或索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词。比如:“我爱狂神”会被分为:”我“,”爱“,”狂“,”神“,这显然是不符合要求的,所以我们需要安装中文分词器IK来解决这个问题

IK提供了两个分词算法:ik_smart和ik_max_word,其中ik_smart为最少切分,ik_max_word为最细粒度划分

下载安装

1、https://github.com/medcl/elasticsearch-analysis-ik

2、下载完毕之后,直接放在ElasticSearch插件中即可!

3、重启ElasticSearch

测试分词器效果

ik__smart

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1bVrE4A0-1651155173759)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713175918474.png)]

ik_max_word

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdxoZpjL-1651155173759)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713180019814.png)]

ik分词器增加自己的配置!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z9Zze9f2-1651155173759)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210713180421414.png)]

保存后重启ES!

在这里插入图片描述

Rest风格说明

一种软件架构风格,而不是标准,只是提供了一组设计原则和约束条件,它主要用于客户端和服务端交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

基本的Rest命令说明:

methodurl地址描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id查询文档通过文档id
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据

基础测试

1、创建一个索引

PUT /索引名/类型名/文档id
{请求体}

2、向索引中PUT值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMTXOCQm-1651155173759)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714090854059.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GaHR9pUg-1651155173759)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714091113094.png)]

3、name这个字段用不用指定类型呢,毕竟我们关系型数据库,是需要指定类型的

  • 字符串类型

    text 、keyword

  • 数值类型

    long、integer、short、byte、double、float、half、float、scaled

  • 日期类型

    date

  • te布尔值类型

    boolean

  • 二进制类型

    binary

  • 等等……

4、指定字段的类型(创建规则)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3IBidM6R-1651155173759)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714110342482.png)]

获取规则,可以通过get请求获取具体的信息

GET test2

测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vhv5KWF6-1651155173765)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714110916101.png)]

如果自己的文档字段没有自定,那么es会给我们配置默认字段类型!

扩展:通过命令ElasticSearch索引情况! 通过get _cat/ 可以获得ElasticSearch的很多信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hbxYfoOJ-1651155173765)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714111546872.png)]

修改索引 提交还是使用PUT

曾经的方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OekLxQhx-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714111950931.png)]

最新办法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-skgM9fbR-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714112233053.png)]

删除索引 通过DELETE命令实现删除,根据你的请求来判断是删除索引还是删除文档记录!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UgGNs63Z-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714112451631.png)]

在这里插入图片描述

关于文档的基本操作(重点)

基本操作

1、添加一条数据

PUT /wumao/user/1
{
  "name":"wumao",
  "age":21,
  "desc":"一顿操作猛如虎,一看工资2500",
  "tags":["技术宅","无聊者"]
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ocrVBSc-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714113305099.png)]

2、获取数据 GET

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PrxLg4f3-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714135508899.png)]

3、更新操作 POST _update推荐使用这种更新方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GxUEG8dO-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714135637869.png)]

简单的搜索

GET wumao/user/1

简单的条件查询 ,可以根据默认的映射规则,产生基本的查询!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0QKl5DY7-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714140557147.png)]

复杂操作 搜索 select(排序、分页、高亮、精准查询!)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LZkRThtn-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714141127591.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i4E1QloB-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714141843976.png)]

输出结果,不想要那么多结果!select name,desc . . . .

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nRMpgm2X-1651155173766)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714142223683.png)]

之后使用Java操作es,所有的方法和对象就是这里面的key!

排序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nF3tCA5p-1651155173767)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714142624053.png)]

分页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-feBGkhCL-1651155173767)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714143143031.png)]

数据下标还是从0开始的,和学的所有数据结构是一样的!

/search/{current}/{pageSize}

布尔值查询

must (and),所有的条件都要符合 where id = 1 and name =xxx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3E96utWQ-1651155173767)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714143805187.png)]

should( or ),所有的条件都要符合 where id = 1 orname =xxx

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iSeyZggq-1651155173767)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714144120165.png)]

must_not(not)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wJjMBlzY-1651155173768)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714144325704.png)]

过滤器filter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-02uhGsog-1651155173768)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714144647767.png)]

 gt  >  大于
 gte >= 大于等于
 lt  <  小于
 lte <= 小于等于

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Asl2iljy-1651155173768)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714145020610.png)]

匹配多个条件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZYhQvlmU-1651155173768)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714145440484.png)]

精确查询!

trem 查询是直接通过倒排索引指定的词条进行精确的查找的!

关于分词:

  • term,直接查询精确地

  • match,会使用分词器解析(先分析文档,通过分析的文档进行查询)

    两个类型 text keyword

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-933o5laz-1651155173768)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714151034789.png)]

在这里插入图片描述[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-INcYqWQ8-1651155173769)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714150952502.png)]

多个值精确匹配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLbiXazY-1651155173769)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714151931527.png)]

高亮查询!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wDE044He-1651155173769)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714152752000.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ULcamB33-1651155173769)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714153126630.png)]

  • 匹配
  • 按条件匹配
  • 精确匹配
  • 区间范围匹配
  • 匹配字段过滤
  • 多条件查询
  • 高亮查询

在这里插入图片描述

集成SpringBoot

找官方文档!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6Vfk5qj-1651155173770)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714154345533.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gZxpArD3-1651155173770)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714154532371.png)]

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/index.html

1、找到原生的依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.13.2</version>
</dependency>

2、找对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KCEJMa0I-1651155173770)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714154927532.png)]

3、分析这个类中的方法

配置基本的项目

问题:创建项目默认的elasticsearch的默认版本是7.12.1,版本和本地不一致!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QDJIZgCD-1651155173770)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714162835451.png)]
需要自己定义版本的依赖

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eIwt5FGV-1651155173770)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714162955935.png)]

分析源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ELtxzxWg-1651155173770)(/Users/wumao/Documents/Typora笔记/typora-user-imagesimage-20210714165030065.png)]

虽然导入了三个类,静态内部类,核心类只有一个

/**
 * Elasticsearch rest client configurations.
 *
 * @author Stephane Nicoll
 */
class ElasticsearchRestClientConfigurations {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingBean(RestClientBuilder.class)
	static class RestClientBuilderConfiguration {

		@Bean
		RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
			return new DefaultRestClientBuilderCustomizer(properties);
		}
	//第一个bean  RestClientBuilder
		@Bean
		RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties,
				ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
			HttpHost[] hosts = properties.getUris().stream().map(this::createHttpHost).toArray(HttpHost[]::new);
			RestClientBuilder builder = RestClient.builder(hosts);
			builder.setHttpClientConfigCallback((httpClientBuilder) -> {
				builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder));
				return httpClientBuilder;
			});
			builder.setRequestConfigCallback((requestConfigBuilder) -> {
				builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(requestConfigBuilder));
				return requestConfigBuilder;
			});
			builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
			return builder;
		}

		private HttpHost createHttpHost(String uri) {
			try {
				return createHttpHost(URI.create(uri));
			}
			catch (IllegalArgumentException ex) {
				return HttpHost.create(uri);
			}
		}

		private HttpHost createHttpHost(URI uri) {
			if (!StringUtils.hasLength(uri.getUserInfo())) {
				return HttpHost.create(uri.toString());
			}
			try {
				return HttpHost.create(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(),
						uri.getQuery(), uri.getFragment()).toString());
			}
			catch (URISyntaxException ex) {
				throw new IllegalStateException(ex);
			}
		}

	}
	
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingBean(RestHighLevelClient.class)
	static class RestHighLevelClientConfiguration {

        //第二个bean  RestHighLevelClient 高级客户端,后面项目会用到!
		@Bean
		RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
			return new RestHighLevelClient(restClientBuilder);
		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Sniffer.class)
	@ConditionalOnSingleCandidate(RestHighLevelClient.class)
	static class RestClientSnifferConfiguration {

		@Bean
		@ConditionalOnMissingBean
		Sniffer elasticsearchSniffer(RestHighLevelClient client, ElasticsearchRestClientProperties properties) {
			SnifferBuilder builder = Sniffer.builder(client.getLowLevelClient());
			PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
			map.from(properties.getSniffer().getInterval()).asInt(Duration::toMillis)
					.to(builder::setSniffIntervalMillis);
			map.from(properties.getSniffer().getDelayAfterFailure()).asInt(Duration::toMillis)
					.to(builder::setSniffAfterFailureDelayMillis);
			return builder.build();
		}

	}

	static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCustomizer {

		private static final PropertyMapper map = PropertyMapper.get();

		private final ElasticsearchRestClientProperties properties;

		DefaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
			this.properties = properties;
		}

		@Override
		public void customize(RestClientBuilder builder) {
		}

		@Override
		public void customize(HttpAsyncClientBuilder builder) {
			builder.setDefaultCredentialsProvider(new PropertiesCredentialsProvider(this.properties));
		}

		@Override
		public void customize(RequestConfig.Builder builder) {
			map.from(this.properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis)
					.to(builder::setConnectTimeout);
			map.from(this.properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
					.to(builder::setSocketTimeout);
		}

	}

	private static class PropertiesCredentialsProvider extends BasicCredentialsProvider {

		PropertiesCredentialsProvider(ElasticsearchRestClientProperties properties) {
			if (StringUtils.hasText(properties.getUsername())) {
				Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(),
						properties.getPassword());
				setCredentials(AuthScope.ANY, credentials);
			}
			properties.getUris().stream().map(this::toUri).filter(this::hasUserInfo)
					.forEach(this::addUserInfoCredentials);
		}

		private URI toUri(String uri) {
			try {
				return URI.create(uri);
			}
			catch (IllegalArgumentException ex) {
				return null;
			}
		}

		private boolean hasUserInfo(URI uri) {
			return uri != null && StringUtils.hasLength(uri.getUserInfo());
		}

		private void addUserInfoCredentials(URI uri) {
			AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort());
			Credentials credentials = createUserInfoCredentials(uri.getUserInfo());
			setCredentials(authScope, credentials);
		}

		private Credentials createUserInfoCredentials(String userInfo) {
			int delimiter = userInfo.indexOf(":");
			if (delimiter == -1) {
				return new UsernamePasswordCredentials(userInfo, null);
			}
			String username = userInfo.substring(0, delimiter);
			String password = userInfo.substring(delimiter + 1);
			return new UsernamePasswordCredentials(username, password);
		}

	}

}

具体的API测试

1、创建索引

2、判断文档是否存在

3、删除索引

4、创建文档

5、CRUD文档

@SpringBootTest
class WumaoEsApiApplicationTests {


    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;


    //测试创建索引 在java中所有的请求都是用Request  PUT wumao_index
    @Test
    public void testCreateIndex() throws IOException {
        //1、创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("wumao_index");
        //2、客户端执行请求  IndicesClient,请求后获取响应
        CreateIndexResponse createIndexResponse = client.indices()
                .create(request, RequestOptions.DEFAULT);

        System.out.println(createIndexResponse);

    }

    //测试获取索引

    @Test
    void testExistsIndex() throws IOException {

        GetIndexRequest re = new GetIndexRequest("wumao_index");

        boolean exists = client.indices().exists(re,RequestOptions.DEFAULT);

        System.out.println(exists);
    }


    //测试删除索引
    @Test
    void testDeleteIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("wumao_index");
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);

        System.out.println(delete);
    }


    //添加文档
    @Test
    void testAddDocument() throws IOException {
        //创建对象
        User user = new User("五毛",3);
        //创建请求
        IndexRequest request = new IndexRequest("wumao_index");

        //设值一些规则 put /wumao_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");

        //将我们的数据放入请求 json
        String string = JSON.toJSONString(user);
        request.source(string, XContentType.JSON);

        //客户端发送请求,获取响应的结果
        IndexResponse index = client.index(request, RequestOptions.DEFAULT);

        System.out.println(index.toString());
        System.out.println(index.status());//对应我们命令的返回状态


    }

    //获取文档
    @Test
    void testIsExists() throws IOException {

        //获取文档,判断是否存在 get/index/doc/1
        GetRequest index = new GetRequest("wumao_index", "1");

        //不获取返回的_source的上下文了
        index.fetchSourceContext(new FetchSourceContext(false));
        index.storedFields("_none_");
        boolean exists = client.exists(index, RequestOptions.DEFAULT);
        System.out.println(exists);
    }


    //获取文档的信息
    @Test
    void testGetDocument() throws IOException {

        GetRequest index = new GetRequest("wumao_index", "1");
        GetResponse fields = client.get(index, RequestOptions.DEFAULT);
        System.out.println(fields.getSourceAsString());
        System.out.println(fields);
    }


    //更新文档记录
    @Test
    void testUpdateDocument() throws IOException {
        UpdateRequest index = new UpdateRequest("wumao_index", "1");

        //设置超时时间
        index.timeout(TimeValue.timeValueSeconds(1));
        User user = new User("法外狂徒张三", 12);
        UpdateRequest doc = index.doc(JSON.toJSONString(user),XContentType.JSON);
        UpdateResponse update = client.update(index, RequestOptions.DEFAULT);
        System.out.println(update);
    }


    //删除文档记录
    @Test
    void testDeleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("wumao_index", "1");
        //设置请求过期时间
        request.timeout("1s");
        DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.status());
    }


    //特殊的,真的项目一般都是批量插入数据
    @Test
    void testBulkRequest() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();

        bulkRequest.timeout("10s");

        ArrayList<User> userList = new ArrayList<>();
        userList.add(new User("wumao",3));
        userList.add(new User("wumao1",23));
        userList.add(new User("wumao2",21));
        userList.add(new User("wumao3",12));
        userList.add(new User("wumao4",13));
        userList.add(new User("wumao5",23));
        userList.add(new User("wumao6",33));

        for (int i = 0; i < userList.size(); i++) {
            bulkRequest.add(new IndexRequest("wumao_index")
                    .source(JSON.toJSONString(userList.get(i)),XContentType.JSON)
            );
        }
        BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(bulk.hasFailures());//是否失败!
    }

    //查询
    // SearchRequest 搜索请求
    // SearchSourceBuilder 条件构造
    // HighlightBuilder 构建高亮
    // TermQueryBuilder 精确查询
    // MatchAllQueryBuilder 查询全部
    // xxxxQueryBuilder 对应之前的那些命令
    @Test
    void testSearch() throws IOException {
        SearchRequest request = new SearchRequest("wumao_index");
        //构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //查询条件,我么可以使用QueryBuilders 工具类来实现
        //QueryBuilders.termQuery 精确查询
        //QueryBuilders.matchAllQuery(); 匹配所有
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        TermQueryBuilder termQuery = QueryBuilders.termQuery("name", "wumao");
            //查询过期时间
            sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

            request.source(sourceBuilder);

        SearchResponse search = client.search(request, RequestOptions.DEFAULT);
        System.out.println(JSON.toJSONString(search.getHits()));

        for (SearchHit hit : search.getHits().getHits()) {
            System.out.println(hit.getSourceAsMap());
        }
    }

    //批量创建文档
    @Test
    void testBulkDocument() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        //设置过期时间
        bulkRequest.timeout("60s");

        ArrayList<User> userList = new ArrayList<>();
        userList.add(new User("qinfeng",3));
        userList.add(new User("qinfeng1",3));
        userList.add(new User("qinfeng2",3));
        userList.add(new User("qinfeng3",3));
        userList.add(new User("qinfeng4",3));
        userList.add(new User("qinfeng5",3));

        for (int i = 0; i < userList.size(); i++) {
            bulkRequest.add(new IndexRequest("wumao_index")
            .id(""+(i+1))
                    .source(JSON.toJSONString(userList.get(i)),XContentType.JSON));
        }
        BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);

        System.out.println(bulk.hasFailures());//判断是否失败

    }

}

在这里插入图片描述

实战案例

  • 爬虫

数据问题 数据库中获取,消息队列获取

爬取数据(获取请求返回的页面信息,筛选出我们所需要的)

<!--解析网页-->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.14.2</version>
</dependency>
 public List<Content> parseJD(String keyWords) throws Exception {
        //获取请求  https://search.jd.com/Search?keyword=java
        String url = "https://search.jd.com/Search?keyword="+keyWords;
        //解析网页 (Jsoup返回的Document就是Document对象)
        Document document = Jsoup.parse(new URL(url), 30000);
        //所有在js中使用的方法,在这里都可以使用
        Element element = document.getElementById("J_goodsList");


        ArrayList<Content> list = new ArrayList<>();

        //获取所有的li元素
        Elements elements = element.getElementsByTag("li");
        //这里的el就是每一个li标签
        for (Element el : elements) {
            //关于这种图片特别多的网站,都是延时加载的
            String price = el.getElementsByClass("p-price").eq(0).text();
            String title = el.getElementsByClass("p-name").eq(0).text();

            Content content = new Content();
            content.setTitle(title);
            content.setPrice(price);
            list.add(content);
        }
        return list;
    }
  • 前后端分离

  • 搜索高亮

   //解析数据放入到es中
    public Boolean parseContent(String keyWords) throws Exception {
        List<Content> contents = new HtmlParseUtil().parseJD(keyWords);

        //把查询到的数据放入到es中
        BulkRequest request = new BulkRequest();
        request.timeout("2m");
        for (int i = 0; i < contents.size(); i++) {
            System.out.println(JSON.toJSONString(contents.get(i)));
            request.add(
                    new IndexRequest("jd_goods")
                    .source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
        }
        BulkResponse bulkResponse = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        return !bulkResponse.hasFailures();
    }
    //3.实现搜索高亮功能
    public List<Map<String,Object>> searchHighlightPage(String keyword,int pageNO,int pageSize) throws IOException {
        if (pageNO <=1){
            pageNO =1;
        }

        //条件搜索
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //分页
        sourceBuilder.from(pageNO);
        sourceBuilder.size(pageSize);

        //精准匹配
        QueryBuilders.termQuery("title",keyword);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.requireFieldMatch(false); //高亮显示一个title只显示一个高亮就可以
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");

        sourceBuilder.highlighter(highlightBuilder);

        //执行搜索
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits()) {

            //解析高亮字段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
            //解析高亮字段,将原来的字段换为我们高亮的字段即可!
            if (title!=null){
                Text[] fragments = title.fragments();
                String n_title="";
                for (Text text : fragments) {
                    n_title += text;
                }
                sourceAsMap.put("title",n_title); //高亮字段替换掉原来的内容即可!
            }
            list.add(sourceAsMap);
        }
        return list;
    }

本篇到这里就结束了!后续还会继续更新ElasticSearch调优、ElasticSearch集群以及面试题相关的内容,
感谢诸佬的点赞和支持。
如有不足之处,还希望诸佬指出不足之处,加以修正。

再见了各位小伙伴!
在这里插入图片描述