0


days04-对es分布式搜索引擎进行实战

继上一篇文章的对es的初步了解,接下来对其进行一些实战操作,来加深理解!

一、 索引库操作

1.1 mapping映射属性

mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:- ### 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)- ### 数值:long、integer、short、byte、double、float、- ### 布尔:boolean- ### 日期:date- ### 对象:object

  • index:是否创建索引,默认为true

  • analyzer:使用哪种分词器

  • properties:该字段的子字段

1.2 索引库的CRUD(增删改查)

1.2.1 创建索引库

ES中通过Restful请求操作索引库、文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下:

接下来就在kibana的可视化界面进行一下实战操作:

如果说这次的操作是在上一篇文章以后的话,虚拟机如果关闭了,可以将虚拟机打开了以后,输入以下命令:

  1. syatemctl restart docker //打开docker
  2. docker start es //打开es容器
  3. docker start kibana //打开kibana可视化界面容器
  4. docker ps //查看当前运行的容器

然后我们在浏览器输入http://本地ip:5601/ 进入可视化界面,然后在Dev Tools上进行后面的索引库和文档的CRUD操作:

1.2.2 查看、删除索引库

查看索引库语法:

  1. #GET /索引库名
  2. # 示例
  3. GET /heima

删除索引库语法:

  1. # DELETE /索引库名
  2. # 示例
  3. DELETE /heima

1.2.3 修改索引库

索引库和mapping一旦创建无法修改,不允许对其进行修改,但是可以添加新的字段,语法如下:

!!*** 因为索引库创建完以后mapping映射都会映射好,而es会基于这些映射来创建倒排索引,如果说修改某一个字段,会导致倒排索引失效,所以禁止修改索引库,这与数据库不同,但是在生产阶段,数据库尽量也别修改,会直接影响性能。***

  1. PUT /索引库名/_mapping
  2. {
  3. "properties": {
  4. "新字段名":{ #切记字段名不能和之前原有的重复
  5. "type": "integer"
  6. }
  7. }
  8. }

二、文档操作

2.1 新增文档

新增文档的DSL语法如下:

  1. POST /索引库名/_doc/文档id #文档id如果不写 会自动生成一个id
  2. {
  3. "字段1": "值1",
  4. "字段2": "值2",
  5. "字段3": {
  6. "子属性1": "值3",
  7. "子属性2": "值4"
  8. },
  9. // ...
  10. }
  11. # 示例
  12. POST /heima/_doc/1
  13. {
  14. "info": "黑马程序员Java讲师",
  15. "email": "zy@itcast.cn",
  16. "name": {
  17. "firstName": "云",
  18. "lastName": "赵"
  19. }
  20. }

2.2 查询 删除文档

查询文档语法:

  1. # GET /索引库名/_doc/文档id
  2. # 示例
  3. GET /heima/_doc/1

删除索引库的语法:

  1. # DELETE /索引库名/_doc/文档id
  2. # 示例
  3. DELETE /heima/_doc/1

2.3 修改文档

方式一:全量修改,会删除旧文档,添加新文档

  1. *** ****如果说id存在就是修改,如果说id不存在就是新增!!!!!*
  1. PUT /索引库名/_doc/文档id
  2. {
  3. "字段1": "值1",
  4. "字段2": "值2",
  5. // ... 略
  6. }
  7. # 示例
  8. PUT /heima/_doc/1
  9. {
  10. "info": "黑马程序员高级Java讲师",
  11. "email": "zy@itcast.cn",
  12. "name": {
  13. "firstName": "云",
  14. "lastName": "赵"
  15. }
  16. }

方式二:增量修改,修改指定字段值

  1. POST /索引库名/_update/文档id
  2. {
  3. "doc": {
  4. "字段名": "新的值",
  5. }
  6. }
  7. # 示例
  8. POST /heima/_update/1
  9. {
  10. "doc": {
  11. "email": "ZhaoYun@itcast.cn"
  12. }
  13. }

作为java程序员,需要将es用java代码实现出来,而不是简单地在可视化界面实现,下面就利用到RestClient来实现。

三、 RestClient操作索引库

ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html

接下来通过一个案例来利用RestClient操作索引库

3.1 创建索引库

步骤一:首先导入上面所提供的数据库数据 tb_hotel.sql,然后导入所提供的项目hotel-demo

步骤二:然后可以对数据库的sql语句编写创建索引库,代码如下:

  1. # 酒店的mapping
  2. PUT /hotel
  3. {
  4. "mappings": {
  5. "properties": {
  6. "id":{
  7. "type": "keyword"
  8. },
  9. "name":{
  10. "type": "text",
  11. "analyzer": "ik_max_word"
  12. },
  13. "address":{
  14. "type": "keyword",
  15. "index": false
  16. },
  17. "price":{
  18. "type": "integer"
  19. },
  20. "score":{
  21. "type": "integer"
  22. },
  23. "brand":{
  24. "type": "keyword"
  25. },
  26. "city":{
  27. "type": "keyword"
  28. },
  29. "starName":{
  30. "type": "keyword"
  31. },
  32. "business":{
  33. "type": "keyword"
  34. },
  35. "location":{
  36. "type": "geo_point"
  37. },
  38. "pic":{
  39. "type": "keyword",
  40. "index": false
  41. }
  42. }
  43. }
  44. }

其中需要注意的是,sql中的经纬度字段,在es中有单独的表示类型:

但是如果说用户想要对多个字段进行搜索比如说用过酒店名称搜、商圈搜等等,但是就数据库而言我们可以知道,只对一个字段就行搜索效率会很高,但是在es中如何做到既对多个字段搜索又能提高效率呢?

* 我们把想要参与搜索的字段统一放到“all”的索引中*

可以将上面的mapping映射代码修改为:

  1. # 酒店的mapping
  2. PUT /hotel
  3. {
  4. "mappings": {
  5. "properties": {
  6. "id":{
  7. "type": "keyword"
  8. },
  9. "name":{
  10. "type": "text",
  11. "analyzer": "ik_max_word",
  12. "copy_to": "all"
  13. },
  14. "address":{
  15. "type": "keyword",
  16. "index": false
  17. },
  18. "price":{
  19. "type": "integer"
  20. },
  21. "score":{
  22. "type": "integer"
  23. },
  24. "brand":{
  25. "type": "keyword",
  26. "copy_to": "all"
  27. },
  28. "city":{
  29. "type": "keyword"
  30. },
  31. "starName":{
  32. "type": "keyword"
  33. },
  34. "business":{
  35. "type": "keyword",
  36. "copy_to": "all"
  37. },
  38. "location":{
  39. "type": "geo_point"
  40. },
  41. "pic":{
  42. "type": "keyword",
  43. "index": false
  44. },
  45. "all":{
  46. "type": "text",
  47. "analyzer": "ik_max_word"
  48. }
  49. }
  50. }
  51. }

步骤三 :初始化JavaRestClient

  1. **1. 引入esRestHighLevelClient依赖:**
  1. <dependency>
  2. <groupId>org.elasticsearch.client</groupId>
  3. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  4. </dependency>

** 2. 因为SpringBoot默认的ES版本是7.6.2,所以我们需要覆盖默认的ES版本:**

  1. <properties>
  2. <java.version>1.8</java.version>
  3. <elasticsearch.version>7.12.1</elasticsearch.version>
  4. </properties>

** 3. 初始化RestHighLevelClient:**

可以新建一个测试类然后书写下面的代码:

  1. package cn.itcast.hotel;
  2. import org.apache.http.HttpHost;
  3. import org.elasticsearch.client.RestClient;
  4. import org.elasticsearch.client.RestHighLevelClient;
  5. import org.junit.jupiter.api.AfterEach;
  6. import org.junit.jupiter.api.BeforeEach;
  7. import org.junit.jupiter.api.Test;
  8. import java.io.IOException;
  9. public class HotelIndexTest {
  10. private RestHighLevelClient client;
  11. @Test
  12. void testInit(){
  13. System.out.println(client);
  14. }
  15. @BeforeEach
  16. void setUp(){
  17. this.client=new RestHighLevelClient(RestClient.builder(
  18. //这里改成自己的ip地址
  19. HttpHost.create("http://192.168.229.101:9200")
  20. ));
  21. }
  22. @AfterEach
  23. void tearDown() throws IOException {
  24. this.client.close();
  25. }
  26. }

步骤四:创建索引库

在测试类中新建一个测试方法 **createHotelIndex() **

  1. @Test
  2. void createHotelIndex() throws IOException {
  3. //1. 创建Request 对象
  4. CreateIndexRequest request = new CreateIndexRequest("hotel");
  5. //2. 准备请求的参数:DSL语句
  6. // 其中这个HotelSource是一个常量类,类里面就是之前所写的mapping映射代码,也可以直接复制到这个位置。
  7. request.source(HotelSource, XContentType.JSON);
  8. //3. 发送请求
  9. client.indices().create(request, RequestOptions.DEFAULT);
  10. }

  1. @Test
  2. void createHotelIndex() throws IOException {
  3. //1. 创建Request 对象
  4. CreateIndexRequest request = new CreateIndexRequest("hotel");
  5. //2. 准备请求的参数:DSL语句
  6. request.source(HotelSource, XContentType.JSON);
  7. //3. 发送请求
  8. client.indices().create(request, RequestOptions.DEFAULT);
  9. }

* 需要注意的是,导包一定要到对,不然会报错:*

最后在可视化界面中利用

  1. GET /hotel

查看 如果有结果则说明创建索引库成功!!!

3.2 删除索引库

和创建索引库代码类似,只是调用方法不同。

  1. @Test
  2. void deleteHotelIndex() throws IOException {
  3. //1. 创建Request 对象
  4. DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("hotel");
  5. //2. 发送请求
  6. client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
  7. }

3.3 判断索引库是否存在

  1. @Test
  2. void existHotelIndex() throws IOException {
  3. //1. 创建Request 对象
  4. GetIndexRequest getIndexRequest = new GetIndexRequest("hotel");
  5. //2. 发送请求
  6. boolean exists=client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
  7. //3. 输出是否存在
  8. System.out.println(exists);
  9. }

四、RestClient操作文档

案例:去数据库查询酒店数据,导入到hotel索引库,实现酒店数据的CRUD!

  1. 初始化JavaRestClient (和上面的对索引库操作的初始化代码一样,可以直接复制)
  2. 利用JavaRestClient新增酒店数据
  3. 利用JavaRestClient根据id查询酒店数据
  4. 利用JavaRestClient删除酒店数据
  5. 利用JavaRestClient修改酒店数据

4.1 新增文档

  1. @Autowired
  2. private IHotelService iHotelService;
  3. @Test
  4. void testAddDocument() throws IOException {
  5. // 根据id查询酒店数据
  6. Hotel hotel = iHotelService.getById(61083L);
  7. // 转换为文档类型
  8. HotelDoc hotelDoc = new HotelDoc(hotel);
  9. //1. 准备 Request对象
  10. IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());
  11. //2. 准备Json文档
  12. request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
  13. //3. 发送请求
  14. client.index(request,RequestOptions.DEFAULT);
  15. }

当查询出id=61083的数据以后则说明新增文档成功!!!

4.2 查询文档

  1. @Test
  2. void testGetDocumentById() throws IOException {
  3. //1. 准备Request
  4. GetRequest request = new GetRequest("hotel","61083");
  5. //2. 发送请求,得到相应
  6. GetResponse response = client.get(request, RequestOptions.DEFAULT);
  7. //3. 解析响应结果
  8. String source = response.getSourceAsString();//反序列化 将json对象转化成java对象
  9. System.out.println(source);
  10. }

得到结果如下,说明查询成功:

4.3 删除文档

  1. @Test
  2. void testDeleteDocumentById() throws IOException {
  3. //1. 准备request
  4. DeleteRequest request = new DeleteRequest("hotel","61083");
  5. //发送请求
  6. client.delete(request,RequestOptions.DEFAULT);
  7. }

当出现下面的信息时,说明id=61083的酒店信息删除成功!!

4.4 修改文档

修改文档数据有两种方式:

  • 方式一:全量更新。再次写入id一样的文档,就会删除旧文档,添加新文档(和新增没啥区别)

  • 方式二:局部更新。只更新部分字段,我们演示方式二

  1. @Test
  2. void testUpdateDocumentById() throws IOException{
  3. //1. 创建request对象
  4. UpdateRequest request = new UpdateRequest("hotel","61083");
  5. //2. 准备参数,每2个参数为一对key value
  6. request.doc(
  7. "price","999",
  8. "starName","四钻"
  9. );
  10. //3. 更新文档
  11. client.update(request,RequestOptions.DEFAULT);
  12. }

4.5 批量导入文档

需求:批量查询酒店数据,然后批量导入索引库中

思路:

  1. 利用mybatis-plus查询酒店数据

  2. 将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)

  3. 利用JavaRestClient中的Bulk批处理,实现批量新增文档,示例代码如下:

  1. //批处理
  2. @Test
  3. void testBulkRequest() throws IOException {
  4. //1. 创建Request
  5. BulkRequest request = new BulkRequest();
  6. // 批量查询酒店数据
  7. List<Hotel> hotels = iHotelService.list();
  8. //转换为文档类型的HotelDoc
  9. for(Hotel hotel:hotels) {
  10. HotelDoc hotelDoc = new HotelDoc(hotel);
  11. //创建新增文档的Request对象
  12. //2. 准备参数,添加多个新增的Request
  13. request.add(new IndexRequest("hotel")
  14. .id(hotelDoc.getId().toString())
  15. .source(JSON.toJSONString(hotelDoc),XContentType.JSON));
  16. }
  17. //3. 发送请求
  18. client.bulk(request,RequestOptions.DEFAULT);
  19. }

以上就是对es的简单实践,包括对索引库以及文档的CRUD、最后实现了数据的批处理。内容若有不足,希望大家批评指正,我们一起努力!


本文转载自: https://blog.csdn.net/m0_62025000/article/details/126865310
版权归原作者 在甲蛙海中掘金 所有, 如有侵权,请联系我们删除。

“days04-对es分布式搜索引擎进行实战”的评论:

还没有评论