详解SpringCloud微服务技术栈:ElasticSearch实践1——RestClient操作索引库与文档

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:详解SpringCloud微服务技术栈:ElasticSearch原理精讲、安装、实践
📚订阅专栏:微服务技术全家桶
希望文章对你们有所帮助

在前面已经学习了如何使用DSL语句去操作ElasticSearch的索引库和文档,现在需要用ES官方提供的RestClient,这个客户端本质就是组装DSL语句,通过http请求发送给ES,从而方便我们使用Java代码进行操作。

导入demo

sql文件和项目工程从网盘下,自行导入:

链接:https://pan.baidu.com/s/1CDgGJGvpSu0-s6bFfLWvVA?pwd=nrx2
提取码:nrx2

在这里插入图片描述
在这里插入图片描述

hotel数据结构分析

mapping映射要考虑的问题:字段名、数据类型、是否参与搜索、是否分词、若分词,分词器选什么?
所以,我们需要针对数据库的字段来做mapping映射:
在这里插入图片描述
这里面的信息在做mapping的时候,主要是要会选择是否要参与搜索、是否分词,这需要根据业务需求来实现,比如用户找酒店的时候肯定不会是搜索酒店的地址,因此酒店地址不应该加入搜索,也不应该分词。

需要注意的是,ES中对地理坐标的描述,并不是字符串也不是数字,它支持了2种坐标数据类型:

geo_point:由维度latitude和精度longitude确定的一个点
geo_shape:有多个geo_point组成的复杂几何图形

容易发现,里面有很多字段存在ES中,将来都要参与搜索,也就意味着当用户输入某个字段的时候需要根据这多个字段来搜,效率肯定不高。
而ES提供了一个功能,能够实现多字段搜索同时效率还高的,即字段拷贝。也就是使用copy_to属性将当前字段拷贝到指定字段,示例:

"all":{
	"type": "text",
	"analyzer": "ik_max_word"
}
"brand":{
	"type": "keyword",
	"copy_to": "all"
}

这样我们就可以把需要搜索的字段全部联合到all里面,即可实现用户输入一个信息,多字段搜索,且效率是会大大提高的。
因此在dev tools中编写DSL代码:

# 酒店索引库及mapping映射
PUT /hotel
{
  "mapping": {
    "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"
      },
      "startName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword",
        "copy_to": "all"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

上面代码没有正式执行,用来做个基础样式,最终创建索引库还是要用ES的java客户端来实现,方便之后简化开发。

RestClient操作索引库

初始化RestClient

1、引入ES的RestHighLevelClient依赖:

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

2、SpringBoot默认的ES版本是7.6.2,因此需要覆盖:
在这里插入图片描述

3、初始化RestHighLevelClient:

public class HotelIndexTest {
    private RestHighLevelClient client;

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

    @BeforeEach //提前完成RestHighLevelClient对象的初始化
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.177.130:9200")
        ));
    }

    @AfterEach //结束后要销毁这个初始化
    void tearDown() throws IOException {
        this.client.close();
    }
}

创建索引库

结合DSL语句会比较好看懂,代码如下:

	@Test
    void createHotelIndex() throws IOException {
        //创建request对象
        CreateIndexRequest request = new CreateIndexRequest("hotel");
        //准备请求的参数,为JSON格式
        request.source(MAPPING_TEMPLATE, XContentType.JSON);
        //发送请求,indices为index复数,可以获得操作索引库的所有对象,默认方式发送
        client.indices().create(request, RequestOptions.DEFAULT);
    }

其中MAPPING_TEMPLATE就是之前的DSL语句,复制过来当作静态常量来存储:
在这里插入图片描述

在DEV TOOLS中输入GET /hotel即可查看是否成功创建:
在这里插入图片描述

删除和判断索引库

其实这个可以自行的去做,也挺容易实现的,毕竟indices已经将所有操作索引库的api都封装好了,按Ctrl+Shift+空格即可查看所有方法。
删除索引库:

	@Test
    void testDeleteIndex() 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.out.println(exists ? "存在" : "不存在");
    }

RestClient操作文档

写一个小demo,去数据库中查询酒店数据,导入到hotel索引库,从而实现酒店数据的CRUD。
需要先进行JavaRestClient的初始化,在之前有代码了,直接CV一下。
而对于文档的操作,不再需要indices了。

新增文档

这里需要用的方法是index,表示新增文档时候创建倒排索引。

	private RestHighLevelClient client;

    @Resource
    private IHotelService hotelService;
    
	@Test
    void testAddDocument() throws IOException {
        //根据id查询酒店
        Hotel hotel = hotelService.getById(61083L);
        /**
         * Hotel对象中的地理位置是分为经度和纬度分别来存的,但是ES中是用geo_point来存的
         * 因此需要先转换为文档类型HotelDoc
         */
        HotelDoc hotelDoc = new HotelDoc(hotel);
        //准备request对象
        IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
        //准备JSON文档,传进去的需要是JSON格式的字符串
        request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);
        //发送请求
        client.index(request, RequestOptions.DEFAULT);
    }

在这里插入图片描述

查询文档

根据id查询到的文档数据是JSON,需要反序列化为java对象:

@Test
    void testGetDocumentById() throws IOException {
        GetRequest request = new GetRequest("hotel", "61083");
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //source里面是这个hotel的相关数据
        String json = response.getSourceAsString();
        //将json反序列化为java对象
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        System.out.println("hotelDoc = " + hotelDoc);
    }

在这里插入图片描述

更新文档

之前讲解了全量更新和局部更新,这里只演示局部更新:

	@Test
    void testUpdateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest("hotel", "61083");
        request.doc(
                "price", "952",
                "starName", "四钻"
        );
        client.update(request, RequestOptions.DEFAULT);
    }

删除文档

	@Test
    void testDeleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("hotel", "61083");
        client.delete(request, RequestOptions.DEFAULT);
    }

再次查询,返回null:
在这里插入图片描述

批量导入文档

之前的新增,都是一次就新增一条数据,现在利用JavaRestClient批量导入酒店数据到ES中。

思路:
1、利用mybatis-plus查询酒店数据
2、将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)
3、利用JavaRestClient中的Bulk批处理,实现批量新增文档

	@Test
    void testBulkRequest() throws IOException {
        //批量查询酒店数据
        List<Hotel> hotels = hotelService.list();
        //创建request
        BulkRequest request = new BulkRequest();
        //将hotels转换成HotelDoc
        for (Hotel hotel : hotels) {
            HotelDoc hotelDoc = new HotelDoc(hotel);
            //准备参数,添加多个新增的request
            request.add(new IndexRequest("hotel")
                    .id(hotelDoc.getId().toString())
                    .source(JSON.toJSONString(hotelDoc), XContentType.JSON)
            );
        }
        //发送请求
        client.bulk(request, RequestOptions.DEFAULT);
    }

在dev tools使用GET /hotel/_search进行批量查询:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布布要成为最负责的男人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值