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

news2024/12/23 23:06:54

目录

一、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;

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

    @AfterEach
    public 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 ,实现了在一个字段里, 搜索到多个字段的内容.

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

创建索引库代码如下:

    @Test
    public 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、判断索引库是否存在

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

    @Test
    public 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、删除索引库

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

    @Test
    public 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;

    @BeforeEach
    public void setUp() {
        client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://云服务器ip:9200")
        ));
    }

    @AfterEach
    public 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:生成无参构造.

编写添加文档代码:

    @Test
    public 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 对象,需要获取里面的原数据.

代码如下:

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

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

1.3.4、根据 id 修改酒店数据

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

  • 全量更新:再次写入 id 一样的文档,就会删除旧文档,添加新文档.
  • 局部更新(演示这个):只更新部分字段.
    @Test
    public 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 删除文档数据

删除文档代码如下:

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

1.3.6、批量导入文档

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

    @Test
    public 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.coloradmin.cn/o/1038865.html

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

相关文章

简单理解三极管导通条件(从电压角度考虑)

1、本文仅描述三极管如何使用&#xff0c;不对三极管的原理做讲解。 2、本文内容如有错误&#xff0c;欢迎交流指正。 3、本文仅作为本人学习笔记&#xff0c;部分内容来源于网络、书籍&#xff0c;如涉及侵权&#xff0c;请联系删除。 三极管的分类&#xff1a;NPN型、PNP型。…

2023中国国际缝制设备展,正运动助力智能缝纫设备“更快更准”更智能!

■展会名称&#xff1a; 2023中国国际缝制设备展览会 ■展会日期 2023年9月25日-28日 ■展馆地点 上海新国际博览中心E6馆 ■展位号 E6-N09 正运动技术&#xff0c;作为国内领先的运动控制企业&#xff0c;将于9月25日参展2023中国国际缝制设备展。展会将在上海新国际博…

【校招VIP】专业课考点之进程同步

考点介绍&#xff1a; 进程同步是指在多个进程之间进行协调&#xff0c;以确保它们在访问共享资源时能够正确、有序地执行。其中最常见的同步机制是互斥锁和信号量 专业课考点之进程同步-相关题目及解析内容可点击文章末尾链接查看&#xff01; 一、考点试题 1.从执行状态挂…

商品秒杀系统思路

1、使用CAS乐观锁解决秒杀超卖问题。 一开始使用库存&#xff0c;但是发现库存&#xff0c;结果发现没卖完。然后就通过CAS判断库存大于0。 2、又发现问题&#xff0c;一个用户可以下好几单&#xff0c;所以想到用商品id和用户id做个唯一索引&#xff0c;解决了&#xff0c;但…

【剑指Offer】76.删除链表中重复的结点

题目 在一个排序的链表中&#xff0c;存在重复的结点&#xff0c;请删除该链表中重复的结点&#xff0c;重复的结点不保留&#xff0c;返回链表头指针。 例如&#xff0c;链表 1->2->3->3->4->4->5 处理后为 1->2->5 数据范围&#xff1a;链表长度满…

二、浏览器--事件循环(也叫事件环,也叫event loop)--任务队列(等待执行的任务(存放的定时器,http,事件等进程))--渲染三者的关系

引用B站视频&#xff0c;搜索标题&#xff1a;【事件循环】【前端】事件原理讲解&#xff0c;超级硬核&#xff0c;忍不住转载 本视频总结&#xff1a; 超级复杂的JS底层。事件循环和事件队列的关系。宏任务、微任务和raf回调这3个事件队列的关系。任务队列和执行栈的关系。d…

LeetCode 第113 双周赛补题

使数组成为递增数组的最少右移次数3 class Solution { public:int minimumRightShifts(vector<int>& nums) {int n nums.size();int j -1;for (int i 0;i < nums.size()-1;i ) {if (nums[i1] < nums[i]) {j i1;break;}}int k j1;if (j -1) return 0;for…

Vue 05 MVVM模型

MVVM模型 M&#xff1a;模型(Model) &#xff1a;data中的数据V&#xff1a;视图(View) &#xff1a;模板代码VM&#xff1a;视图模型(ViewModel)&#xff1a;Vue实例 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>理…

accesskey_tools AWS红队利用工具:强大的云安全评估和渗透测试工具

一、简介 accesskey_tools是一款专为云环境渗透设计的红队利用工具。本文将介绍accesskey_tools的功能和用途&#xff0c;并探索其在安全评估和渗透测试中的价值和实际应用。 二、工具下载 【点击下载工具】 三、安装依赖 cd aws/aliyun/tencentcloud #进入相应的云服务平…

MySQL数据库描述以及安装使用

一&#xff1a;数据库介绍 数据库 数据库就是用来存储数据的一种特殊文件。 数据库类别 数据库主要分为两种&#xff1a; 关系型数据库RDBMS 非关系型数据库 关系型数据库的主要产品&#xff1a; oracle&#xff1a;在以前的大型项目中使用,银行,电信等项目 mysql&#xff1a;…

工业通讯Modbus简介(一)

写在前面&#xff1a; 昨日雨&#xff0c;在床上睡觉许久&#xff0c;放空身体精神。至傍晚&#xff0c;雨仍淅淅沥沥&#xff0c;拆半年前行李&#xff0c;取煮水锅&#xff0c;欲食火锅。与老王一起&#xff0c;美哉。 今日团建&#xff0c;我队共10个老铁&#xff0c;拔河获…

ES6-匿名函数

匿名函数 没有名字的函数&#xff0c;无法直接使用。 使用方式&#xff1a; 1&#xff09;函数表达式 将匿名函数赋值给一个变量&#xff0c;并且通过变量名称进行调用&#xff0c;我们将这个称为函数表达式 let fn function () {console.log(我是函数表达式)} console.l…

Linux:冯诺依曼系统和操作系统的概念

文章目录 冯诺依曼体系结构冯诺依曼体系的理解 操作系统操作系统的基本定位操作系统的理解1 操作系统的理解2总结 本篇主要总结的是操作系统的基本认知和一些概念 冯诺依曼体系结构 那么上图表示的就是冯诺依曼体系结构&#xff0c;那这个体系结构是什么&#xff1f;为什么要先…

【从0学习Solidity】28. Hash函数解析

【从0学习Solidity】28. Hash函数解析 博主简介&#xff1a;不写代码没饭吃&#xff0c;一名全栈领域的创作者&#xff0c;专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构&#xff0c;分享一些项目实战经验以及前沿技术的见解。关注我们的主页&#xff0c;探索…

Purple-Pi-OH Linux SDK编译手册

一、 SDK下载 1.1 源码下载 在官网下载Purple-Pi-OH的的相关资料以及Linux SDK&#xff1a; 链接&#xff1a;Purple Pi OH-深圳触觉智能科技有限公司 1.2 源码解压 由于SDK打包后体积较大&#xff0c;我们在上传到百度云盘前把SDK包按照4GB大小分割了&#xff0c;因此下载…

【LRU缓存机制】+ 双向链表一些基础操作

文章目录 Tag题目来源题目解读解题方法方法一&#xff1a;哈希表双向链表 知识回顾双向链表的几个基本操作 写在最后 Tag 【哈希表】【双向链表】【设计数据结构】【2023-09-24】 题目来源 146. LRU 缓存 题目解读 LRU 是Least Recently Used的缩写&#xff0c;即最近最少使…

C语言每日一题(4):打印二进制的奇数位和小数位

文章主题&#xff1a;打印二进制的奇数位和小数位&#x1f525;所属专栏&#xff1a;C语言每日一题&#x1f4d7;作者简介&#xff1a;每天不定时更新C语言的小白一枚&#xff0c;记录分享自己每天的所思所想&#x1f604;&#x1f3b6;个人主页&#xff1a;[₽]的个人主页&…

干洗店收银管理软件,洗鞋店收银系统干洗app

干洗店收银管理软件&#xff0c;洗鞋店收银系统干洗app&#xff0c;支持上门取衣服干洗&#xff0c;在手机上下单&#xff0c;预约合适的时间&#xff0c;就会有专员来上门取&#xff0c;当然&#xff0c;送衣服务也是有的&#xff0c;一些价格都标注清楚&#xff0c;有更多的参…

YOLOv5改进系列(24)——替换主干网络之MobileViTv3(移动端轻量化网络的进一步升级)

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制 YOLOv5改进系列(2)——添加CBAM注意力机制

Stellar Toolkit for MySQL 9.0 Crack 3in1

面向数据库管理员的 MySQL 工具包 Stellar Toolkit for MySQL是一款三合一软件套件&#xff0c;用于修复损坏的 MySQL 和 MariaDB 数据库、从 MySQL 数据库的 InnoDB 和 MyISAM 表恢复数据以及分析 MySQL 数据库日志文件。该软件还可以以最高的安全性和完整性相互转换 MySQL/Ma…