- 导入数据
- 酒店数据的索引库结构:
- 为了单元测试方便
- 在hotel-demo的cn.itcast.hotel.constants包下
- 在hotel-demo中的HotelIndexTest测试类中,
- 在hotel-demo中的HotelIndexTest测试类中,
- 判断索引库是否存在
- 为了与索引库操作分离,
- 数据库查询后的结果是一个Hotel类型的对象。
- 我们导入酒店数据,基本流程一致,
- 在hotel-demo的HotelDocumentTest测试类中,
- 在hotel-demo的HotelDocumentTest测试类中,
- 在hotel-demo的HotelDocumentTest测试类中,
- 在hotel-demo的HotelDocumentTest测试类中,
导入数据
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;
@BeforeEach<br /> void setUp() {<br /> this.client = new RestHighLevelClient(RestClient.builder(<br /> HttpHost.create("http://192.168.94.129:9200")<br /> ));<br /> }
@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;
private RestHighLevelClient client;
@BeforeEach<br /> void setUp() {<br /> this.client = new RestHighLevelClient(RestClient.builder(<br /> HttpHost.create("http://192.168.150.101:9200")<br /> ));<br /> }
@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;
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.准备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();
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
// 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 />}