15 Rest高级客户端实践(一):文档索引


1 准备工作

  1. 依赖
<dependencies>
     <dependency>
         <groupId>org.elasticsearch.client</groupId>
         <artifactId>elasticsearch-rest-high-level-client</artifactId>
         <version>7.10.1</version>
     </dependency>
     <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
         <version>1.2.3</version>
     </dependency>
     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.18.16</version>
     </dependency>
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.13.1</version>
     </dependency>
 </dependencies>
  1. 准备索引库
PUT books
{
  "settings": {
    "number_of_shards": 3, 
    "number_of_replicas": 1
  }, 
  "mappings": {
      "properties": {
        "id":{
          "type": "long"
        },
        "title":{
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "language":{
          "type": "keyword"
        },
        "author":{
          "type": "keyword"
        },
        "price":{
          "type": "double"
        },
        "publish_time":{
          "type": "date",
          "format": "yyyy-MM-dd"
        },
        "description":{
          "type": "text",
          "analyzer": "ik_max_word"
        }
      }
    }
  
}

2 前置API介绍

2.1 如何构建高级客户端

@Test
public void buildHighClient() throws IOException {
    // 可见高级客户端的构建也是基于低级客户端构建,可以大胆猜测高级客户端就是对低级客户端的包装
    // 对外暴露的API对使用者来说更加友好
    RestHighLevelClient restHighLevelClient = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http"))
    );
    restHighLevelClient.close();
}

2.2 如何构建json文档(数据)

es,提供了一下几个方式来构建json格式的数据

  1. json格式的字符串
  2. 使用Map,es会自动把他转换成一个json数据
  3. 使用XContentFactory.jsonBuilder来构建json
 /****
     * 直接使用字符串形式
     */
    @Test
    public void testString(){
        // 索引的名字
        IndexRequest request = new IndexRequest("books");
        // 设置文档id, 也可以不设置es会自动生成一个
        request.id("1");
        // String 类型文档
        String json = "{\n" +
                "    \"id\":\"1\",\n" +
                "    \"title\":\"Java编程思想\",\n" +
                "    \"language\":\"java\",\n" +
                "    \"author\":\"Bruce Eckel\",\n" +
                "    \"price\":70.2,\n" +
                "    \"publish_time\":\"2007-10-01\",\n" +
                "    \"description\":\"Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。\"\n" +
                "}";
        request.source(json, XContentType.JSON);

    }

    /****
     * 使用Map构建
     *
     */
    @Test
    public void testMap(){
        // 索引的名字
        IndexRequest request = new IndexRequest("books");
        // 设置文档id, 也可以不设置es会自动生成一个
        request.id("2");
        Map<String,Object> mappings = new HashMap<>();
        mappings.put("id",2L);
        mappings.put("title","Java程序性能优化");
        mappings.put("language","java");
        mappings.put("author","葛一鸣");
        mappings.put("price",45.60f);
        mappings.put("publish_time",new Date());
        mappings.put("description","让你的Java程序更快、更稳定。深入剖析软件设计层面、代码层面、JVM虚拟机层面的优化方法");
        request.source(mappings);
    }

    /****
     * 使用Map构建
     *
     */
    @Test
    public void testXContentBuilder() throws IOException {
        // 索引的名字
        IndexRequest request = new IndexRequest("books");
        // 设置文档id, 也可以不设置es会自动生成一个
        request.id("3");
        XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
        // startObject 构建对象,可以理解为json中的{
        // startArray:构建数组,可以理解为json中的[
        xContentBuilder.startObject();
        xContentBuilder.field("id",3L);
        xContentBuilder.field("title","Python科学计算");
        xContentBuilder.field("language","python");
        xContentBuilder.field("author","张若愚");
        xContentBuilder.field("price",81.40f);
        xContentBuilder.field("publish_time",new Date());
        xContentBuilder.field("description","零基础学python,光盘中作者独家整合开发winPython运行环境,涵盖了Python各个扩展库");
        // endObject 可以理解为json中的}
        xContentBuilder.endObject();
        request.source(xContentBuilder);

    }

3 索引文档

整体步骤:

  1. 构建请求参数:IndexRequest
  2. 执行请求
    • 同步执行
    • 异步执行
  3. 解析响应结果: IndexResponse

3.1 如何构建IndexRequest

必填的参数:

  • 索引库名:
  • 文档id
  • 文档内容:json格式,如何构建上面已经介绍了

几个可选参数:这些都可以对应到es提供的restAPI,可以去翻看前面的RestAPI介绍

  • 超时时间
  • 超时策略
  • 设置路由
  • 设置版本号,版本类型
  • 设置操作类型
// 索引的名字
IndexRequest request = new IndexRequest("books");
// 设置文档id, 也可以不设置es会自动生成一个
request.id("1");
// 设置超时时间
 request.timeout(TimeValue.timeValueSeconds(1L));
 // request.timeout("1s");
 // 设置超时策略
 request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
 // 设置版本
 request.version(1);
 // 设置版本类型
 request.versionType(VersionType.EXTERNAL);
 // 设置操作类型
 //request.opType("create");
 request.opType(DocWriteRequest.OpType.CREATE);

3.2 执行请求

3.2.1 同步执行

同步执行,客户端就会阻塞,直到es服务端返回请求结果。

API:

public class RestHighLevelClient implements Closeable {
 public final IndexResponse index(IndexRequest indexRequest, RequestOptions options)
}
  • 同步执行的时候可能会出现io异常,比如请求超时,客户端会抛出IOException
  • es服务端返回4XX或者5XX错误码的时候,客户端会尝试解析响应报文中的错误信息,并且抛出一个ElasticsearchException
 // 同步执行执行请求
 try {
     IndexResponse response = client.index(request, RequestOptions.DEFAULT);
 } catch (Exception e) {
     e.printStackTrace();
 }
3.2.2 异步执行

异步执行,需要配置一个监听器ActionListener,用于监听es响应结果:

public final Cancellable indexAsync(IndexRequest indexRequest, RequestOptions options, ActionListener<IndexResponse> listener) {
    return performRequestAsyncAndParseEntity(indexRequest, RequestConverters::index, options, IndexResponse::fromXContent, listener,
            emptySet());
}
// 异步执行
client.indexAsync(request, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
    // 执行成功的回调
    @Override
    public void onResponse(IndexResponse indexResponse) {
        
    }
    // 执行失败的回调
    @Override
    public void onFailure(Exception e) {

    }
});

3.3 解析响应结果

   IndexResponse response = client.index(request, RequestOptions.DEFAULT);
  // 响应状态
  RestStatus status = response.status();
  log.info("响应状态: {}",status);
  // 获取文档id
  String id = response.getId();
  // 获取文档索引
  String index = response.getIndex();
  log.info("文档索引库: {}; 文档id: {}",index,id);
  // 获取结果: 枚举值:创建,删除,更新,not find
  // 对于此处来说,只能是创建或者是更新,es当id存在的时候就是执行更新,id不存在就是创建,和restAPI是一样的
  DocWriteResponse.Result result = response.getResult();
  log.info("响应结果: {}",result);
  // 获取分片信息
  ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
  log.info("分片信息: {}",shardInfo);
  // 获取文档版本
  long version = response.getVersion();
  log.info("文档版本号: {}",version);

3.4 完整的一个测试代码

public abstract class BaseTest {

    public static RestHighLevelClient client;

    static {
        client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http"))
        );
    }
}
package study.wyy.esclient.high.document;

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.rest.RestStatus;
import org.junit.Test;
import study.wyy.esclient.high.BaseTest;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wyaoyao
 * @description
 * @date 2021/1/8 16:32
 */
@Slf4j
public class BuildJsonDocumentTest extends BaseTest {

    /****
     * 直接使用字符串形式,测试同步执行,和响应结果的解析
     */
    @Test
    public void testString() throws IOException {
        // 索引的名字
        IndexRequest request = new IndexRequest("books");
        // 设置文档id, 也可以不设置es会自动生成一个
        request.id("1");
        // String 类型文档
        String json = "{\n" +
                "    \"id\":\"1\",\n" +
                "    \"title\":\"Java编程思想\",\n" +
                "    \"language\":\"java\",\n" +
                "    \"author\":\"Bruce Eckel\",\n" +
                "    \"price\":70.2,\n" +
                "    \"publish_time\":\"2007-10-01\",\n" +
                "    \"description\":\"Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。\"\n" +
                "}";
        request.source(json, XContentType.JSON);
        // 设置超时时间
        request.timeout(TimeValue.timeValueSeconds(1L));
        // request.timeout("1s");
        // 设置超时策略
        request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
        // 设置版本
        //request.version(2);
        // 设置版本类型
        //request.versionType(VersionType.EXTERNAL);
        // 设置操作类型
        //request.opType("create");
        request.opType(DocWriteRequest.OpType.CREATE);

        // 同步执行执行请求
        try {
            IndexResponse response = client.index(request, RequestOptions.DEFAULT);
            // 响应状态
            RestStatus status = response.status();
            log.info("响应状态: {}",status);
            // 获取文档id
            String id = response.getId();
            // 获取文档索引
            String index = response.getIndex();
            log.info("文档索引库: {}; 文档id: {}",index,id);
            // 获取结果: 枚举值:创建,删除,更新,not find
            // 对于此处来说,只能是创建或者是更新,es当id存在的时候就是执行更新,id不存在就是创建,和restAPI是一样的
            DocWriteResponse.Result result = response.getResult();
            log.info("响应结果: {}",result);
            // 获取分片信息
            ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
            log.info("分片信息: {}",shardInfo);
            // 获取文档版本
            long version = response.getVersion();
            log.info("文档版本号: {}",version);

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            client.close();
        }

    }

    /****
     * 使用Map构建,并测试异步执行
     *
     */
    public static void testMap(){
        // 索引的名字
        IndexRequest request = new IndexRequest("books");
        // 设置文档id, 也可以不设置es会自动生成一个
        request.id("2");
        Map<String,Object> mappings = new HashMap<>();
        mappings.put("id",2L);
        mappings.put("title","Java程序性能优化");
        mappings.put("language","java");
        mappings.put("author","葛一鸣");
        mappings.put("price",45.60f);
        mappings.put("publish_time",new Date());
        mappings.put("description","让你的Java程序更快、更稳定。深入剖析软件设计层面、代码层面、JVM虚拟机层面的优化方法");
        request.source(mappings);

        // 异步执行
        client.indexAsync(request, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
            // 执行成功的回调
            @Override
            public void onResponse(IndexResponse indexResponse) {
                log.info("成功");

            }
            // 执行失败的回调
            @Override
            public void onFailure(Exception e) {
                log.info("失败");
            }
        });
        
    }

    /****
     * 使用XContentBuilder构建
     *
     */
    @Test
    public void testXContentBuilder() throws IOException {
        // 索引的名字
        IndexRequest request = new IndexRequest("books");
        // 设置文档id, 也可以不设置es会自动生成一个
        request.id("3");
        XContentBuilder xContentBuilder = XContentFactory.jsonBuilder();
        // startObject 构建对象,可以理解为json中的{
        // startArray:构建数组,可以理解为json中的[
        xContentBuilder.startObject();
        xContentBuilder.field("id",3L);
        xContentBuilder.field("title","Python科学计算");
        xContentBuilder.field("language","python");
        xContentBuilder.field("author","张若愚");
        xContentBuilder.field("price",81.40f);
        xContentBuilder.field("publish_time",new Date());
        xContentBuilder.field("description","零基础学python,光盘中作者独家整合开发winPython运行环境,涵盖了Python各个扩展库");
        // endObject 可以理解为json中的}
        xContentBuilder.endObject();
        request.source(xContentBuilder);
        IndexResponse index = client.index(request, RequestOptions.DEFAULT);
        client.close();
    }

    public static void main(String[] args) {
        testMap();
    }

}

响应结果日志打印:

响应状态: CREATED
文档索引库: books; 文档id: 1
响应结果: CREATED
分片信息: ShardInfo{total=2, successful=1, failures=[]}

kibana: 查看是否三个文档已经存在

GET books/_search
{
  "query": {
    "match_all": {}
  }
}
{
  "took" : 12,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "books",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "author" : "葛一鸣",
          "price" : 45.6,
          "publish_time" : "2021-01-11T02:47:27.580Z",
          "description" : "让你的Java程序更快、更稳定。深入剖析软件设计层面、代码层面、JVM虚拟机层面的优化方法",
          "language" : "java",
          "id" : 2,
          "title" : "Java程序性能优化"
        }
      },
      {
        "_index" : "books",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "id" : 3,
          "title" : "Python科学计算",
          "language" : "python",
          "author" : "张若愚",
          "price" : 81.4,
          "publish_time" : "2021-01-11T02:48:05.585Z",
          "description" : "零基础学python,光盘中作者独家整合开发winPython运行环境,涵盖了Python各个扩展库"
        }
      },
      {
        "_index" : "books",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "id" : "1",
          "title" : "Java编程思想",
          "language" : "java",
          "author" : "Bruce Eckel",
          "price" : 70.2,
          "publish_time" : "2007-10-01",
          "description" : "Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。"
        }
      }
    ]
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值