导入数据

CREATE TABLE tb_hotel (
id bigint(20) NOT NULL COMMENT ‘酒店id’,
name varchar(255) NOT NULL COMMENT ‘酒店名称;例:7天酒店’,
address varchar(255) NOT NULL COMMENT ‘酒店地址;例:航头路’,
price int(10) NOT NULL COMMENT ‘酒店价格;例:329’,
score int(2) NOT NULL COMMENT ‘酒店评分;例:45,就是4.5分’,
brand varchar(32) NOT NULL COMMENT ‘酒店品牌;例:如家’,
city varchar(32) NOT NULL COMMENT ‘所在城市;例:上海’,
star_name varchar(16) DEFAULT NULL COMMENT ‘酒店星级,从低到高分别是:1星到5星,1钻到5钻’,
business varchar(255) DEFAULT NULL COMMENT ‘商圈;例:虹桥’,
latitude varchar(32) NOT NULL COMMENT ‘纬度;例:31.2497’,
longitude varchar(32) NOT NULL COMMENT ‘经度;例:120.3925’,
pic varchar(255) DEFAULT NULL COMMENT ‘酒店图片;例:/img/1.jpg’,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

酒店数据的索引库结构:


{
“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”,
“copy_to”: “all”
},
“starName”:{
“type”: “keyword”
},
“business”:{
“type”: “keyword”
},
“location”:{
“type”: “geo_point”
},
“pic”:{
“type”: “keyword”,
“index”: false
},
“all”:{
“type”: “text”,
“analyzer”: “ik_max_word”
}
}
}
}
几个特殊字段说明:

  • location:地理坐标,里面包含精度、纬度
  • all:一个组合字段,其目的是将多字段的值 利用copy_to合并,提供给用户搜索

为了单元测试方便

我们创建一个测试类HotelIndexTest,然后将初始化的代码编写在@BeforeEach方法中:
package cn.itcast.hotel;

import org.apache.http.HttpHost;
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;

  1. @BeforeEach<br /> void setUp() {<br /> this.client = new RestHighLevelClient(RestClient.builder(<br /> HttpHost.create("http://192.168.94.129:9200")<br /> ));<br /> }
  2. @AfterEach<br /> void tearDown() throws IOException {<br /> this.client.close();<br /> }<br />}

在hotel-demo的cn.itcast.hotel.constants包下

创建一个类,定义mapping映射的JSON字符串常量:
package cn.itcast.hotel.constants;

public class HotelConstants {
public static final String MAPPING_TEMPLATE = “{\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” +
“ \”copy_to\”: \”all\”\n” +
“ },\n” +
“ \”starName\”:{\n” +
“ \”type\”: \”keyword\”\n” +
“ },\n” +
“ \”business\”:{\n” +
“ \”type\”: \”keyword\”\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 createHotelIndex() throws IOException {
// 1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest(“hotel”);
// 2.准备请求的参数:DSL语句
request.source(MAPPING_TEMPLATE, XContentType.JSON);
// 3.发送请求
client.indices().create(request, RequestOptions.DEFAULT);
}

在hotel-demo中的HotelIndexTest测试类中,

编写单元测试,实现删除索引:
@Test
void testDeleteHotelIndex() throws IOException {
// 1.创建Request对象
DeleteIndexRequest request = new DeleteIndexRequest(“hotel”);
// 2.发送请求
client.indices().delete(request, RequestOptions.DEFAULT);
}

判断索引库是否存在

@Test
void testExistsHotelIndex() throws IOException {
// 1.创建Request对象
GetIndexRequest request = new GetIndexRequest(“hotel”);
// 2.发送请求
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
// 3.输出
System.err.println(exists ? “索引库已经存在!” : “索引库不存在!”);
}

为了与索引库操作分离,

我们再次参加一个测试类,做两件事情:

  • 初始化RestHighLevelClient
  • 我们的酒店数据在数据库,需要利用IHotelService去查询,所以注入这个接口


package cn.itcast.hotel;

import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.service.IHotelService;
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.test.context.SpringBootTest;

import java.io.IOException;
import java.util.List;

@SpringBootTest
public class HotelDocumentTest {
@Autowired
private IHotelService hotelService;

  1. private RestHighLevelClient client;
  2. @BeforeEach<br /> void setUp() {<br /> this.client = new RestHighLevelClient(RestClient.builder(<br /> HttpHost.create("http://192.168.150.101:9200")<br /> ));<br /> }
  3. @AfterEach<br /> void tearDown() throws IOException {<br /> this.client.close();<br /> }<br />}

数据库查询后的结果是一个Hotel类型的对象。

结构如下:

@Data
@TableName(“tb_hotel”)
public class Hotel {
@TableId(type = IdType.INPUT)
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String longitude;
private String latitude;
private String pic;
}
与我们的索引库结构存在差异:

  • longitude和latitude需要合并为location

因此,我们需要定义一个新的类型,与索引库结构吻合:
package cn.itcast.hotel.pojo;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class HotelDoc {
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String location;
private String pic;

  1. public HotelDoc(Hotel hotel) {<br /> this.id = hotel.getId();<br /> this.name = hotel.getName();<br /> this.address = hotel.getAddress();<br /> this.price = hotel.getPrice();<br /> this.score = hotel.getScore();<br /> this.brand = hotel.getBrand();<br /> this.city = hotel.getCity();<br /> this.starName = hotel.getStarName();<br /> this.business = hotel.getBusiness();<br /> this.location = hotel.getLatitude() + ", " + hotel.getLongitude();<br /> this.pic = hotel.getPic();<br /> }<br />}

我们导入酒店数据,基本流程一致,

但是需要考虑几点变化:

  • 酒店数据来自于数据库,我们需要先查询出来,得到hotel对象
  • hotel对象需要转为HotelDoc对象
  • HotelDoc需要序列化为json格式

因此,代码整体步骤如下:

  • 1)根据id查询酒店数据Hotel
  • 2)将Hotel封装为HotelDoc
  • 3)将HotelDoc序列化为JSON
  • 4)创建IndexRequest,指定索引库名和id
  • 5)准备请求参数,也就是JSON文档
  • 6)发送请求

在hotel-demo的HotelDocumentTest测试类中,编写单元测试:
@Test
void testAddDocument() throws IOException {
// 1.根据id查询酒店数据
Hotel hotel = hotelService.getById(61083L);
// 2.转换为文档类型
HotelDoc hotelDoc = new HotelDoc(hotel);
// 3.将HotelDoc转json
String json = JSON.toJSONString(hotelDoc);

  1. // 1.准备Request对象<br /> IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());<br /> // 2.准备Json文档<br /> request.source(json, XContentType.JSON);<br /> // 3.发送请求<br /> client.index(request, RequestOptions.DEFAULT);<br />}

在hotel-demo的HotelDocumentTest测试类中,

编写单元测试:
@Test
void testGetDocumentById() throws IOException {
// 1.准备Request
GetRequest request = new GetRequest(“hotel”, “61082”);
// 2.发送请求,得到响应
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.解析响应结果
String json = response.getSourceAsString();

  1. HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);<br /> System.out.println(hotelDoc);<br />}

在hotel-demo的HotelDocumentTest测试类中,

编写单元测试:
@Test
void testDeleteDocument() throws IOException {
// 1.准备Request
DeleteRequest request = new DeleteRequest(“hotel”, “61083”);
// 2.发送请求
client.delete(request, RequestOptions.DEFAULT);
}

在hotel-demo的HotelDocumentTest测试类中,

编写单元测试:

@Test
void testUpdateDocument() throws IOException {
// 1.准备Request
UpdateRequest request = new UpdateRequest(“hotel”, “61083”);
// 2.准备请求参数
request.doc(
“price”, “952”,
“starName”, “四钻”
);
// 3.发送请求
client.update(request, RequestOptions.DEFAULT);
}

在hotel-demo的HotelDocumentTest测试类中,

编写单元测试:

@Test
void testBulkRequest() throws IOException {
// 批量查询酒店数据
List hotels = hotelService.list();

  1. // 1.创建Request<br /> BulkRequest request = new BulkRequest();<br /> // 2.准备参数,添加多个新增的Request<br /> for (Hotel hotel : hotels) {<br /> // 2.1.转换为文档类型HotelDoc<br /> HotelDoc hotelDoc = new HotelDoc(hotel);<br /> // 2.2.创建新增文档的Request对象<br /> request.add(new IndexRequest("hotel")<br /> .id(hotelDoc.getId().toString())<br /> .source(JSON.toJSONString(hotelDoc), XContentType.JSON));<br /> }<br /> // 3.发送请求<br /> client.bulk(request, RequestOptions.DEFAULT);<br />}