ElasticSearch - 基于 JavaRestClient 操作索引库和文档

目录

一、RestClient操作索引库

1.1、RestClient是什么?

1.2、JavaRestClient 实现创建、删除索引库

1.2.1、前言

1.2.1、初始化 JavaRestClient

1.2.2、创建索引库

1.2.3、判断索引库是否存在

1.2.4、删除索引库

1.3、JavaRestClient 实现文档的 CRUD

1.3.1、初始化 JavaRestClient 

1.3.2、添加文档(酒店数据)到索引库

1.3.3、根据 id 查询酒店数据

1.3.4、根据 id 修改酒店数据

1.3.5、根据 id 删除文档数据

1.3.6、批量导入文档


一、RestClient操作索引库


1.1、RestClient是什么?

前面我们已经了解了如何利用 DSL 语句去操作 es 的索引库和文档,但作为 java 程序员,将来肯定是要通过 java 代码去操作 es 的,那么想要实现这些,就需要通过 es 官方提供的 RestClient 实现.

RestClient 实际上就是 es 官方提供的各种语言的客户端,他的作用就是帮助我们组装 DSL 语句,然后发送 http 请求给 es 服务器,而我们只需要通过 java 代码将请求发送给客户端,然后客户端就会帮我们来处理剩下的这些事情.

官方文档地址:Elasticsearch Clients | Elastic

1.2、JavaRestClient 实现创建、删除索引库

1.2.1、前言

这里我将以一个 酒店 demo 工程来演示 JavaRestClient 的操作.

具体来讲,这是一个酒店的数据,创建的 sql 如下:

CREATE TABLE `tb_hotel` (`id` bigint(20) NOT NULL COMMENT '酒店id',`name` varchar(255) NOT NULL COMMENT '酒店名称;例:7天酒店',`address` varchar(255) NOT NULL COMMENT '酒店地址;例:航头路',`price` int(10) NOT NULL COMMENT '酒店价格;例:329',`score` int(2) NOT NULL COMMENT '酒店评分;例:45,就是4.5分',`brand` varchar(32) NOT NULL COMMENT '酒店品牌;例:如家',`city` varchar(32) NOT NULL COMMENT '所在城市;例:上海',`star_name` varchar(16) DEFAULT NULL COMMENT '酒店星级,从低到高分别是:1星到5星,1钻到5钻',`business` varchar(255) DEFAULT NULL COMMENT '商圈;例:虹桥',`latitude` varchar(32) NOT NULL COMMENT '纬度;例:31.2497',`longitude` varchar(32) NOT NULL COMMENT '经度;例:120.3925',`pic` varchar(255) DEFAULT NULL COMMENT '酒店图片;例:/img/1.jpg',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

之后我们创建 索引库 的时候,就需要基于上述 sql 数据,来考虑 mapping 约束.

1.2.1、初始化 JavaRestClient

a)引入 es 的 RestHighLevelClient 依赖

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

b)由于 SpringBoot 默认的 ES 版本是 7.6.2,因此这里我们需要覆盖默认的 ES 版本.

在 yml 配置文件中添加如下版本信息即可.

<properties><java.version>1.8</java.version>                    <elasticsearch.version>7.12.1</elasticsearch.version> 
</properties>

c)初始化 RestHighLevelClient.

这里我们创建一个测试类 HotelIndexTest ,用来演示 RestClient 操作的相关方法.

@SpringBootTest
class HotelIndexTest {private RestHighLevelClient client;@BeforeEachpublic void setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http//云服务器ip:9200")//将来如果是集群,这里还可以通过 HttpHost.create 继续连接多个节点));}@AfterEachpublic void tearDown() throws IOException {client.close();}}

1.2.2、创建索引库

这里就需要根据前面提供的表结构来考虑 mapping 该如何建立.

具体的要考虑:字段名、数据类型、是否参与搜索、是否分词、如果分词,分词器是什么?

这里可以先使用 Kibana 来编写.

PUT /hotel 
{"mappings": {"properties": {"id": { // id 按照数据库那边的定义,这里因该类型设置为 long// 但是这里比较特殊,在索引库中 id 比较特殊,将来都是字符串类型.// 又因为 id 将来不做分词处理,因此是 keyword 类型// id 将来肯定要参与 crud ,因此 index 就默认为 true 即可."type": "keyword"},"name": {// 酒店的名字需要搜索和分词."type": "text","analyzer": "ik_max_word", "copy_to": "all"},"address": {// 有时候我们需要根据地址来查询附近的酒店,分词也是有必要的("例如 徐汇龙华西路315弄58号")"type": "text","analyzer": "ik_max_word","copy_to": "all"},"price": {//将来要根据价格范围过滤酒店,所以需要搜索,分词就没必要了."type": "integer"},"score": {//这里就和 price 一样了"type": "integer"},"brand": {//酒店的品牌肯定是不需要分词了,但一定需要参与搜索."type": "keyword","copy_to": "all"},"city": {//城市名字不要分词,但需要参与搜索"type": "keyword","copy_to": "all"},"star_name": {//一星、二星、三星... 分词是没有意义的,组合起来才有意义.//有的人就想住5星酒店,那肯定要参与搜索."type": "keyword"},"business": {//商圈比如: 虹桥、外滩... 这些肯定不需要分词,但一定需要参与搜索."type": "keyword","copy_to": "all"},"pic": {//图片这里就是一个 url 路径,不需要分词,也没有人会搜这个 url//因此就这个 url 就可以当作关键字来处理."type": "keyword","index": false},"location": {//在 es 中有两种特殊的方式,专门来表示地理坐标//"geo_point": 表示地图上的点//"geo_shape": 表示地图上的区域,也就是多个点组成.//那么酒店肯定是属于一个点(毕竟从地球上看,再大的酒店也不过是点)// geo_point 里面由 经度 和 纬度 组成,并且是这两拼在一起组成的字符串"type": "geo_point"},"all": {// 将来 name、address、brand... 这些字段大概率都需要参与搜索// 也就意味着用户输入的的关键字,我们后端都需要根据多个字来搜.// 并且我们可以想象以下 es 作搜索的时候, 根据多个字段去搜索的效率肯定是要比一个字段搜索效率要低//这里对比以下数据库就清楚了.//最重要的是, 我们也希望用户输入名称就能搜到相关的内容, 用户输入品牌也能搜到相关内容...// es 就中有一个字段 "copy_to", 就是将当前字段的值拷贝到指定字段.//这里我们就将需要搜索的字段都拷贝到 all 这个字段中就 ok//这也就实现了在一个字段里, 搜索到多个字段的内容."type": "text","analyzer": "ik_max_word"}}}  
}

自定义 all 字段的解读: 

将来 name、address、brand... 这些字段大概率都需要参与搜索,也就意味着用户输入的的关键字,我们后端都需要根据多个字来搜,并且我们可以想象以下 es 作搜索的时候, 根据多个字段去搜索的效率肯定是要比一个字段搜索效率要低,这里对比以下数据库就清楚了~

最重要的是, 我们也希望用户输入名称就能搜到相关的内容, 用户输入品牌也能搜到相关内容... es 就中有一个字段 "copy_to", 就是将当前字段的值拷贝到指定字段。这里我们就将需要搜索的字段都拷贝到 all 这个字段中就 ok ,实现了在一个字段里, 搜索到多个字段的内容.

而且这里还做了优化,并不是真的吧文档拷贝进去,而是创建索引,将来你去查的时候,是看不到这些字段,但搜却能搜到(类似于根据指针找到数据所在位置).

创建索引库代码如下:

    @Testpublic void testCreateHotelIndex() throws IOException {//1.创建 Request 对象CreateIndexRequest request = new CreateIndexRequest("hotel");//2.编写请求参数(MAPPING_TEMPLATE 是一个静态常量,内容是创建索引库的 DSL 语句)request.source(MAPPING_TEMPLATE, XContentType.JSON);//3.发起请求client.indices().create(request, RequestOptions.DEFAULT);}
  • CreateIndexRequest 的构造参数就是请求创建的索引库的名字.
  • MAPPING_TEMPLATE:是自定义的静态常量,内容是创建索引库的 DSL 语句.
  • client.indices(): 这个方法的返回值是一个对象(indices 是 index 的复数形式),包含了操作索引库的所有方法.
  • RequestOptions.DEFAULT :就表示走默认的方法.

执行以后发现运行成功了~

之后去 Elastic DevTools 上去 GET,就可以看到新增的索引库了~

1.2.3、判断索引库是否存在

判断索引库是否存在代码如下:

    @Testpublic void testExistsHotelIndex() throws IOException {//1.创建 Request 对象GetIndexRequest request = new GetIndexRequest("hotel");//2.发送请求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);System.out.println(exists);}

很多时候,我们先写 client.indices().exists 就可以之间看出需要什么参数

运行以后,可以看到通过了(true 是因为上个案例添加索引库是存在的).

1.2.4、删除索引库

判断删除索引库代码如下:

    @Testpublic void testDeleteHotelIndex() throws IOException {//1.创建 Request 对象DeleteIndexRequest request = new DeleteIndexRequest("hotel");//2.发送请求client.indices().delete(request, RequestOptions.DEFAULT);}

之后再查询就发现查询不到了,表明删除成功.

1.3、JavaRestClient 实现文档的 CRUD

1.3.1、初始化 JavaRestClient 

这里的初始化操作和操作索引库的初始化一样(本质上都是连接 JavaRestClient 客户端).

@SpringBootTest
class HotelDocumentTest {private RestHighLevelClient client;@BeforeEachpublic void setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://云服务器ip:9200")));}@AfterEachpublic void tearDown() throws IOException {client.close();}}

1.3.2、添加文档(酒店数据)到索引库

Ps:操作文档前需要先创建对应索引库

这里我先通过 MyBatis-Puls 从数据库拿到数据,然后添加文档.

实体类如下(这里重写构造方法主要是为了 location 属性(地理位置),将经度,纬度合二为一):

@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();}
}

@NoArgsConstructor:生成无参构造.

编写添加文档代码:

    @Testpublic void testAddDocument() throws IOException {//1.获取酒店数据Hotel hotel = hotelService.getById(5865979L);//2.转化文档(主要是地理位置)HotelDoc hotelDoc = new HotelDoc(hotel);//3.转化为 JSON 格式String hotelJson = objectMapper.writeValueAsString(hotelDoc);//4.构造请求IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());//5.添加请求参数(json 格式)request.source(hotelJson, XContentType.JSON);//6.发送请求client.index(request, RequestOptions.DEFAULT);}

运行后发现通过了

在 Kibana 上查询就可以得到对应的数据

1.3.3、根据 id 查询酒店数据

这里值得注意的是:通过 client.get 查询到的是一个 GetResponse 对象,需要获取里面的原数据.

代码如下:

    @Testpublic void testGetDocument() throws IOException {//1.构造请求GetRequest request = new GetRequest("hotel").id("5865979");//2.发送请求GetResponse response = client.get(request, RequestOptions.DEFAULT);//3.转化成jsonString json = response.getSourceAsString();System.out.println(json);}

运行后就可以得到对应的数据

1.3.4、根据 id 修改酒店数据

修改文档数据有两种方式(之前提到过):

  • 全量更新(就是上面演示的添加文档):再次写入 id 一样的文档,就会删除旧文档,添加新文档.
  • 局部更新(演示这个):只更新部分字段.
    @Testpublic void testUpdateDocument() throws IOException {//1.构造请求UpdateRequest request = new UpdateRequest("hotel", "5865979");//2.填写参数request.doc("name", "地表最强酒店","price", "99999");//3.发送请求client.update(request, RequestOptions.DEFAULT);}

在 Kibana 上通过 GET 查询如下:

1.3.5、根据 id 删除文档数据

删除文档代码如下:

    @Testpublic void testDeleteDocument() throws IOException {//1.构造请求DeleteRequest request = new DeleteRequest("hotel", "5865979");//2.发送请求client.delete(request, RequestOptions.DEFAULT);}

1.3.6、批量导入文档

例如导入酒店的所有数据,代码如下:

    @Testpublic void testBulkDocument() throws IOException {//1.获取酒店所有数据List<Hotel> hotelList = hotelService.list();//2.构造请求BulkRequest request = new BulkRequest();//3.准备参数for(Hotel hotel : hotelList) {//转化为文档(主要是地理位置)HotelDoc hotelDoc = new HotelDoc(hotel);String json = objectMapper.writeValueAsString(hotelDoc);request.add(new IndexRequest("hotel").id(hotel.getId().toString()).source(json, XContentType.JSON));}//4.发送请求client.bulk(request, RequestOptions.DEFAULT);}

运行后可以看到通过了

之后再 Kibana 上随机查询一个酒店数据都是存在的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/91593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构复习重点代码——连载中

前言 本文中使用数据类型时&#xff0c;若无特殊需求&#xff0c;默认都采用int类型。 线性表 顺序表 定义 //静态定义 #define MaxSize 50 typedef struct{int data[MaxSize];//采用数组的形式定义int length; //表示顺序表的长度 }seqList;//动态定义 #define InitSize …

【Git】配置SSH密钥实现Git操作免密

背景 在使用Git推送代码的时候&#xff0c;会默认需要输入密码。如果经常推送代码&#xff0c;那就需要经常输入密码&#xff0c;比较繁琐。所以Git也提供了免密登录的功能。 Git本身支持两种协议对远程Git仓库进行访问&#xff1a;HTTPS、SSH。两种方式有一定的区别&#xf…

GO语言:文件操作之写入文件及iota生成常量

目录标题 一、Writing files 写入文件1. Writing string to a file 写入字符串2. Writing bytes to a file 写入字节3. Writing strings line by line to a file 一行一行写入4. Appending to a file 添加内容5. Writing to file concurrently 并发写入文件 二、iota 常量生成器…

UE学习记录06----根据Actor大小自适应相机位置

背景&#xff1a; staticMesh 会根据业务需要随时变化&#xff0c;然后通过staticMesh的大小自适应相机位置&#xff0c;捕捉画面用来预览该模型&#xff0c;使模型在画布中不会太大导致显示不全&#xff0c;也不会太小 参考&#xff1a; UE实现相机聚焦物体功能_右弦GISer的…

机器学习小白理解之一元线性回归

关于机器学习&#xff0c;百度上一搜一大摞&#xff0c;总之各有各的优劣&#xff0c;有的非常专业&#xff0c;有的看的似懂非懂。我作为一名机器学习的门外汉&#xff0c;为了看懂这些公式和名词真的花了不少时间&#xff0c;还因此去着重学了高数。 不过如果不去看公式&…

Linux中定时任务以及开机自启相关

一.定时任务 1.编辑任务 crontab -e #实际的地址在/var/spool/cron #编写任务 1 * * * * /myproject/sql.sh 2.查询任务 crontab -l 3.Cron表达式 * * * * *&#xff1a;每分钟都运行0 * * * *&#xff1a;每小时的第0分钟运行0 2 * * *&#xff1a;每天凌晨2点运行0 2 *…

WebGL笔记:使用鼠标绘制多个线条应用及绘制动感线性星座

使用鼠标绘制多个线条 多个线条&#xff0c;肯定不是一笔画过的&#xff0c;而是多次画的线条既然是多线&#xff0c;那就需要有个容器来管理它们 1 &#xff09;建立容器对象 建立一个 lineBox 对象&#xff0c;作为承载多边形的容器 // lineBox.js export default class …

记忆化搜索,901. 滑雪

901. 滑雪 - AcWing题库 给定一个 R 行 C 列的矩阵&#xff0c;表示一个矩形网格滑雪场。 矩阵中第 i行第 j 列的点表示滑雪场的第 i 行第 j列区域的高度。 一个人从滑雪场中的某个区域内出发&#xff0c;每次可以向上下左右任意一个方向滑动一个单位距离。 当然&#xff0…

数据结构--栈的实现

数据结构–栈的实现 1.栈的概念和结构&#xff1a; 栈的概念&#xff1a;栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Las…

SpringMVC 学习(三)注解开发

4. 注解开发 4.1 环境搭建 (1) 新建 maven 模块 springmvc-03-annotation (2) 确认依赖 确认方法同 3(2)&#xff0c;手动导入发布依赖见3(11) <!--资源过滤--> <build><resources><resource><directory>src/main/java</directory>&…

PostMan的学习

PostMan的学习 目录 环境变量和全局变量接口关联内置动态参数以及自定义动态参数实现业务闭环Postman断言批量运行collection数据驱动之CSV文件和JSON文件测试必须带请求头的接口Mock Serviers 服务器Cookie鉴权NewmanPostManNewManjenkins实现接口测试持续集成 参考资料&am…

Kerberos常见报错汇总

一.kdb5_util: Password mismatch while reading master key from keyboard 1>.错误复现 2>.错误原因分析 在初始化Kerberos数据库时需要输入密码&#xff0c;2次密码输入不一致就会导致该错误。 3>.解决方案 重新执行"kdb5_util -r YINZHENGJIE.COM create -s…

Mendix中的依赖管理:npm和Maven的应用

序言 在传统java开发项目中&#xff0c;我们可以利用maven来管理jar包依赖&#xff0c;但在mendix项目开发Custom Java Action时&#xff0c;由于目录结构有一些差异&#xff0c;我们需要自行配置。同样的&#xff0c;在mendix项目开发Custom JavaScript Action时&#xff0c;…

数据集笔记:旧金山共享单车OD数据

数据地址&#xff1a;System Data | Bay Wheels | Lyft

使用不同尺寸的传感器拍照时,怎么保证拍出同样视场范围的照片?

1、问题背景 使用竞品机做图像效果对比时&#xff0c;我们通常都会要求拍摄的照片要视场范围一致&#xff0c;这样才具有可比性。之前我会考虑用同样焦距、同样分辨率的设备去拍照对比就可以了&#xff0c;觉得相机的视场范围只由镜头焦距来决定。 但如果对于不同尺寸的传感器…

Spring修炼之旅(3)自动装配与注解开发

一、自动装配说明 1.1概述 自动装配是使用spring满足bean依赖的一种方法 spring会在应用上下文中为某个bean寻找其依赖的bean。 1.2装配机制 Spring中bean有三种装配机制&#xff0c;分别是&#xff1a; 在xml中显式配置&#xff1b; 在java中显式配置&#xff1b; 隐式…

【Java 进阶篇】MySQL 数据控制语言(DCL):管理用户权限

MySQL 是一个强大的关系型数据库管理系统&#xff0c;提供了丰富的功能和选项来管理数据库和用户。数据库管理员&#xff08;DBA&#xff09;通常使用数据控制语言&#xff08;Data Control Language&#xff0c;简称 DCL&#xff09;来管理用户的权限和访问。 本文将详细介绍…

定义现代化实时数据仓库,SelectDB 全新产品形态全面发布

导读&#xff1a;9 月 25 日&#xff0c;2023 飞轮科技产品发布会在线上正式召开&#xff0c;本次产品发布会以 “新内核、新图景” 为主题&#xff0c;飞轮科技 CEO 马如悦全面解析了现代化数据仓库的演进趋势&#xff0c;宣布立足于多云之上的 SelectDB Cloud 云服务全面开放…

数据结构——堆(C语言)

本篇会解决一下几个问题&#xff1a; 1.堆是什么&#xff1f; 2.如何形成一个堆&#xff1f; 3.堆的应用场景 堆是什么&#xff1f; 堆总是一颗完全二叉树堆的某个节点总是不大于或不小于父亲节点 如图&#xff0c;在小堆中&#xff0c;父亲节点总是小于孩子节点的。 如图&a…

华为ensp单臂路由及OSPF实验

单臂路由及OSPF实验 1.1实验背景 在这个实验中&#xff0c;我们模拟了一个复杂的网络环境&#xff0c;该网络环境包括多个子网和交换机。这个实验旨在帮助网络工程师和管理员了解如何配置单臂路由和使用开放最短路径优先&#xff08;OSPF&#xff09;协议来实现不同子网之间的…