实用篇-ES-RestClient操作文档

一、RestClient案例准备

对es概念不熟悉的话,先去看上面的 '实用篇-ES-索引库和文档',不建议基础不牢就直接往下学

ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求来发送给ES。

官方文档地址: https://www.elastic.co/guide/en/elasticsearch/client/index.html

下面就使用java程序进行操作es,不再像上面那样使用浏览器页面进行操作es

在下面会逐步完成一个案例: 下载提供的hotel-demo.zip压缩包,解压后是hotel-demo文件夹,是一个java项目工程文件,按照条件创建索引库,索引库名为hotel,mapping属性根据数据库结构定义。还要下载一个tb_hotel.sql文件,作为数据库数据

hotel-demo.zip下载:https://cowtransfer.com/s/36ac0a9f9d9043
tb_hotel.sql下载: https://cowtransfer.com/s/716f049850a849

第一步: 把tb_hotel.sql文件导入进你的数据库
实用篇-ES-RestClient操作文档_第1张图片

第二步:idea打开解压后的文件

实用篇-ES-RestClient操作文档_第2张图片

第三步:在application.yml中配置正确的信息

实用篇-ES-RestClient操作文档_第3张图片

二、hotel数据结构分析

在es中,mapping要考虑的问题: 字段名、数据类型、是否参与搜索、是否分词、如果分词那么分词器是什么。

我们刚刚在mysql导入了tb_hotel.sql,里面有很多数据,我们需要基于这些数据结构,去分析并尝试编写对应的es的mapping映射

先看mysql中的数据类型(已有),如下

实用篇-ES-RestClient操作文档_第4张图片

根据mysql的数据类型等信息,编写es(没有,自己对着上面的sql写的)。注意经纬度在es里面是geo_point类型,且经纬度是写在一起的

PUT /hotel
{
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "address":{
        "type": "keyword",
        "index":false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword"
      },
       "city":{
        "type": "keyword"
      },
       "starName":{
        "type": "keyword"
      },
       "business":{
        "type": "keyword"
      },
       "location":{
        "type": "geo_point"
      },
      "pic":{
        "type":"keyword",
        "index": false
      }
    }
  }
}

可以看到name,brand,score,city,starName等字段都要参与搜索,也就是用户可能根据多个关键字搜,查询条件是多个值,这时候可以用es提供的copy_to属性,把这些字段都拷贝到这个字段中,就可以实现在一个字段中搜到多个字段的内容了

下面演示把名字(name)、品牌(brand)和商圈(business)三个字段拷贝到all字段,代码如下

PUT /hotel
{
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index":false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
       "city":{
        "type": "keyword"
      },
       "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"
      }
    }
  }
}

三、初始化RestClient

操作主要是在idea的hotel-demo项目进行,hotel-demo项目(不是springcloud项目,只是springboot项目)是前面 '1. RestClient案例准备',跳过的可回去补

第一步: 在hotel-demo项目的pom.xml添加如下


        1.8
        7.12.1




	org.elasticsearch.client
	elasticsearch-rest-high-level-client
	7.12.1

第二步: 在hotel-demo项目的src/test/java/cn.itcast.hotel目录新建HotelIndexTest类,写入如下

package cn.itcast.hotel;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

public class HotelIndexTest {

     private RestHighLevelClient client;

     @Test
     void init(){
          System.out.println(client);
     }

     @BeforeEach
     void setUp(){
          this.client = new RestHighLevelClient(RestClient.builder(
                  //指定你Centos7部署的es的主机地址
                  HttpHost.create("http://192.168.229.129:9200")
          ));
     }

     @AfterEach
     void tearDown() throws IOException {
          this.client.close();
     }

}

运行init方法,可以看到client的信息打印出来,表示初始化成功 

实用篇-ES-RestClient操作文档_第5张图片

四、创建索引库

不是通过kibana的浏览器控制台,通过DSL语句来进行操作es,在es里面创建索引库

而是通过上一节初始化的RestClient对象,在Java里面去操作es,创建es的索引库。根本不需要kibana做中间者

第一步: 在src/main/java/cn.itcast.hotel目录新建constants.HotelConstants类,里面写DSL语句,如下

其中长长的字符串就是我们在前面 '2. hotel数据结构分析' 里面写的。忘了怎么写出来的,可以回去看看

package cn.itcast.hotel.constants;

public class HotelConstants {
     public static final String MAPPING_TAMPLATE = "{\n" +
             "  \"mappings\": {\n" +
             "    \"properties\": {\n" +
             "      \"id\":{\n" +
             "        \"type\": \"keyword\"\n" +
             "      },\n" +
             "      \"name\":{\n" +
             "        \"type\": \"text\",\n" +
             "        \"analyzer\": \"ik_max_word\",\n" +
             "        \"copy_to\": \"all\"\n" +
             "      },\n" +
             "      \"address\":{\n" +
             "        \"type\": \"keyword\",\n" +
             "        \"index\":false\n" +
             "      },\n" +
             "      \"price\":{\n" +
             "        \"type\": \"integer\"\n" +
             "      },\n" +
             "      \"score\":{\n" +
             "        \"type\": \"integer\"\n" +
             "      },\n" +
             "      \"brand\":{\n" +
             "        \"type\": \"keyword\",\n" +
             "        \"copy_to\": \"all\"\n" +
             "      },\n" +
             "       \"city\":{\n" +
             "        \"type\": \"keyword\"\n" +
             "      },\n" +
             "       \"starName\":{\n" +
             "        \"type\": \"keyword\"\n" +
             "      },\n" +
             "       \"business\":{\n" +
             "        \"type\": \"keyword\",\n" +
             "        \"copy_to\": \"all\"\n" +
             "      },\n" +
             "       \"location\":{\n" +
             "        \"type\": \"geo_point\"\n" +
             "      },\n" +
             "      \"pic\":{\n" +
             "        \"type\":\"keyword\",\n" +
             "        \"index\": false\n" +
             "      },\n" +
             "      \"all\":{\n" +
             "        \"type\": \"text\",\n" +
             "        \"analyzer\": \"ik_max_word\"\n" +
             "      }\n" +
             "    }\n" +
             "  }\n" +
             "}";
}

第二步: 在hotel-demo项目的HotelIndexTest类,添加如下

   @Test
     void testCreateHotelIndex() throws IOException {
          //创建Request对象
          CreateIndexRequest request = new CreateIndexRequest("hotel");
          //请求参数,MAPPING_TEMPLATE是静态常量字符串,内容是创建索引库的DSL语句
          request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
          //发起请求
          client.indices().create(request, RequestOptions.DEFAULT);
     }

第三步: 确保下面的服务你都在Centos7里面启动了

systemctl start docker # 启动docker服务
docker restart es #启动elasticsearch容器
docker restart kibana #启动kibana容器

第四步: 验证。运行HotelIndexTest类的testCreateHotelIndex测试方法

实用篇-ES-RestClient操作文档_第6张图片

第五步: 验证,浏览器打开http://192.168.229.129:5601

实用篇-ES-RestClient操作文档_第7张图片

五、删除和判断索引库

1、删除索引库。在hotel-demo项目的HotelIndexTest类,添加如下。然后运行testDeleteHotelIndex方法

 @Test
     void testDeleteHotelIndex() throws IOException {
          DeleteIndexRequest request = new DeleteIndexRequest("hotel");
          client.indices().delete(request,RequestOptions.DEFAULT);
     }

 实用篇-ES-RestClient操作文档_第8张图片

实用篇-ES-RestClient操作文档_第9张图片

2. 判断索引库是否存在,刚才我们已经运行过删除索引库了,现在我们来写一个测试来判断索引库是否存在

@Test
     void testExistsHotelIndex() throws IOException {
          GetIndexRequest request = new GetIndexRequest("hotel");
          boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
          System.err.println(exists?"索引库存在":"索引库不存在");
     }

实用篇-ES-RestClient操作文档_第10张图片

六、新增文档

案例: 去数据库查询酒店数据,把查询到的结果导入到hotel索引库(上一节我们已经创建一个名为hotel的索引库),实现酒店数据的增删改查

简单说就是先去数据查酒店数据,把结果转换成索引库所需要的格式(新增文档的DSL语法)然后写到索引库,然后在索引库对这些酒店数据进行增删改查

第一步:在HotelIndexTest写入如下

package cn.itcast.hotel;

import cn.itcast.hotel.constants.HotelConstants;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
public class HotelIndexTest {

     private RestHighLevelClient client;

     @Autowired
     private IHotelService hotelService;

     @Test
     void init(){
          System.out.println(client);
     }

     @Test
     void testCreateHotelIndex() throws IOException {
          //创建Request对象
          CreateIndexRequest request = new CreateIndexRequest("hotel");
          //请求参数,MAPPING_TEMPLATE是静态常量字符串,内容是创建索引库的DSL语句
          request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
          //发起请求
          client.indices().create(request, RequestOptions.DEFAULT);
     }

     @Test
     void testDeleteHotelIndex() throws IOException {
          DeleteIndexRequest request = new DeleteIndexRequest("hotel");
          client.indices().delete(request,RequestOptions.DEFAULT);
     }

     @Test
     void testExistsHotelIndex() throws IOException {
          GetIndexRequest request = new GetIndexRequest("hotel");
          boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
          System.err.println(exists?"索引库存在":"索引库不存在");
     }


     @BeforeEach
     void setUp(){
          this.client = new RestHighLevelClient(RestClient.builder(
                  //指定你Centos7部署的es的主机地址
                  HttpHost.create("http://192.168.229.129:9200")
          ));
     }

     @AfterEach
     void tearDown() throws IOException {
          this.client.close();
     }

     @Test
     void testAddDocument() throws IOException {
          //根据id查询酒店数据
          //注意数据库中bigint类型对应java中的long类型
          Hotel hotel = hotelService.getById(60223L);
          //转换为文档类型
          HotelDoc hotelDoc = new HotelDoc(hotel);
          //准备Request对象
          IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
          //准备Json文档
          request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
          //发送请求
          client.index(request,RequestOptions.DEFAULT);
     }

}

主要是新增这个方法 

@Test
     void testAddDocument() throws IOException {
          //根据id查询酒店数据
          //注意数据库中bigint类型对应java中的long类型
          Hotel hotel = hotelService.getById(60223L);
          //转换为文档类型
          HotelDoc hotelDoc = new HotelDoc(hotel);
          //准备Request对象
          IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
          //准备Json文档
          request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
          //发送请求
          client.index(request,RequestOptions.DEFAULT);
     }

第二步:文档新增成功,我们去浏览器查询一下 

实用篇-ES-RestClient操作文档_第11张图片

七、查询文档

不管我们学习什么样的文档操作,java中的代码和DSL中的语句非常相似,所以我们可以类比着DSL语句来编写java代码

实用篇-ES-RestClient操作文档_第12张图片

具体操作如下,我们查询刚才添加的id为60223的文档信息

 @Test
     void testGetDocumentById() throws IOException {
          //创建request对象
          GetRequest request = new GetRequest("hotel","60223");
          //发送请求
          GetResponse response = client.get(request,RequestOptions.DEFAULT);
          //解析结果
          String res = response.getSourceAsString();
          System.out.println(res);
     }

实用篇-ES-RestClient操作文档_第13张图片

八、更新文档

实用篇-ES-RestClient操作文档_第14张图片

具体操作,把id为60223的文档信息更新一下,名字和城市

第一步:写入此方法,并运行 

 @Test
     void testUpdateDocumentById() throws IOException {
          //创建Request对象
          UpdateRequest request = new UpdateRequest("hotel","60223");
          //准备参数,每两个参数为一对key value
          request.doc(
                  "name","上海梅赛德斯奔驰文化中心",
                  "city","阿布扎比"
          );
          //更新文档
          client.update(request,RequestOptions.DEFAULT);
     }

第二步:测试是否更新,在浏览器中Get请求

实用篇-ES-RestClient操作文档_第15张图片

 九、删除文档

经过以上类比,我们不难写出删除文档的代码

实用篇-ES-RestClient操作文档_第16张图片

具体操作,删除id为60223的文档信息

@Test
     void testDeleteDocumentById() throws IOException {
          //创建Request对象
          DeleteRequest request = new DeleteRequest("hotel","60223");
          //删除文档
          client.delete(request,RequestOptions.DEFAULT);
     }

 测试如下

实用篇-ES-RestClient操作文档_第17张图片

十、批量导入文档

我们一直都是操作一条id为60223的文档(相当于数据库表的某一行)。我们如何把mysql的更多数据导入进es的索引库(相当于mysql的表)呢,下面就来学习批量把文档导入进索引库

思路:
1、利用mybatis-plus把MySQL中的酒店数据查询出来
2、将查询到的酒店数据转换为文档类型的数据
3、利用RestClient中bulk批处理方法,实现批量新增文档

实用篇-ES-RestClient操作文档_第18张图片

第一步: 在HotelDocumentTest类,添加如下

@Test
     void testBulkRequest() throws IOException {
          //mp查出数据库中所有的信息
          List hotelList = hotelService.list();
          //转化为hotelDoc
          List hotelDocList = hotelList.stream()
                  .map(new Function() {
                       @Override
                       public HotelDoc apply(Hotel hotel) {
                            HotelDoc hotelDoc = new HotelDoc(hotel);
                            return hotelDoc;
                       }
                  }).collect(Collectors.toList());
          //创建Bulk请求
          BulkRequest bulkRequest = new BulkRequest();
          hotelDocList.forEach(hotelDoc -> bulkRequest
                          .add(new IndexRequest("hotel").id(hotelDoc.getId().toString())
                          .source(JSON.toJSONString(hotelDoc),XContentType.JSON)));
          //发送bulk请求
          client.bulk(bulkRequest, RequestOptions.DEFAULT);
     }
}

第二步:浏览器批量查询

实用篇-ES-RestClient操作文档_第19张图片

你可能感兴趣的:(分布式微服务,elasticsearch,大数据,搜索引擎)