龙空技术网

使用Java High Level REST Client操作最新版Elasticsearch 7.3.0

软件架构 711

前言:

目前你们对“restfuljava”可能比较关怀,小伙伴们都需要剖析一些“restfuljava”的相关内容。那么小编在网摘上搜集了一些有关“restfuljava””的相关知识,希望我们能喜欢,看官们快快来学习一下吧!

本文假定你已经对Elasticsearch 的基本概念有比较全面的认识,然后演示如何使用Elasticsearch 提供的Java API。

通过官方文档可以得知,现在存在至少三种Java客户端。

1. Transport Client

2. Java High Level REST Client

3. Java Low Level Rest Client

现在Elasticsearch 官方推出Java High Level REST Client,它是基于Java Low Level REST Client的封装,并且API接收参数和返回值和TransportClient是一样的,使得代码迁移变得容易并且支持了RESTful的风格,兼容了这两种客户端的优点。当然缺点是存在的,就是版本的问题。ES的小版本更新非常频繁,在最理想的情况下,客户端的版本要和ES的版本一致(至少主版本号一致),次版本号不一致的话,基本操作也许可以,但是新API就不支持了。

另外,还有Spring Data Elasticsearch 组件,该组件主要是与Spring生态对接,可以在web系统中整合到Spring中使用。目前比较推荐使用官方的高阶、低阶Rest Client,官方维护,比较值得信赖。

下面演示基于Elasticsearch Client提供的Java High Level REST Client来操作Elasticsearch。

1. 首先创建Spring Boot 项目

如下图所示,创建一个普通的Spring Boot 项目。

2. Maven配置

添加elasticsearch-rest-high-level-client依赖包,将以下内容添加到pom.xml文件中。

<dependency>

<groupId>org.elasticsearch.client</groupId>

<artifactId>elasticsearch-rest-high-level-client</artifactId>

<version>7.3.0</version>

</dependency>

elasticsearch-rest-high-level-client还存在依赖关系,High Level Java REST Client依赖于以下工件及其传递依赖性。

org.elasticsearch.client:elasticsearch-rest-clientorg.elasticsearch:elasticsearch

如果使用了parent,那么需要在此定义es版本号,因为spring-boot-start-parent中已经定义了es相关依赖的版本号,high-level-client中的部分依赖会被覆盖成低版本的,导致出现莫名其妙的错误。

如上图所示,Spring Boot的每个发布版本都会规划它所支持的依赖项。实际上,你不用指定这些依赖项的版本号,因为Spring Boot都为你管理好了。当更新Spring Boot时,会相应的更新依赖。

通过代码跟踪方式,跟踪到这个 pom 的 parent,一直到 Spring Boot Dependencies 这个 POM 文件,可以看到如下的版本信息 (部分摘要)。

spring-boot-dependencies pom文件部分截图,其中发现elasticsearch 默认引用版本为 6.4.3,但是本项目中,我们需要引用最新版本的 elasticsearch v7.3.0 相关依赖包。

在本场景下,不希望使用 parent pom。可以在Maven 中的 dependencyManagement 管理所有依赖的版本号。

在 dependencyManagement 元素中声明 jar 包的版本信息,那么子项目再次引用相应 jar 包时则无需指定版本号。Maven 会沿着父子层级向上寻找 dependencyManagement 元素,然后使用其指定的版本号。

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.elasticsearch.client</groupId>

<artifactId>elasticsearch-rest-client</artifactId>

<version>7.3.0</version>

</dependency>

<dependency>

<groupId>org.elasticsearch</groupId>

<artifactId>elasticsearch</artifactId>

<version>7.3.0</version>

</dependency>

</dependencies>

</dependencyManagement>

此时,发现elasticsearch-rest-high-level-client 依赖包都已经更新为正确的版本号 v7.3.0,而不是之前spring boot dependencies 中默认的v6.4.3 版本。

3. application.properties 配置文件

在properties 配置文件中,添加如下参数:

spring.application.name=rest-client-demo

server.port=8088

elasticsearch.host=localhost

elasticsearch.port=9200

设置 ES 的主机地址,以及端口号9200,因为REST client是通过HTTP 和ES 进行交互的,因此port=9200。

4. EsConfig 配置类

添加 High Level REST Client配置。

package com.rickie.elasticsearch.restclientdemo.config;

import lombok.Data;

import org.apache.http.HttpHost;

import org.elasticsearch.client.RestClient;

import org.elasticsearch.client.RestHighLevelClient;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Data

@Configuration

@ConfigurationProperties(prefix = "elasticsearch")

public class EsConfig {

private String host;

private Integer port;

@Bean(destroyMethod = "close")

public RestHighLevelClient client(){

return new RestHighLevelClient(RestClient.builder(

new HttpHost(host, port, "http")

));

}

}

注意:上述代码引用了 lombok 依赖包。

另外,在Spring Boot启动类上加上@EnableConfigurationProperties注解:

@EnableConfigurationProperties({EsConfig.class})

至此,我们的项目框架就搭建完毕了。直接运行,我们可以看到项目已经跑起来了。

5. 开发Elasticsearch 相关的业务代码

项目框架搭建完毕后,我们来尝试着执行一些简单的增删改查操作。

首先,我们构建一个BookService,并且注入RestHighLevelClient。

Index API允许用户将一个类型化的JSON文档索引(插入)到一个特定的索引中,并使其可搜索。

完整代码如下所示。

package com.rickie.elasticsearch.restclientdemo.service;

import com.rickie.elasticsearch.restclientdemo.domain.vo.BookVO;

import org.elasticsearch.action.index.IndexRequest;

import org.elasticsearch.action.index.IndexResponse;

import org.elasticsearch.client.RequestOptions;

import org.elasticsearch.client.RestHighLevelClient;

import org.elasticsearch.common.xcontent.XContentBuilder;

import org.elasticsearch.common.xcontent.XContentFactory;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.io.IOException;

@Service

public class BookService {

@Resource

private RestHighLevelClient client;

public String addBook(BookVO vo) {

try {

XContentBuilder content = XContentFactory.jsonBuilder().startObject()

.field("type", vo.getType())

.field("word_count", vo.getWordCount())

.field("author", vo.getAuthor())

.field("title", vo.getTitle())

.timeField("publish_date", vo.getPublishDate())

.endObject();

IndexRequest request = new IndexRequest("book").source(content);

IndexResponse response = client.index(request, RequestOptions.DEFAULT);

return response.toString();

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

}

BookVo.java 类的代码如下所示。

package com.rickie.elasticsearch.restclientdemo.domain.vo;

import lombok.Data;

@Data

public class BookVO {

private String id;

private String type;

private Integer wordCount;

private String author;

private String title;

private String publishDate;

}

BookController 的代码如下所示。

package com.rickie.elasticsearch.restclientdemo.controller;

import com.rickie.elasticsearch.restclientdemo.domain.vo.BookVO;

import com.rickie.elasticsearch.restclientdemo.service.BookService;

import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

@RestController

@RequestMapping("book")

public class BookController {

@Resource

private BookService bookService;

@PostMapping("add")

public String add(@RequestBody BookVO vo) {

return bookService.addBook(vo);

}

@GetMapping("test")

public String test() {

return "hello rickie";

}

}

演示项目包结构如下图所示。

现在直接项目,通过postman 发送post请求,请求参数如下所示。

输出结果:

IndexResponse[index=book,type=_doc,id=NYLx5WwB19IsZPIN0L3a,version=1,result=created,seqNo=2,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]

IndexResponse中包含了一些我们刚刚创建的文档的信息,并且该文档的id 为 【NYLx5WwB19IsZPIN0L3a】。自动生成的id,长度为20个字符,URL安全,base64编码,GUID,分布式系统并行生成时不可能会发生冲突。

在代码中,我们首先构建出了一个IndexRequest对象,然后为该对象设置了source参数,随后使用我们上面注入的RestHighLevelClient对象,并调用 index() 方法,这样就拿到了对应的Response对象。

source 参数通过XContentBuilder构建是一种推荐的方式。

另外,client.index()方法的第二个参数,我们可以自定义一些请求配置项,比如,我们可以在这里指定一个节点选择器(NodeSelector)来控制哪个节点接收请求。这里,我们直接使用了默认配置 RequestOptions.DEFAULT。

执行三次,下面Elasticsearch中产生的索引数据。

6. 其他对索引文件的操作

(1)Get API

Get API允许根据 id 从索引中获取一个类型化的JSON文档。

(2)Update API

Update API 通过使用脚本或传递部分文档来更新现有文档。

输出结果:UpdateResponse[index=book,type=_doc,id=NIJy5WwB19IsZPINrr0l,version=2,seqNo=4,primaryTerm=1,result=updated,shards=ShardInfo{total=2, successful=1, failures=[]}]

(3)Delete API

Delete API 就是根据ID删除相关的文档。

POST localhost:8088/book/delete/OILI52wB19IsZPIN9b0q

返回结果:DeleteResponse[index=book,type=_doc,id=OILI52wB19IsZPIN9b0q,version=2,result=deleted,shards=ShardInfo{total=2, successful=1, failures=[]}]

(4)Search API

Search API用于搜索文档、聚合分析等等相关操作。

输出结果:

{"took":4,"timed_out":false,"_shards":{"total":6,"successful":6,"skipped":0,"failed":0},"hits":{"total":{"value":1,"relation":"eq"},"max_score":1.7294393,"hits":[{"_index":"book","_type":"_doc","_id":"M4KO42wB19IsZPINAb0E","_score":1.7294393,"_source":{"type":"doc","word_count":300,"author":"rickie","title":"Elasticsearch 7.x","publish_date":"2019-08-31"}}]}}

上述API 的调用,完整演示代码,可以访问github。

标签: #restfuljava