ElasticSearch入门简介、安装ES(安装Kibana和IK分词器)使用 Postman连接ES进行测、ESRestAPI(操作索引CRUD操作文档CRUD)、练习
- 要理解倒排索引
- 要能够使用DSL命令操作索引库
- 要能够使用DSL命令操作文档
- 要能够使用RestAPI操作索引库、文档
一、ES简介
- 理解倒排索引的概念和作用
- 理解es和MySql的区别和使用场景
1. 数据库查询的问题
假如我们有一个电商系统,需要查询商品。以前一直是直接从MySql数据库里用SQL语句模糊查询,例如:
select * from tb_product where pname like '%华为手机%'
但是这种查询检索数据的方式,有很大的问题:
查询性能很低
MySql可以通过索引的方式来提高查询的效率,但是像上边这种模糊查询以%开头,会导致索引失效,实际上执行的是全表扫描,效率非常低。
查询结果不准确
我们应当查询到与“手机”、“华为”等词条相关的所有商品,而不是 只包含“华为手机”的商品
而这些问题,都可以使用ElasticSearch轻易的解决掉:把数据存储到ElasticSearch里,由ElasticSearch提供高效的文档检索能力
2. ES简介
2.1 ElasticSearch简介
ElasticSearch,简称ES。
ES是:一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。
如:百度搜索、京东商品搜索、打车软件中搜附近的车辆等等。
ES结合kibana、Logstash、Beats(也就是ELK技术栈,Elastic Stack),
被广泛的用户在日志数据分析、实时监控等领域。
ES是:ELK的核心,负责存储、搜索、分析数据。
2.2 ElasticSearch发展
Doug Cutting于1999年研发了一个Java语言的搜索引擎类库(函数库):Lucene,目前已是Apache的顶级项目。
官网地址:Apache Lucene - Welcome to Apache Lucene
Lucene优势:易扩展、高性能(基于倒排索引)
Lucene缺点:只限于Java语言、学习曲线陡峭、不支持水平扩展
2004年Shay Banon基于Lucene开发了Compass,随后于2010年重写了Compass,取名为ElasticSearch。
官网地址:欢迎来到 Elastic — Elasticsearch 和 Kibana 的开发者 | Elastic
相比于Lucene,ElasticSearch具备更多优势:
支持分布式,可水平扩展
提供RESTful接口,任何编程语言都可以使用。
到目前为止,ElasticSearch已经成为主流的搜索引擎
3. 倒排索引
3.0 索引介绍
索引:索引是一种数组结构,可以帮助我们快速查找数据,提升查询的速度。类似于字典的目录
如果没有目录:想要查找一项数据,就需要全表扫描,速度非常慢
可以构造目录:
根据拼音构造了目录:想要查找一个字,就可以根据拼音,从拼音目录里快速找到这个字在哪一页
直接到这一页,获取这个字的详细信息了
根据笔画构造了目录:想要查找一个字,就可以根据笔画,从笔画目录里快速找到这个字在哪一页
直接到这一页,获取这个字的详细信息了
根据偏旁构造了目录:想要查找一个字,就可以根据偏旁,从偏旁目录里快速找到这个字在哪一页
直接到这一页,获取这个字的详细信息了
在数据库里:
如果没有索引:想要查找一条数据,就需要全表扫描,速度非常慢
可以构造索引:
根据主键id构造索引:想要查找id为1的数据,直接去索引里找到id对应的数据在磁盘上哪个地址
直接跳转到这个地址,获取这条数据的详细信息
根据用户名构造索引:想要查找“张三”数据,直接去用户名索引里找到数据对应的地址
直接到这个地址,获取这条数据的详细信息
索引的特点:
可以极大的提升查询速度
但是会影响增删改的速度
3.1 正向索引
说明
传统RDBMS(例如MySql)采用的是正向索引,
即:根据表的主键字段构建索引,在查询时要扫描到每个索引值对应的数据,
从中筛选出符合查询条件的记录。
这样的检索方式构建索引简单,但是不适合复杂的文档检索。
复杂的文档检索时,索引会失效,变成全表扫描
示例
以商品表搜索为例,商品表tb_product如下:
id title price 1 小米手机 3499 2 华为手机 4999 3 华为小米手机充电器 49 4 小米手环 79 要搜索包含“手机”的商品,执行SQL:select * from tb_product where title like '%手机%'
MySql会扫描所有的数据记录,逐条判断 “title”的值是否包含“手机”,直到全表扫描,过滤出所有符合要求的结果
3.2 倒排索引
说明
ElasticSearch采用的是:倒排索引
即:以字或词为关键字构建索引,保存每个关键字所在的记录。
当需要查询时,根据词条匹配查询条件,直接找到关联的记录。
倒排索引的建立和维护都比较复杂,但是在查询时可以和查询关键字关联的所有结果,并快速响应。
示例
以商品表搜索为例,商品表略
构建倒排索引
词条(term) 文档id 小米 1, 3, 4 手机 1, 2 华为 2, 3 充电器 3 手环 4 文档Document:每条数据就是一个文档
词条term:按照语义分成的词语
当搜索“华为手机”时:
把搜索条件进行分词,得到两个词条:“华为”, “手机”
根据词条,去倒排索引里查询相关的文档id,得到:
“华为”:2, 3
“手机”:1, 2
根据文档id,找到对应的文档数据,得到:id为1、2、3的文档
4. ES和MySql
使用方式
传统的RDBMS和ElasticSearch各有所长:
RDBMS是 Relational Database Management System 的缩写,
中文译为“关系数据库管理系统”
它是 SQL 语言以及所有现代数据库系统(例如 SQL Server、DB2、Oracle、MySQL 和 Microsoft Access)的基础。
关系数据库管理系统(RDBMS)是一种基于 E. F. Codd 发明的关系模型的数据库管理系统(DBMS)。
MySQL:擅长事务类操作,可以确保数据的一致性和安全性
ES:擅长海量数据的搜索、分析、计算
在实际开发中,通常是结合使用
MySQL负责写操作
ES负责搜索操作
5. 小结
正向索引:先找到数据,再判断数据是否符合条件。需要全表扫描,速度慢
倒排索引:根据词条去倒排索引里找文档id,直接找到数据。不需要全表扫描,速度极快
1. ES会对数据表里的某些字段构建倒排索引
对这个字段的值,进行拆词(分词),得到词条
构建出来 每个词条 与 文档id的对应关系
这个对应关系,就是倒排索引
2. 在搜索数据时,提供搜索词
ES会对搜索词进行拆词(分词)得到词条
去倒排索引里,直接找到关联的文档id,获取id对应的数据
ES和MySQL的使用方式
有查询操作,找ES
有增删改操作,找MySQL
然后MySQL和ES之间要实现数据同步
二、安装ES
掌握
- 安装es7.4,安装kibana
- 安装ik分词器
- 理解ik分词器的分类和作用
1. 安装ES
目前我们安装的是ES的7.4.0版本,需要JDK8及以上
1.1 解压
把《elasticsearch-7.4.0-windows-x86_64.zip》解压到一个不含中文、空格、特殊字符的目录里
1.2 配置
1) 配置存储路径
打开config/elasticsearch.yml文件,设置索引数据的存储路径,和日志的存储路径
2) 配置虚拟机参数
进入es的bin目录,直接双击 elasticsearch.bat即可启动
es服务要占用两个端口:
9200:rest访问接口,我们稍后要通过这个端口连接es、操作es
9300:用于es集群间通信的接口
1.3 验证
在浏览器上直接输入地址 http://localhost:9200/, 如果看到以下界面,说明es启动成功了
2. 安装Kibana
Kibana是一个ES索引库数据统计工具,可以利用ES的聚合功能,生成各种图表,如柱形图,线状图,饼图等。
而且还提供了操作ES索引数据的控制台,并且提供了一定的API提示,非常有利于我们学习ES的语法。
2.1 安装nodeJs
Kibana依赖于nodeJs,需要在windows下先安装Node.js,然后才能安装Kibana。
双击nodejs的安装包,按照提示一步步安装即可
安装成功后,打开cmd 输入:
node -v
,如果能看到版本号,说明node安装成功2.2 安装Kibana
1) 解压
把《kibana-7.4.0-windows-x86_64.zip》解压到不含中文、空格、特殊字符的目录里
2) 配置
修改kibana的config/kibana.yml,配置es的地址
3) 启动
进入到kibana的bin目录,双击 kibana.bat 启动。启动稍微有些慢,耐心等待一会
4) 访问
打开浏览器输入 http://localhost:5601/
3. 安装IK分词器
3.1 ES标准分词器的问题
ES自带的分词器叫“Standard Analyzer”,它对中文的支持非常不友好,会将一个词语的每个字拆分成一个词条,和中文的语法是完全不符的。
例如,一个词语“使用分词器”,按中文语法习惯可以拆分成“使用”,“分词器”,“分词”等词条。但是标准分词器分拆分成“使”,“用”,“分”,“词”,“器”
示例如下:
3.2 安装IK分词器 结果焕然一新
为了解决中文词语拆分的问题,可以安装一个IK分词器。IK分词器是一款适合于中文分词习惯的、优秀的中文分词器,具有60万字/秒的高速处理能力。
它支持两种粒度的拆分:
ik_smart:做粗粒度的拆分
ik_max_word:将文本做细粒度的拆分,拆分出尽可能多的词条
1) 解压 自己实操一下
把分词器《elasticsearch-analysis-ik-7.4.0.zip》解压到es的plugins目录下,重命名为“ik”
2) 重启
重启es
重启kibana
3) 测试
在浏览器的kibana开发工具界面,输入并执行
4.使用Postman测试
路径:http://localhost:9200/_analyze
内容:可以先测试一下正常了再自己实操练习
{"text":"2023年5月17号,演示一下postman请求ES,首先在ES里面plugins文件夹里面创建一个文件夹比如“ik”,然后在ik文件夹里面解压ik分词器即可!最后按照如图的格式请求postman请求ES即可","analyzer":"ik_smart" }
5. 安装过程中可能出现的问题
5.1 JDK环境变量问题
ElasticSearch7.4,要求使用jdk8或者jdk11。如果JDK版本不正确,启动es会报错
验证方式:打开cmd,执行
java -version
,看一下JDK版本5.2 端口占用问题
苍穹外卖里内网穿透软件cpolar,占用的是9200端口,会导致使用es出问题
解决方式:
方式一:关掉cpolar或者卸载cpolar,然后重启电脑,再启动es,就没有端口冲突了。es会占用9200端口
方式二:不管它,es发现9200被占用,它会自动改用其它端口。要看一下启动es的控制台,看它的端口是多少 (一般是9201)。
然后Kibana要配置连接ES时的地址,配置成 http://localhost:9201
5.3 操作系统权限问题
你的电脑当前用户权限不足,会导致启动es和Kibana会报错 “operate ... prom...”。解决方法是:
es文件夹和Kibana文件夹都需要设置:
在文件夹上右键-属性-安全-编辑-添加
在弹出的容器里,添加当前计算机用户名(可以在cmd里使用
net user
查看)勾选中这个用户,点击下边的“完全控制”,再确定
三、操作索引
- 理解es的核心概念
- 掌握索引库的CURD
1. ES的核心概念
老版本(es7之前)结构:
Indices----->Type---->document----->field
Database-->Table--->row-------------->column
从es7开始,抛弃了type的概念:
Index(索引库)-->Document(json文档)-->Field(json里的key)
Table------------->Row------------------------->column
MySQL ES 说明 Table Index 索引Index,就是文档的集合,类似数据库表。注意:索引名必须小写 Row Document 文档Document,就是一条数据,类似于数据库表中一行记录。
文档是json格式的
Column Field 字段Field,是json中的字段,类似于数据库中的列column Schema Mapping 映射Mapping,是索引中文档的约束,例如字段类型约束。
类似于数据库的表结构
SQL DSL DSL是ES提供的json格式的请求语句,用来操作ES,实现CURD 2. 操作索引库
2.1 索引库映射mapping
说明
映射mapping:目的是为了给索引的每个Field设置类型(字符串,数字,日期,对象,数组……)
在MySql里,我们在插入一条记录之前,需要提前设置好表里每个每个字段的类型。
而类似的,在ES里,我们需要给每个索引库设置映射信息
参考:Put mapping API | Elasticsearch Guide [7.4] | Elastic
映射类型
常见的mapping属性有:
type:字段的类型,常见的简单类型有
text:可分词的文本字符串。如果是text,需要设置
analyzer
分词器keyword:不分词的文本字符串。某些字符串一旦分词就失去意义了,例如品牌、国家、ip地址等
byte,short,integer,long,double,float等数值
boolean
date日期。ES可以把日期格式化为字符串存储,但是为了节省空间,建议使用long存储毫秒值
object对象。如果是object,需要设置
properties
index:是否创建索引,默认true。如果字段值不参与搜索,要设置为false。比如图片url
analyzer:使用哪种分词器。text类型时需要设置,其它类型的字段不需要设置
properties:字段的子字段。如果字段是object时,需要设置子字段
示例
有如下文档数据,分析该索引库的mapping映射
{"age": 21, #type是integer"weight": 52.1, #type是double"isMarried": false, #type是boolean"info": "ES搜索引擎操作索引", #type是text,analyzer可用ik_smart"email": "zyyny@itcast.cn", #type是keyword"score": [99.1, 99.5, 98.9], #type是double"name": { #type是object"firstName": "云","lastName": "赵"} }#索引库的结构 {"mappings":{"properties":{"age":{"type": "integer"},"weight":{"type": "double","index": false},"isMarrid":{"type": "boolean"},"info":{"type": "text","analyzer": "ik_smart"},"email":{"type": "keyword"},"score":{"type": "double"},"name":{"type": "object","properties":{"firstName":{"type": "keyword"},"lastName":{"type": "keyword"}}}}} }
{"mappings":{"properties":{"id":{"type": "long"},"title":{"type": "text","analyzer": "ik_smart"},"price":{"type": "double"},"picUrl":{"type": "keyword","index": false}}} }
2.2 索引库的CURD
2.2.1 创建索引库
语法
PUT /索引库名 {"mappings":{"properties":{"字段名":{"type": "类型","index": true,"analyzer": "分词器",...},"字段名":{"type": "类型","index": true,"analyzer": "分词器",...},...}} }
示例
#--------如何操作索引库--------- #1.创建索引库 PUT /suoyinku {"mappings": {"properties": {"id":{"type":"integer"},"name":{"type":"text","analyzer": "ik_max_word"},"sex":{"type":"keyword"},"age":{"type":"integer"},"score":{"type":"double"},"avatar":{"type": "keyword","index": false}}} } #2.查询所有索引库 GET /_cat/indices#3.查看库详细信息 GET /suoyinku#4.修改索引库 # 不允许修改已有字段,只能新增字段 PUT /suoyinku/_mapping {"properties":{"email":{"type":"keyword"}} }#5.删除索引库 DELETE /suoyinku #-------------------------------------------------------------------------# 练习,创建索引库itcast。四个字段 商品名称title,商品图片images,商品价格price,品牌brand PUT /itcast {"mappings": {"properties": {"title":{"type": "text","analyzer": "ik_smart"},"images":{"type": "keyword","index": false},"price":{"type": "double"},"brand":{"type": "keyword"}}} }
2.2.2 查看索引库
语法
GET /索引库名 #2.查询所有索引库 GET /_cat/indices #3.查看库详细信息 GET /suoyinku
2.2.3 修改索引库
注意:es里不能修改已有字段,可以给索引库添加字段
因为创建好索引库后,es会构建倒排索引,这个过程是比较消耗性能的。
一旦索引库的某个字段被修改,可能会导致原本的倒排索引失效,影响太大,
所以es不能修改索引库中已有的字段。
语法
PUT /索引库名/_mapping {"properties":{"新字段名":{"type": "类型","index": true,...},"新字段名":{"type": "类型","index": true,...},...} }#4.修改索引库 # 不允许修改已有字段,只能新增字段 PUT /suoyinku/_mapping {"properties":{"email":{"type":"keyword"}} }
2.2.4 删除索引库
语法
DELETE /索引库名#5.删除索引库 DELETE /suoyinku
2.3 练习
要求1:创建一个索引库itcast,用于存储商品信息。要有以下字段:
商品id id
商品名称 title
商品价格 price
所属品牌 brand
商品库存量 quantity
商品图片url地址 images
要求2:查看索引库itcast的信息
要求3:给索引库itcast增加一个字段“商品分类 category”
要求4:删除索引库itcast
3. 小结
ES的一些概念:
Index:索引库,相当于MySQL里的表
Document:文档,一个文档是json格式,相当于MySQL里的一行数据
Field:字段,相当于MySQL里的字段
Mapping:映射,相当于MySQL里的表结构 每个字段的名称、类型、约束等等
DSL:操作ES的语句,相当于MySQL里的SQL语句
操作索引库的DSL命令:
新增:
PUT /索引库名
{
"mappings":{
"properties":{
"字段名":{
"type": "类型",
"analyzer": "分词器",
"index": 是否参与搜索
},
...,
"字段名":{
"type": "类型",
"analyzer": "分词器",
"index": 是否参与搜索
}
}
}
}
查看:
GET /_cat/indices 查询所有索引库
GET /索引库名 查看索引库详细信息
修改:只能新增字段,不能修改已有字段
PUT /索引库名/_mapping
{
"properties":{
"字段名":{
"type": "类型",
"analyzer": "分词器",
"index": 是否参与搜索
},
...,
"字段名":{
"type": "类型",
"analyzer": "分词器",
"index": 是否参与搜索
}
}
}
删除:
DELETE /索引库名
四、操作文档
掌握文档的CURD参考:Document APIs | Elasticsearch Guide [7.4] | Elastic
1. 新增文档
语法:
PUT /索引库名/_doc/[id] {"key": value,..."key": value }------------------------------------------- #id:文档的主键值#示例 ------------------------------------------ #0.查询所有索引库 GET /_cat/indices GET /suoyinku#1.保存一条文档数据: # 如果唯一标识对应数据不存在,是新增 # 如果唯一标识对应的数据存在,是覆盖式修改 PUT /suoyinku/_doc/1 {"id":1,"name":"凉介","age":"26","email":"huiyishi@163.com","sex":"男","avatar":"http//:www.baidu.com/abc.jpg","score":59 }
2. 查看文档
语法
#语法: GET /索引库名/_doc/id#示例: #2.查询文档 GET /suoyinku/_doc/1
3. 删除文档
语法
#语法: DELETE /索引库名/_doc/id值#示例 #3.删除文档 DELETE /suoyinku/_doc/1
4. 修改文档
语法
方式一:全量修改
全量修改操作,会删除旧文档,添加新文档
如果唯一标识对应数据不存在,是新增
PUT /索引库名/_doc/文档id {"字段1": 值1,"字段2": 值2,... }#示例1 #在刚才已删除的基础上 修改 #如果唯一标识对应数据不存在,是新增 #则实际操作的为:新增 PUT /shuoyinku/_doc/1 {"id":1,"name":"凉介","age":"26","email":"huiyishi@163.com","sex":"男","avatar":"http//:www.baidu.com/abc.jpg","score":59 } 结果: {"_index" : "shuoyinku","_type" : "_doc","_id" : "1","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 0,"_primary_term" : 1 }
2.如果唯一标识对应的数据已存在,是覆盖式修改
------------------------------------- #示列2 #在刚才已修改的基础上 唯一标识不存在则是:新增 #如果唯一标识对应的数据已存在,是覆盖式修改 PUT /shuoyinku/_doc/1 {"id":1,"name":"小凉介","age":"26","email":"huiyishi@163.com","sex":"男","avatar":"http//:www.baidu.com/abc.jpg","score":89 } #------------------------------------ #返结果响应:updated {"_index" : "shuoyinku","_type" : "_doc","_id" : "1","_version" : 2,"result" : "updated","_shards" : {"total" : 2,"successful" : 1,"failed" : 0},"_seq_no" : 1,"_primary_term" : 1 }
对比 :
方式二:增量修改
增量修改操作,只修改指定字段值
POST /索引库名/_update/文档id {"doc":{"字段1": 值1,"字段2": 值2,...} } #示例 #方式二: #增量修改文档: #在原始文档基础上修改,不常用 POST /shuoyinku/_update/1 {"doc":{"age":40} }
5. 查询所有文档
语法
#语法: POST /索引库名/_search #示例: POST /shuoyinku/_search
6. 动态映射【拓展了解】
思考
如果新增文档的结构,与mapping结构不一致,会出现什么结果
例如
#插入的文档结构,与mapping结构不符。 #itcast索引库中原本没有color、weight、stock、isSoldOut四个字段 PUT /itcast/_doc/2 {"title": "罗技鼠标","price": 89,"images": "http://www.jd.com/xxxx.jpg","stock": 50,"weight": 0.22,"color": "black","isSoldOut": false }
查询索引的映射:
GET /itcast/_mapping
看到结果
{"itcast" : {"mappings" : {"properties" : {"color" : { #增加了color字段,是字符串。ES无法判断类型,因此存储了两种映射类型。color是text类型,color.keyword是keyword类型"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}},"images" : {"type" : "keyword","index" : false},"isSoldOut" : { #增加了isSoldOut字段,类型boolean"type" : "boolean"},"price" : {"type" : "double"},"stock" : { #增加了stock字段,类型long"type" : "long"},"title" : {"type" : "text","analyzer" : "ik_smart"},"weight" : { #增加了weight字段,类型float"type" : "float"}}}} }
说明
插入文档时,es会检查文档中的字段是否有对应的mapping,如果没有,则按照默认的mapping规则来创建索引。
如果默认的mapping不符合你的要求,一定要自己设置字段的mapping
6. 小结
1. 保存文档
如果唯一标识对应的文档不存在:是新增
如果唯一标识对应的文档已存在:是覆盖式修改,直接把原始文档数据全部覆盖掉
PUT /索引库名/_doc/唯一标识
{
"字段名": 值,
"字段名": 值,
...
"字段名": 值
}
2. 查看文档
GET /索引库名/_doc/唯一标识
3. 增量修改文档,不常用。在原始文档基础上做修改
POST /索引库名/_update/唯一标识
{
"doc":{
"字段名": 值,
"字段名": 值,
...
"字段名": 值
}
}
4. 删除文档:
DELETE /索引库名/_doc/唯一标识
5. 查询所有文档
POST /索引库名/_search
五、RestAPI
1. 准备工作
1.1 创建project导入依赖
导入es的客户端依赖坐标
注意:es客户端依赖的版本号,必须要和es的版本号一致
<dependencies><!--es客户端--><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.4.0</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.8.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.70</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version></dependency> </dependencies>
1.2 创建实体类
商品Product,对应es里的product索引
@Data @NoArgsConstructor @AllArgsConstructor public class Product {private Long id;/**标题*/private String title;/**分类*/private String category;/**品牌*/private String brand;/**价格*/private Double price;/**图片地址*/private String images; }
1.3 RestAPI的使用说明
要想操作es,需要按照如下步骤:
创建RestHighLevelClient对象
使用RestHighLevelClient操作es
关闭RestHighLevelClient
//1. 创建RestHighLevelClient客户端对象。 // 如果连接ES集群,就写多个地址; // 如果是单ES实例,就只写一个地址 RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9201),new HttpHost("localhost", 9202),new HttpHost("localhost", 9203) ));//2. 使用client操作es//3. 关闭client client.close();
2. 操作索引【了解】
2.1 API说明
RestHighLevelClient对象提供了操作索引库的API方法,常用的有:
创建:
restClient.indices()
.create(CreateIndexRequest request, RequestOptions options)
删除:
restClient.indices()
.delete(DeleteIndexRequest request, RequestOptions options)
是否存在:
restClient.indices()
.exists(GetIndexRequest request, RequestOptions options)
以上方法的参数:
CreateIndexRequest
:创建索引库的请求对象
DeleteIndexRequest
:删除索引库的请求对象
GetIndexRequest
:查询索引库的请求对象
RequestOptions
:创建索引库的请求选项,使用固定值RequestOptions
.
DEFAULT
即可注意事项:
使用RestAPI创建索引库非常繁琐,建议在Kibana里使用DSL语句执行操作,而不是用Java代码创建索引库
2.2 使用示例
索引库分析:
要把一条商品信息存储到es,我们要先分析一下对应的索引库及映射该如何编写:
id: 商品id,主键,可以使用long类型
title:商品名称,使用text类型,要分词并构建倒排索引进行搜索
category:商品分类,分类是整体,不进行分词,使用keyword
brand:品牌,和分类类似,不进行分词,使用keyword
price:价格,double类型
images:图片地址,用来展示的字段,不需要构建索引,不参与搜索;index设置为false,使用keyword类型
编辑DSL命令如下:
PUT /product {"mappings":{"properties":{"id":{"type": "long"},"title":{"type": "text","analyzer": "ik_max_word"},"category":{"type": "keyword"},"brand":{"type": "keyword"},"price":{"type": "double"},"images":{"type": "keyword","index": false}}} }
操作示例
准备工作:
/** 使用RestAPI操作ES的步骤:* 创建客户端对象,连接ES* 使用客户端对象,操作ES* 关闭客户端对象,断开连接* API:* 客户端对象:RestHighLevelClient** ctrl+alt+f:把选中的变量提取成为Field成员变量* ctrl+alt+m:把选中的代码提取成为Method成员方法* ctrl+alt+v:所选中的代码提取给一个Variable局部变量*/ public class Demo01Es {private RestHighLevelClient client;@Testpublic void test(){//使用客户端对象,操作ES}@Testpublic void test2(){//使用客户端对象,操作ES}@BeforeEachpublic void init(){//创建客户端对象,连接ESnew RestHighLevelClient(RestClient.builder(new HttpHost("localhost",9200)));}@AfterEachpublic void destroy() throws IOException {//关闭客户端对象,断开连接client.close();} } //@BeforeAll 注解表示在 所有 测试方法执行之前执行一次,并且必须是静态方法。//通常用于初始化测试环境,例如启动一个数据库连接池或者读取测试数据文件。 //@BeforeEach 注解表示在 每个 测试方法执行之前执行一次。方法不能是静态的 。// 通常用于初始化测试数据或者创建被测试对象的实例。
使用RestHighLevelClient操作的示例代码如下:
public class Demo01Index {private RestHighLevelClient client;@Testpublic void testCreateIndex() throws IOException {String json = "{\n" +" \"mappings\":{\n" +" \"properties\":{\n" +" \"id\":{\n" +" \"type\":\"long\"\n" +" },\n" +" \"title\":{\n" +" \"type\":\"text\",\n" +" \"analyzer\":\"ik_max_word\"\n" +" },\n" +" \"category\":{\n" +" \"type\":\"keyword\"\n" +" },\n" +" \"brand\":{\n" +" \"type\":\"keyword\"\n" +" },\n" +" \"price\":{\n" +" \"type\":\"double\"\n" +" },\n" +" \"images\":{\n" +" \"type\":\"keyword\",\n" +" \"index\":false\n" +" }\n" +" }\n" +" }\n" +"}";//创建索引库CreateIndexRequest request = new CreateIndexRequest("product").source(json, XContentType.JSON);client.indices().create(request, RequestOptions.DEFAULT);}@Testpublic void testDeleteIndex() throws IOException {//删除索引库DeleteIndexRequest request = new DeleteIndexRequest("product");client.indices().delete(request, RequestOptions.DEFAULT);}@Testpublic void testExistsIndex() throws IOException {//索引库是否存在GetIndexRequest request = new GetIndexRequest("product");boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);System.out.println(exists);}@BeforeEachpublic void init() {// 创建客户端对象,连接ESclient = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200)));}@AfterEachpublic void destroy() throws IOException {// 关闭客户端对象,断开连接client.close();} }
@BeforeEach和@BeforeAll
//@BeforeAll 注解表示在 所有 测试方法执行之前执行一次,并且必须是静态方法。通常用于初始化测试环境,例如启动一个数据库连接池或者读取测试数据文件。
//@BeforeEach 注解表示在 每个 测试方法执行之前执行一次。方法不能是静态的 。通常用于初始化测试数据或者创建被测试对象的实例。
3. 操作文档【重点】
3.1 API说明
使用Java操作文档,和在kibana里编写DSl非常类似。
只是由Java代码来执行相同的操作
RestHighLevelClient提供了操作文档的API如下:
新增与修改:
client.index(IndexRequest request, RequestOptions options)
查看:
client.get(GetRequest request, RequestOptions options)
删除:
client.delete(DeleteRequest request, RequestOptions options)
批量操作文件:
client.bulk(BulkRequest request,RequestOptions options)
以上方法的参数:
IndexRequest
:新增与修改文档的请求对象
GetRequest
:查询文档的请求对象
DeleteRequest
:删除文档的请求对象
RequestOptions
:请求选项参数,使用固定值RequestOptions.DEFAULT
即可3.2 使用示例
新增或修改
查询:
删除:
完整代码
public class Demo03Document {private RestHighLevelClient client;//新增或修改@Testpublic void testSave() throws IOException {Product product = new Product(2L, "桌子", "家具", "欧斯曼",4500D, "http://images.huawei.com/pro40.jpg");IndexRequest request = new IndexRequest("product").id(product.getId().toString()).source(JSON.toJSONString(product), XContentType.JSON);client.index(request, RequestOptions.DEFAULT);}//查询@Testpublic void testGet() throws IOException {GetRequest request = new GetRequest("product").id("2");//向ES发RESTful请求,得到响应结果。响应结果就是查询结果GetResponse response = client.get(request, RequestOptions.DEFAULT);//从结果里获取_source,得到json格式的字符串String docJson = response.getSourceAsString();//把JSON格式的字符串,还原成JavaBean对象Product product = JSON.parseObject(docJson, Product.class);System.out.println("product = " + product);}@Testpublic void testDelete() throws IOException {//删除DeleteRequest request = new DeleteRequest("product").id("2");client.delete(request, RequestOptions.DEFAULT);}@BeforeEachpublic void init() {//创建客户端对象,连接ESclient = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200)));}@AfterEachpublic void destroy() throws IOException {//关闭客户端对象 ,断开连接client.close();} }
4. 批量操作文档
4.1 说明
批量操作的核心在于将多个普通请求封装在一个批量请求中,一次性发送到服务器,下面仅仅演示批量新增(其他自己尝试)
操作的步骤:
准备BulkRequest对象
把每个文档数据,封装到一个IndexRequest对象里。
把IndexRequest添加到BulkRequest对象中
使用client.bulk(bulkRequest对象, RequestOptions.DEFAULT)
4.2 示例
public class Demo03Document {private RestHighLevelClient client;//批量操作文件@Testpublic void testBulkDocument() throws IOException {ArrayList<Product> list = new ArrayList<>();list.add(new Product(11L, "小米手机", "手机数码", "小米", 3299.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(12L, "锤子手机", "手机数码", "锤子", 3699.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(13L, "联想手机", "手机数码", "联想", 4499.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(14L, "红米手机", "手机数码", "小米", 4299.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(15L, "iPhone X", "手机数码", "苹果", 8299.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(16L, "MacBook pro", "电脑", "苹果", 14999.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(17L, "AirPods", "手机数码", "苹果", 4299.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(18L, "外星人", "电脑", "DELL", 21299.00, "http://image.huawei.com/13123.jpg"));list.add(new Product(19L, "联想小新", "电脑", "联想", 6299.00, "http://image.huawei.com/13123.jpg"));//1.创建一个bulkrequest对象BulkRequest request = new BulkRequest();//2.添加数据for (Product product : list) {//2.1 把一个Product对象,封装到一个IndexRequest对象里IndexRequest indexRequest = new IndexRequest("product").id(product.getId().toString()).source(JSON.toJSONString(product),XContentType.JSON);//把IndesRequest对象添加到BulkRequest对象里面request.add(indexRequest);}client.bulk(request,RequestOptions.DEFAULT);}@BeforeEachpublic void init() {//创建客户端对象,连接ESclient = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200)));}@AfterEachpublic void destroy() throws IOException {//关闭客户端对象 ,断开连接client.close();} }
5. 小结
1. 使用RestHighLevelClient操作ES的统一步骤:
创建RestHighLevelClient对象
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
new HttpHost("ip", 9200)
));
使用RestHighLevelClient操作ES
关闭RestHighLevelClient对象
client.close();2. 操作索引库的API
创建:client.indices().create(CreateIndexRequest request, RequestOptions options);
注意:使用CreateIndexRequest是全类名短的那个
删除:client.indices().delete(DeleteIndexRequest request, RequestOptions options);
是否存在:client.indices().exists(GetIndexRequest reuqest, RequestOptions options);
注意:使用GetIndexRequest是全类名短的那个3. 操作文档的API
保存(新增与修改):client.index(IndexRequest request, RequestOptions options);
查询:client.get(GetRequest request, RequestOptions options);
删除:client.delete(DeleteRequest request, RequestOptions options);
批量操作文件:client.bulk(BulkRequest request, RequestOptions options);
六、练习
需求
执行SQL脚本《资料/tb_hotel.sql》,其中有tb_hotel表,存储了酒店的数据
利用BulkRequest批量将数据库数据导入到索引库中。
步骤
根据数据库表结构,在es里创建对应的索引库
使用Java程序读取MySQL数据,再使用RestHighLevelClient存储到es的索引库里
实现
1. 创建索引库
# 创建酒店索引 PUT /hotel {"mappings": {"properties": {"id":{"type": "long"},"name":{"type": "text","analyzer": "ik_max_word","copy_to": "all"},"address":{"type": "text","analyzer": "ik_smart","copy_to": "all"},"price":{"type": "integer"},"score":{"type": "integer"},"brand":{"type": "keyword","copy_to": "all"},"city":{"type": "keyword","copy_to": "all"},"starName":{"type": "keyword"},"business":{"type": "keyword","copy_to": "all"},"location":{"type": "geo_point"},"pic":{"type": "keyword","index": false},"all":{"type": "text","analyzer": "ik_max_word"}}} }
2. 准备环境
创建一个新的project,执行以下步骤:
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version> </parent><!--全局锁定ES客户端的版本号--> <properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><elasticsearch.version>7.4.0</elasticsearch.version> </properties><dependencies><!--es客户端--><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId></dependency><!-- web起步依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mp和mysql --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.0</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.33</version></dependency><!-- 单元测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!-- json转换 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.70</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency> </dependencies>
配置文件
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql:///es?useSSL=falseusername: rootpassword: root
引导类
@SpringBootApplication @MapperScan("com.esrestapi.mapper") public class HotelApplication {public static void main(String[] args) {SpringApplication.run(HotelApplication.class,args);} }
实体类Hotel
@Data @TableName("tb_hotle") public class Hotel {@TableId(type = IdType.AUTO)private Long id;private String name;private String address;private Integer price;private Integer score;private String brand;private String city;private String starName;private String business;private String longitude;private String latitude;private String pic; }
实体类HotelDoc
@Data @NoArgsConstructor public class HotelDoc {private Long id;private String name;private String address;private Integer price;private Integer score;private String brand;private String city;private String starName;private String business;private String location;private String pic;public HotelDoc(Hotel hotel){this.id = hotel.getId();this.name = hotel.getName();this.address = hotel.getAddress();this.price = hotel.getPrice();this.score = hotel.getScore();this.brand = hotel.getBrand();this.city = hotel.getCity();this.starName = hotel.getStarName();this.business = hotel.getBusiness();this.location = hotel.getLatitude() + ", " + hotel.getLongitude();this.pic = hotel.getPic();} }
HotelMapper
public interface HotelMapper extends BaseMapper<Hotel> { }
3. 批量插入数据
@SpringBootTest public class HotelTest {@Autowiredprivate HotelMapper hotelMapper;@Autowiredprivate RestHighLevelClient esClient;@Testpublic void test() throws IOException {//1. 读取数据库里所有的酒店数据List<Hotel> list = hotelMapper.selectList(null);//2. 循环酒店列表,把每个酒店数据添加到BulkRequest对象里BulkRequest bulkRequest = new BulkRequest();for (Hotel hotel : list) {//把每个Hotel对象转换成对应ES的HotelDoc对象HotelDoc hotelDoc = new HotelDoc(hotel);//创建IndexRequest对象IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc), XContentType.JSON);bulkRequest.add(request);}//3. 执行批量插入esClient.bulk(bulkRequest, RequestOptions.DEFAULT);//4. 关闭连接//client.close();} }
ElasticSearch入门简介、安装ES(安装Kibana和IK分词器)使用 Postman连接ES进行测、ESRestAPI(操作索引CRUD操作文档CRUD)、练习相关推荐
- Docker安装ElasticSerach、ElasticSerachhead、IK分词器及Kibanna步骤(亲测能用)
前言:网上有很多文章描述关于Docker安装ElasticSerach.ElasticSerachhead.IK分词器及Kibanna步骤.流程及注意事项.我试了很多,综合整理出此文,此文中有些地方是 ...
- ES入门学习:ElasticSearch、Kibana、ik分词器的安装、简单使用及SpringBoot集成
前言 es是采用Java语言开发,因此,想要安装运行es需要提前准备好jdk环境,关于linux配置jdk在前文linux配置jdk 本文主要介绍es的安装.kibana的安装和简单使用及ik分词器的 ...
- 服务器安装配置elasticsearch,kibana,IK分词器和拼音分词器,集群搭建教程
docker安装配置elasticsearch,kibana和IK分词器 elasticsearch文章系列 前置安装docker 创建docker网络 安装Elasticsearch 运行elast ...
- [Linux]Linux下安装和配置solr/tomcat/IK分词器 详细实例二.
为了更好的排版, 所以将IK分词器的安装重启了一篇博文, 大家可以接上solr的安装一同查看. [Linux]Linux下安装和配置solr/tomcat/IK分词器 详细实例一: http://w ...
- Linux下安装和配置solr/tomcat/IK分词器 详细实例二.
为了更好的排版, 所以将IK分词器的安装重启了一篇博文, 大家可以接上solr的安装一同查看. [Linux]Linux下安装和配置solr/tomcat/IK分词器 详细实例一: http://w ...
- es安全组端口_从零开始在远程服务器(Linux)上搭建es,eshead和ik分词器
一.资源准备 远程服务器一个(本教程为CentOS 64位) 注:ik分词器版本需与es版本统一 jdk1.8.0 elasticsearch-head-master.zip 二.开放端口 注:本例采 ...
- ElasticSearch学习笔记之十一 Anayle API和IK分词器
ElasticSearch学习笔记之十一 Anayle API和IK分词器 Anayle API IK分词器 IK分词器版本支持 安装 下载或者编译 选择一 选择二 重启ElasticSearch I ...
- ES集群添加IK分词器
ES集群添加IK分词器 ES : 7.5.0 官方文档其实已经够优秀了,毕竟是中文的,这里只给出一些建议. IKAnalyzer.cfg.xml 建议放到插件的目录下,要不然有可能会有一些问题 {pl ...
- Docker 安装 ES 7.7.0 及 Head、Kibana、IK分词器、Logstash、Filebeat 插件
目录 环境信息 ES安装 ElasticSearch-Head安装 IK分词器安装 环境信息 Docker version 1.13.1, build 4ef4b30/1.13.1 CentOS Li ...
最新文章
- 对抗性攻击轻松愚弄人工智能
- RxJava flatMap操作符用法详解
- 《魂斗罗:归来》手游子弹中没中,没你想得那么简单!
- Java项目课程04:需求分析
- web项目里看不到html,在webpack中导入html文件时找不到模块错误
- em,rem,px的实际应用
- 什么是 POD 数据类型
- 怎样用UE4把一个Actor直接打包成Pak
- Jmeter接口测试及接口性能测试
- 18个Windows应该有却没有具有的苦守(2)
- 【Ubuntu】检测内存并压力测试
- 1200PLC学习资料整理
- 品牌连锁店5G/4G无线组网方案
- 怎么批量下载Onedrive分享文件_怎么用PS弄字幕文件 PS批量生成字幕制作教程
- 【C语言】猴子吃桃问题。猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第2天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想……
- 指针:C语言二级指针与二维数组
- 手机运行慢可以刷机吗_智能手机反应慢怎么处理?【详解】
- 效率系列(二) Win10常用快捷键
- 车联网解决方案一DSRC与C-V2X对比
- 知识图谱从入门到应用——知识图谱推理:基于表示学习的知识图谱推理-[嵌入学习]