EslaticSearch-RestAPI详解
简介
ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。
官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high.html
其中的Java Rest Client包括两种:
- Java Low Level Rest Client
- Java High Level Rest Client
下面使用Java HighLevel Rest Client客户端API演示
添加配置文件:
映射分析
创建索引库,关键是要考虑映射,信息包括:字段名、数据类型、是否参与搜索、是否分词、是否分词
- 字段名、字段数据类型,可以参考数据表结构的名称和类型
- 是否参与搜索要分析业务来判断,例如图片地址,就无需参与搜索
- 是否分词呢要看内容,内容如果是一个整体就无需分词,反之则要分词
- 分词器,我们可以统一使用ik_max_word
创建索引库
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",
"copy_to": "all"
},
"startName":{
"type": "keyword",
"copy_to": "all"
},
"business":{
"type": "keyword"
},
"location":{
"type": "geo_point"
},
"pic":{
"type": "keyword",
"index": false
},
"all":{
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
几个特殊字段说明:
-
location:地理坐标,里面包含精度、纬度
-
all:一个组合字段,其目的是将多字段的值 利用copy_to合并,提供给用户搜索
copy_to 属性:
将当前字段拷贝到指定字段中
"all":{
"type": "text",
"analyzer": "ik_max_word"
},
"brand": {
"type": "keywod",
"copy_to": "all"
}
索引库操作的基本步骤:
- 初始化
RestHighLevelClient
- 创建
XxxIndexRequest
。XXX是Get、Create、Delete - 准备参数(Create需要)
- 发送请求。调用
RestHighLevelClient.indices().xxx()
方法,xxx是exists、create、delete
连接es
@SpringBootTest
public class HotelDocumentTest {
private RestHighLevelClient client;
@BeforeEach
public void init() {
client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("192.168.248.128", 9200, "http")));
}
@AfterEach
void closeClient() throws IOException {
client.close();
}
}
操作索引库
索引库,在kibana中创建
判断索引库是否存在
@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 ? "索引库已经存在!" : "索引库不存在!");
}
删除索引库
@Test
void testDeleteHotelIndex() throws IOException {
// 1.创建Request对象
DeleteIndexRequest request = new DeleteIndexRequest("hotel");
// 2.发送请求
client.indices().delete(request, RequestOptions.DEFAULT);
}
创建索引库
@Test
void createHotelIndex() throws IOException {
// 1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest("hotel");
// 2.准备请求的参数:DSL语句
request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
// 3.发送请求
client.indices().create(request, RequestOptions.DEFAULT);
}
操作文档
测试类
- 初始化RestHighLevelClient
- 我们的酒店数据在数据库,需要利用HotelMapper去查询,所以注入这个接口
数据库查询后的结果是一个Hotel类型的对象,与索引库结构存在差异:longitude和latitude需要合并为location
@SpringBootTest
public class HotelDocumentTest {
@Autowired
private HotelMapper hotelMapper;
private RestHighLevelClient client;
@BeforeEach
public void init() {
client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("192.168.136.134", 9200, "http")));
}
@AfterEach
void closeClient() throws IOException {
client.close();
}
}
实体类
MySQL:
@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;
}
ES:
@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;
private Object distance; // 排序结果显示距离值
private Boolean isAD; // 广告标记
public HotelDoc(Hotel hotel) {
this.id = hotel.getId();
this.name = hotel.getName();
this.address = hotel.getAddress();
this.price = hotel.getPrice();
this.score = hotel.getScore();
this.brand = hotel.getBrand();
this.city = hotel.getCity();
this.starName = hotel.getStarName();
this.business = hotel.getBusiness();
this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
this.pic = hotel.getPic();
}
}
文档操作的基本步骤:
- 初始化
RestHighLevelClient
- 创建
XxxRequest
。XXX是Index、Get、Update、Delete、Bulk - 准备参数(Index、Update、Bulk时需要)
- 发送请求。调用
RestHighLevelClient..xxx()
方法,xxx是index、get、update、delete、bulk - 解析结果(Get时需要)
新增文档
需要注意的是:
- 酒店数据来自于数据库,我们需要先查询出来,得到hotel对象
- hotel对象需要转为HotelDoc对象
- HotelDoc需要序列化为json格式
//添加文档
@Test
public void testAddDocument() throws Exception {
//1 准备文档数据
// 1-1 根据id查询酒店数据
Hotel hotel = hotelMapper.selectById(61083L);
// 1-2 转为文档实体类型
HotelDoc hotelDoc = new HotelDoc(hotel);
// 1-3 将hotelDoc转为json
String json = JSON.toJSONString(hotelDoc);
//2 创建request
IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
request.source(json, XContentType.JSON);
//3 发送请求
client.index(request, RequestOptions.DEFAULT);
}
查询文档
查询结果是一个JSON,其中文档放在一个_source
属性中,因此解析就是拿到_source
,反序列化为Java对象即可
//根据id查询文档
@Test
public void testGetDocumentById()throws Exception{
// 1.创建request
GetRequest request = new GetRequest("hotel", "61083");
// 2.发送请求,得到响应
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.解析响应
String json = response.getSourceAsString();
// 4.json转为hotelDoc
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
修改文档
//根据id修改指定文档
@Test
public void testUpdateDocument() throws Exception {
// 1.创建request
UpdateRequest request = new UpdateRequest("hotel", "61083");
//2. 设置更新内容
Map<String, Object> map = new HashMap<>();
map.put("price", 339);
map.put("starName", "四钻");
request.doc(map);
// 3.发送请求
client.update(request, RequestOptions.DEFAULT);
}
删除文档
删除与查询相比,仅仅是请求方式从GET变成DELETE
//删除文档
@Test
void testDeleteDocument() throws IOException {
// 1.创建Request
DeleteRequest request = new DeleteRequest("hotel", "61083");
// 2.发送请求
client.delete(request, RequestOptions.DEFAULT);
}
批量操作
批量处理BulkRequest,其本质就是将多个普通的CRUD请求组合在一起发送。
其中提供了一个add方法,用来添加其他请求:
可以看到,能添加的请求包括:
- IndexRequest,也就是新增
- UpdateRequest,也就是修改
- DeleteRequest,也就是删除
因此Bulk中添加了多个IndexRequest,就是批量新增功能了。示例:
//批量操作
@Test
public void testBulkRequest() throws Exception {
// 查询所有酒店数据
List<Hotel> hotelList = hotelMapper.selectList(null);
// 1.创建request
BulkRequest request = new BulkRequest();
// 2.准备DSL
for (Hotel hotel : hotelList) {
// 2-1 转为文档类型
HotelDoc hotelDoc = new HotelDoc(hotel);
// 2-2 转为json
String json = JSON.toJSONString(hotelDoc);
// 2-3 新增document
request.add(
new IndexRequest("hotel")
.id(hotelDoc.getId().toString())
.source(json, XContentType.JSON)
);
}
// 3.发送请求
client.bulk(request, RequestOptions.DEFAULT);
}