一、前言
上篇文章我们了解了ES的修改文档的操作,也同样分别通过ES的kibana客户端以及Java高级Rest客户端进行学习,那么本篇末尾要给大家介绍的是对文档的删除操作,同新修改文档,也有删除单条文档和批量删除文档操作,根据条件删除文档,我们本篇均会涉及到。
二、删除文档
2.1、删除单条文档
在ES中删除文档的请求的类型是DELETE,其请求的形式如下:
DELETE /${index_name}/_doc/${_id}
上面的_id就是将要删除的ES文档的_id。执行下面的删除命令:
DELETE /hotel/_doc/021
返回的结果如下:
通过结果可知,已经成功删除文档,之前添加的文档已经不存在了。我们可以通过下面的根据_id搜索文档的命令进行验证:
GET /hotel/_doc/021
ES返回结果如下:
由返回的结果可知,删除已经生效。
在Java高级REST客户端中,执行删除文档需要创建DeleteRequest对象并设置对应的索引名称和删除文档的_id,然后执行客户端的delete()方法并把DeleteRequest对象传入即可。以下代码演示了根据_id删除文档的方法。
首先同修改一样,我们需要建立一个专门处理删除逻辑的service,记得引入client:
public String singleDelete(String indexName, String docId) {
if (CharSequenceUtil.isBlank(indexName)) {
throw new SearchException("索引名不能为空");
}
DeleteRequest deleteRequest = new DeleteRequest(indexName, docId);
try {
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
return deleteResponse.toString();
} catch (IOException e) {
throw new SearchException("删除服务错误");
}
}
接着controller层调用service:
@PostMapping("/single/delete")
public FoundationResponse<String> singleDelete(String indexName, String docId) {
try {
String result = esDeleteDocService.singleDelete(indexName, docId);
return FoundationResponse.success(result);
} catch (SearchException e) {
log.warn("搜索发生异常,原因为:{}", e.getMessage());
return FoundationResponse.error(100, e.getMessage());
} catch (Exception e) {
log.error("服务发生异常,原因为:{}", e.getMessage());
return FoundationResponse.error(100, e.getMessage());
}
}
然后postman调用该接口:
2.2、批量删除文档
与批量写入和更新文档不同的是,批量删除文档不需要提供JSON数据,其请求形式如下:
POST /_bulk
{"delete":{"_index":"${index_name}","_id":"${_id}"}}
{"delete":{"_index":"${index_name}","_id":"${_id}"}}
例如,下面的DSL将批量删除_id为002,003,004的文档:
POST /_bulk
{"delete":{"_index":"hotel_order","_id":"004"}}
{"delete":{"_index":"hotel_order","_id":"002"}}
{"delete":{"_index":"hotel_order","_id":"003"}}
和批量写入修改文档相似,在Java客户端接口中,批量删除文档同样需要创建BulkRequest对象并设置对应的索引名称。对于多条需要删除的文档,可构建多个DeleteRequest对象并调用BulkRequest.add()方法添加这些DeleteRequest对象,执行时,调用客户端的bulk()方法并把BulkRequest对象传入即可。
首先Service层代码如下,我们通过接收前端传的需要批量删除的id的list进行批量删除,并且模拟的是删除同一个索引下的多个文档:
public String bulkDelete(HotelDocRequest hotelDocRequest) {
String indexName = hotelDocRequest.getIndexName();
if (CharSequenceUtil.isBlank(indexName)) {
throw new SearchException("索引名不能为空");
}
List<String> docIds = hotelDocRequest.getHotelList().stream().map(Hotel::getId).collect(Collectors.toList());
BulkRequest bulkRequest = new BulkRequest();
for (String docId : docIds) {
//创建DeleteRequest
DeleteRequest deleteRequest = new DeleteRequest(indexName, docId);
bulkRequest.add(deleteRequest);
}
BulkResponse bulkResponse;
try {
//执行批量删除
bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
if (bulkResponse.hasFailures()) {
return "失败,原因:" + bulkResponse.buildFailureMessage();
} else {
return "成功";
}
} catch (IOException e) {
throw new SearchException("批量修改服务错误");
}
}
controller调用Service层:
@PostMapping("/bulk/delete/doc")
public FoundationResponse<String> bulkDelete(@RequestBody HotelDocRequest hotelDocRequest) {
List<Hotel> hotelList = hotelDocRequest.getHotelList();
if (CollUtil.isEmpty(hotelList)) {
return FoundationResponse.error(100, "无可修改的有效文档");
}
try {
String s = esDeleteDocService.bulkDelete(hotelDocRequest);
return FoundationResponse.success(s);
} catch (SearchException e) {
log.warn("批量删除发生异常,原因为:{}", e.getMessage());
return FoundationResponse.error(100, e.getMessage());
} catch (Exception e) {
log.error("服务发生异常,原因为:{}", e.getMessage());
return FoundationResponse.error(100, e.getMessage());
}
}
postman调用该接口,body如下:
{
"hotelList": [
{
"id": "001"
},
{
"id": "002"
}
],
"indexName":"hotel"
}
返回结果如下:
2.3、根据条件删除文档
和条件更新操作类似,有些场景需要根据某些条件同时删除多条数据,类似于在关系型数据库中使用delete table_name where… 删除一批数据。为了满足这样的需求,ES为用户提供了_delete_by_query功能,其请求形式如下:
POST /hotel/_delete_by_query
{
"query":{
... //删除文档的查询条件
}
}
query子句用于指定删除数据的匹配条件,相当于SQL中的where语句。下面的DSL将把city为成都的文档删除:
POST /hotel/_delete_by_query
{
"query":{
"term":{
"city":{
"value":"成都"
}
}
}
}
在java高级REST客户端中,执行条件删除文档需要创建DeleteByQueryRequest对象并设置对应的索引名称类似于DSL中的query子句,通过调用DeleteByQueryRequest.setQuery()方法设置查询逻辑,然后执行客户端的deleteByQuery()方法并把DeleteByQueryRequest对象传入即可。以下代码演示了根据城市删除文档的方法:
Service层:
public String deleteByCity(String indexName, String city) {
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(indexName);
deleteByQueryRequest.setQuery(new TermQueryBuilder("city", city));
try {
BulkByScrollResponse response = client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
return response.toString();
} catch (IOException e) {
throw new SearchException("按照条件修改服务错误");
}
}
controller调用service:
@PostMapping("/delete/byCity")
public FoundationResponse<String> updatePriceByQueryCity(String indexName, String city) {
if (CharSequenceUtil.isBlank(indexName)) {
throw new SearchException("索引名不能为空");
}
try {
String result = esDeleteDocService.deleteByCity(indexName, city);
return FoundationResponse.success(result);
} catch (SearchException e) {
log.warn("搜索发生异常,原因为:{}", e.getMessage());
return FoundationResponse.error(100, e.getMessage());
} catch (Exception e) {
log.error("服务发生异常,原因为:{}", e.getMessage());
return FoundationResponse.error(100, e.getMessage());
}
}
postman调用该接口: