xgl-case/src/main/java/com/nbclass/activity/service/impl/ElasticSearchServiceImpl.java
2021-12-08 18:23:11 +08:00

360 lines
15 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.nbclass.activity.service.impl;
import java.io.IOException;
import java.util.*;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.nbclass.activity.model.Content;
import com.nbclass.activity.model.ContentTags;
import com.nbclass.activity.service.ContentService;
import com.nbclass.activity.service.ElasticSearchService;
import com.nbclass.exception.ParameterException;
import com.nbclass.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
/**
* 案例内容ES操作
* @author Leon
* @datetime 2020年6月1日 下午3:02:00
*/
@Slf4j
@Service
public class ElasticSearchServiceImpl implements ElasticSearchService {
@Resource
private RestHighLevelClient restHighLevelClient;
@Resource
private ContentService contentService;
private static final String es_index_content = "es-cases-content";
/**
* 检查索引是否存在
* @throws IOException
*/
private boolean existIndex() throws IOException{
GetIndexRequest request = new GetIndexRequest().indices(es_index_content);
@SuppressWarnings("deprecation")
boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
return exists;
}
// 创建索引
public void createIndex(){
try {
// 检查索引是否存在
if(existIndex())return;
CreateIndexRequest indexRequest = new CreateIndexRequest(es_index_content);
CreateIndexResponse indexResponse = restHighLevelClient.indices().create(indexRequest, RequestOptions.DEFAULT);
log.info("创建索引, 返回值=>{}, 确认状态=>{}", indexResponse.index(), indexResponse.isAcknowledged());
}catch (Exception e) {
log.info("创建索引异常", e);
}
}
// 删除索引
public void deleteIndex(){
try {
DeleteIndexRequest indexRequest = new DeleteIndexRequest(es_index_content);
AcknowledgedResponse delete = restHighLevelClient.indices().delete(indexRequest, RequestOptions.DEFAULT);
log.info("删除索引, 返回值=>{}, 确认状态=>{}", delete.isFragment(), delete.isAcknowledged());
}catch (Exception e) {
log.info("删除索引异常", e);
}
}
// 创建或者更新文档
@Override
public void merge(Content entity) {
try {
if(entity!=null && entity.getTagList()!=null && entity.getTagList().size()>0) {
String tags = "";
for(ContentTags tag : entity.getTagList()) {
if(StringUtils.isBlank(tag.getTagName()))continue;
tags += (StringUtils.isBlank(tags)?"":",")+tag.getTagName();
}
entity.setTags(tags); // 将标签组到字符串里,便于搜索。
}
createIndex(); // 判断索引是否存在,不存在创建索引
// 判断document是否存在存在修改不存在新增
GetRequest getRequest = new GetRequest(es_index_content, String.valueOf(entity.getId()));
boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
if(!exists) {
// 创建文档索引
IndexRequest indexRequest = new IndexRequest(es_index_content);
indexRequest.id(String.valueOf(entity.getId())).source(JSON.toJSONString(entity), XContentType.JSON);
@SuppressWarnings("unused")
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
log.info("添加文档新建ES索引成功id = " + entity.getId());
}else {
// 修改文档索引
UpdateRequest updateRequest = new UpdateRequest(es_index_content, String.valueOf(entity.getId()));
updateRequest.doc(JSON.toJSONString(entity), XContentType.JSON);
@SuppressWarnings("unused")
UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
log.info("修改文档重建ES索引成功id = " + entity.getId());
}
} catch (IOException e) {
log.error("添加文档新建ES索引失败id = " + entity.getId(), e);
throw new ServiceException("案例更新ES索引失败");
}
}
@Override
public void deleteDocByIds(List<Long> ids) {
if(ids == null || ids.isEmpty()){
return;
}
try {
for (Long id : ids) {
// DeleteRequest
DeleteRequest deleteRequest = new DeleteRequest(es_index_content, String.valueOf(id));
@SuppressWarnings("unused")
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
}
} catch (IOException e) {
log.error("删除案例ES索引失败", e);
throw new ServiceException("删除案例ES索引失败");
}
}
// matchQuery会将搜索词分词再与目标查询字段进行匹配若分词中的任意一个词与目标字段匹配上则可查询到。
// termQuery不会对搜索词进行分词处理而是作为一个整体与目标字段进行匹配若完全匹配则可查询到。
@Override
public void deleteDocByQuery(Content entity) {
/*if(entity.getType()!=null) {
throw new ParameterException("案例类型不能为空");
}*/
try {
DeleteByQueryRequest request = new DeleteByQueryRequest(es_index_content);
request.setConflicts("proceed"); // 发生冲突即略过
//request.setQuery(QueryBuilders.termQuery("type", entity.getType()));
request.setQuery(QueryBuilders.matchAllQuery());
BulkByScrollResponse bulkResponse = restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT);
TimeValue timeTaken = bulkResponse.getTook();
boolean timedOut = bulkResponse.isTimedOut();
long totalDocs = bulkResponse.getTotal();
long updatedDocs = bulkResponse.getUpdated();
long deletedDocs = bulkResponse.getDeleted();
long batches = bulkResponse.getBatches();
long noops = bulkResponse.getNoops();
long versionConflicts = bulkResponse.getVersionConflicts();
log.info("根据案例类型删除文档,花费时间:" + timeTaken + ",是否超时:" + timedOut + ",总文档数:" + totalDocs + ",更新数:" +
updatedDocs + ",删除数:" + deletedDocs + ",批量次数:" + batches + ",跳过数:" + noops + ",冲突数:" + versionConflicts);
} catch (IOException e) {
log.error("根据案例类型删除文档异常", e);
}
}
@Override
public boolean existDoc(Long id){
boolean exists = false;
GetRequest getRequest = new GetRequest(es_index_content, String.valueOf(id));
try {
exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return exists;
}
// 获取文档
@Override
public Content findById(Long id) {
// GetRequest
GetRequest getRequest = new GetRequest(es_index_content, String.valueOf(id));
// 查询ES
GetResponse getResponse;
Content content = null;
try {
getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
content = JSON.parseObject(getResponse.getSourceAsString(), Content.class);
if(content == null) {
content = contentService.findById(id);
}
if(content!=null && content.getId()!=null && content.getId()>0) {
content.setTags(null);
content.setImages(null);
}
} catch (IOException e) {
log.error("从ES查询数据失败", e);
throw new ServiceException("从ES查询数据失败");
}
return content;
}
/**
* 从数据库查询
* @return
*/
private JSONObject getListByMySQL(Integer pageNum, Integer pageSize, String type, String keyWord, String tagIds, String sourceIds) {
JSONObject result = new JSONObject();
Content param = new Content();
param.setType(type);
param.setTitle(keyWord);
param.setTags(tagIds);
param.setFromids(sourceIds);
PageHelper.startPage(pageNum, pageSize);
List<Content> dataList = contentService.getListByFront(param);
PageInfo<Content> pages = new PageInfo<>(dataList);
if(dataList!=null && dataList.size()>0) {
for (Content entity : dataList) {
// 清空一些前端用不上的字段
entity.setTags(null);
entity.setImages(null);
entity.setImgList(null);
}
}
result.put("total", pages.getTotal()); // 总记录数
result.put("rows", dataList); // 数据体
int totalPage = (int)(pages.getTotal() % pageSize==0 ? pages.getTotal()/pageSize : pages.getTotal()/pageSize+1);
result.put("totalPage", totalPage); // 总页数
return result;
}
@Override
public Map<String, Object> getList(Integer pageNum, Integer pageSize, String type, String keyWord, String tagIds, String sourceIds) {
// 封装Map参数返回
Map<String, Object> result = new HashMap<>();
try {
// 选择标签或来源过滤时,从数据库查询记录
/*if(StringUtils.isNotBlank(tagIds) || StringUtils.isNotBlank(sourceIds)) {
return getListByMySQL(pageNum, pageSize, type, keyWord, tagIds, sourceIds);
}*/
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 分页采用简单的from + size分页适用数据量小的了解更多分页方式可自行查阅资料
searchSourceBuilder.from((pageNum - 1) * pageSize); // 从0开始
searchSourceBuilder.size(pageSize);
// 查询条件,只有查询关键字不为空才带查询条件
if (StringUtils.isNoneBlank(keyWord)) {
// QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, "name", "desc");
// searchSourceBuilder.query(queryBuilder);
}
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termQuery("visibility", 1));
/*if(StringUtils.isNotBlank(type)) { // 案例类型
boolQueryBuilder.must(QueryBuilders.termQuery("type", type));
if (StringUtils.isNoneBlank(keyWord)){
BoolQueryBuilder keywordQuery = QueryBuilders.boolQuery();
keywordQuery.should(QueryBuilders.matchQuery("title", keyWord));
keywordQuery.should(QueryBuilders.matchQuery("desct", keyWord));
keywordQuery.should(QueryBuilders.matchQuery("fromName", keyWord));
keywordQuery.should(QueryBuilders.matchQuery("tags", keyWord));
keywordQuery.should(QueryBuilders.matchQuery("content_text", keyWord));
boolQueryBuilder.must(keywordQuery);
}
}else {
if (StringUtils.isNoneBlank(keyWord)){
boolQueryBuilder.should(QueryBuilders.matchQuery("title", keyWord)); //.boost(3) // 给name字段更高的权重
boolQueryBuilder.should(QueryBuilders.matchQuery("desct", keyWord)); // description 默认权重 1
boolQueryBuilder.should(QueryBuilders.matchQuery("fromName", keyWord));
boolQueryBuilder.should(QueryBuilders.matchQuery("tags", keyWord));
boolQueryBuilder.should(QueryBuilders.matchQuery("content_text", keyWord));
boolQueryBuilder.minimumShouldMatch(1); // 至少一个should条件满足
}
}*/
if (StringUtils.isNoneBlank(keyWord)){
BoolQueryBuilder keywordQuery = QueryBuilders.boolQuery();
keywordQuery.should(QueryBuilders.matchQuery("title", keyWord));
keywordQuery.should(QueryBuilders.matchQuery("desct", keyWord));
//keywordQuery.should(QueryBuilders.matchQuery("fromName", keyWord));
keywordQuery.should(QueryBuilders.matchQuery("tags", keyWord));
keywordQuery.should(QueryBuilders.matchQuery("content_text", keyWord));
boolQueryBuilder.must(keywordQuery);
}
//选择标签或来源过滤
if(StringUtils.isNotBlank(tagIds)){
List<String> tagIdList = Arrays.asList(tagIds.split(","));
for(String tagId:tagIdList) {
boolQueryBuilder.must(QueryBuilders.termQuery("tagList.tid", tagId));
}
}
/*if(StringUtils.isNotBlank(sourceIds)){
List<String> sourIdList = Arrays.asList(sourceIds.split(","));
for(String sourId:sourIdList) {
boolQueryBuilder.must(QueryBuilders.termQuery("fromid", sourId));
}
}*/
searchSourceBuilder.query(boolQueryBuilder);
// 排序根据ID倒叙
searchSourceBuilder.sort("id", SortOrder.DESC);
// SearchRequest
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(searchSourceBuilder);
// 查询ES
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
// 获取总数
Long total = hits.getTotalHits().value;
// 遍历封装列表对象
List<Content> dataList = new ArrayList<>();
SearchHit[] searchHits = hits.getHits();
for (SearchHit searchHit : searchHits) {
Content entity = JSON.parseObject(searchHit.getSourceAsString(), Content.class);
// 清空一些前端用不上的字段
entity.setTags(null);
entity.setImages(null);
entity.setImgList(null);
dataList.add(entity);
}
result.put("total", total); // 总记录数
result.put("rows", dataList); // 数据体
int totalPage = (int)(total % pageSize==0 ? total/pageSize : total/pageSize+1);
result.put("totalPage", totalPage); // 总页数
}catch (Exception e) {
log.error("从es查询数据列表异常", e);
}
return result;
}
}