将RestHighLevelClient添加到Spring容器
@Value("${elasticsearch.server.host:localhost}")
private String[] elasticsearchHost;
@Bean
public RestHighLevelClient restHighLevelClient() {
try {
HttpHost[] httpHosts = new HttpHost[elasticsearchHost.length];
//将地址转换为http主机数组,未配置端口则采用默认9200端口,配置了端口则用配置的端口
for (int i = 0; i < httpHosts.length; i++) {
if (!StringUtils.isEmpty(elasticsearchHost[i])) {
if (elasticsearchHost[i].contains(":")) {
String[] uris = elasticsearchHost[i].split(":");
httpHosts[i] = new HttpHost(uris[0], Integer.parseInt(uris[1]), "http");
} else {
httpHosts[i] = new HttpHost(elasticsearchHost[i], 9200, "http");
}
}
}
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(httpHosts)
.setRequestConfigCallback(requestConfigBuilder->requestConfigBuilder
.setConnectTimeout(3000)
.setSocketTimeout(5000)
.setConnectionRequestTimeout(500)));
return client;
} catch (Exception e) {
logger.error("创建elasticsearch客户端异常:", e);
throw new RuntimeException(e);
}
}
封装执行客户端
@Component
public class ElasticsearchClientUtil {
@Autowired
private RestHighLevelClient restHighLevelClient;
@Autowired
private SnowflakeIdUtils idUtils;
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 判断索引是否存在
* @author
* @date 2021/9/10 14:42
* @params indexName 索引名称
* @return
*/
public boolean exists(String indexName) {
try{
GetIndexRequest indexRequest = new GetIndexRequest(indexName);
return restHighLevelClient.indices().exists(indexRequest, RequestOptions.DEFAULT);
}catch (NoNodeAvailableException e) {
logger.error("Elasticsearch服务不可用: ", e);
throw new RuntimeException("Elasticsearch服务不可用");
} catch (Exception e) {
logger.error("Elasticsearch数据异常: ", e);
throw new RuntimeException("Elasticsearch数据异常");
}
}
/**
* 创建索引
* @author
* @date 2021/9/10 14:51
* @params clazz对应结构class
* @return
*/
public boolean create(Class clazz) throws IOException{
return create(getIndexName(clazz), clazz);
}
/**
* 创建索引
* @author
* @date 2021/9/10 14:51
* @params indexName索引名称 ,clazz对应结构class
* @return
*/
public boolean create(String indexName, Class clazz) {
CreateIndexRequest requestIndex = new CreateIndexRequest(indexName);
requestIndex.mapping(getMapping(clazz));
try{
CreateIndexResponse indexResponse = restHighLevelClient.indices().create(requestIndex, RequestOptions.DEFAULT);
if (!indexResponse.isAcknowledged()) {//索引创建失败
return false;
}
//给集群一点时间拷贝副本
//TimeUnit.SECONDS.sleep(2);
//集群操作,再添加数据前可以先判断索引是否存在
/**
while(true){
//判断索引是否存在
if(clientUtil.exists(indexName)) {
logger.info(indexName + "索引存在");
break;
}
}
**/
}catch (NoNodeAvailableException e) {
logger.error("Elasticsearch服务不可用: ", e);
throw new RuntimeException("Elasticsearch服务不可用");
} catch (Exception e) {
logger.error("Elasticsearch数据异常: ", e);
throw new RuntimeException("Elasticsearch数据异常");
}
return true;
}
private String getIndexName(Class clazz){
Document doc = (Document) clazz.getAnnotation(Document.class);
return doc.indexName();
}
private Map<String,Object> getMapping(Class clazz){
Map<String, Object> properties = new ConcurrentHashMap<String, Object>();
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Field.class)) {
Map<String, Object> property = new ConcurrentHashMap<String,Object>();
Field fieldAnnotation = field.getAnnotation(Field.class);
property.put("type",fieldAnnotation.type().name().toLowerCase());
if (!"".equals(fieldAnnotation.analyzer())) {
property.put("analyzer", fieldAnnotation.analyzer());
}
if (!"".equals(fieldAnnotation.searchAnalyzer())) {
property.put("search_analyzer", fieldAnnotation.searchAnalyzer());
}
if (TermVector.none!=fieldAnnotation.termVector()){
property.put("term_vector",fieldAnnotation.termVector().name());
}
if (fieldAnnotation.store()) {
properties.put(field.getName(), property);
}
}
}
Map<String,Object> result = new HashMap<String,Object>();
result.put("properties",properties);
return result;
}
/**
* 保存索引
* @author
* @date 2021/9/10 14:53
* @params indexName 索引名称 index 索引内容
* @return
*/
public String save(String indexName, Object index) {
try{
IndexResponse indexResponse = restHighLevelClient.index(getIndexRequest(indexName, index),RequestOptions.DEFAULT);
return indexResponse.getId();
}catch (NoNodeAvailableException e) {
logger.error("Elasticsearch服务不可用: ", e);
throw new RuntimeException("Elasticsearch服务不可用");
} catch (Exception e) {
logger.error("Elasticsearch数据异常: ", e);
throw new RuntimeException("Elasticsearch数据异常");
}
}
private IndexRequest getIndexRequest(String indexName,Object index){
IndexRequest request = new IndexRequest(indexName);
String indexString = JSONObject.toJSONString(index);
JSONObject jsonObject = JSONObject.parseObject(indexString);
String id = analysisEntity(jsonObject, index.getClass());
request.id(id);
request.source(jsonObject, XContentType.JSON);
return request;
}
/**
* 解析Entity
* @author
* @date 2021/9/14 15:01
* @param jsonObject 实体数据
* @param clazz 实体类型
* @return id
*/
private String analysisEntity(JSONObject jsonObject,Class clazz){
String id = null;
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Id.class)) {
if(jsonObject.get(field.getName()) == null){ ;
id = idUtils.nextId()+"";
jsonObject.put(field.getName(), id);
}else {
id = jsonObject.get(field.getName()).toString();
}
}
if (field.isAnnotationPresent(Field.class)) {
if (!field.getAnnotation(Field.class).store()) {
jsonObject.remove(field.getName());
}
}
}
return id;
}
/**
* 批量保存
* @author
* @date 2021/9/14 14:42
* @param
* @return
*/
public Boolean batchSave(String indexName, Object... indexs) {
BulkRequest bulkRequest = new BulkRequest();
for (Object index : indexs) {
bulkRequest.add(getIndexRequest(indexName, index));
}
try{
BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
if (RestStatus.OK == bulkResponse.status()) {
return true;
}
}catch (NoNodeAvailableException e) {
logger.error("Elasticsearch服务不可用: ", e);
throw new RuntimeException("Elasticsearch服务不可用");
} catch (Exception e) {
logger.error("Elasticsearch数据异常: ", e);
throw new RuntimeException("Elasticsearch数据异常");
}
return false;
}
/**
* 方法描述
* @author
* @date 2021/9/14 15:09
* @param indexName 索引名称
* @param index 索引内容
* @return
*/
public boolean update(String indexName,Object index) {
String indexString = JSONObject.toJSONString(index);
JSONObject jsonObject = JSONObject.parseObject(indexString);
String id = analysisEntity(jsonObject, index.getClass());
UpdateRequest updateRequest = new UpdateRequest(indexName,id);
updateRequest.doc(jsonObject);
try{
UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
return RestStatus.OK == updateResponse.status();
}catch (NoNodeAvailableException e) {
logger.error("Elasticsearch服务不可用: ", e);
throw new RuntimeException("Elasticsearch服务不可用");
} catch (ElasticsearchStatusException e){
logger.error("elasticsearch索引状态错误",e);
throw new RuntimeException("索引记录异常,索引ID:"+id);
}catch (Exception e) {
logger.error("Elasticsearch数据异常: ", e);
throw new RuntimeException("Elasticsearch数据异常");
}
}
/**
* 删除索引记录
* @author
* @date 2021/9/14 15:19
* @param
* @return
*/
public Boolean delete(String indexName,String id) {
DeleteRequest deleteRequest = new DeleteRequest(indexName, id);
try {
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
return RestStatus.OK == deleteResponse.status();
}catch (NoNodeAvailableException e) {
logger.error("Elasticsearch服务不可用: ", e);
throw new RuntimeException("Elasticsearch服务不可用");
}catch (ElasticsearchStatusException e){
logger.error("elasticsearch索引状态错误",e);
throw new RuntimeException("索引记录异常,索引ID:"+id);
} catch (Exception e) {
logger.error("Elasticsearch数据异常: ", e);
throw new RuntimeException("Elasticsearch数据异常");
}
}
/**
* 保存索引
* @author
* @date 2021/9/10 14:53
* @param index 索引内容
* @return
*/
public String save(Object index) throws IOException {
return save(getIndexName(index.getClass()), index);
}
/**
* 查询索引
* @author
* @date 2021/9/13 17:42
* @param
* @return
*/
public QueryData searchDocument(IndexRequestParams indexRequestParams,Class clazz,String... indexName){
QueryData queryData = new QueryData();
try {
SearchSourceBuilder sourceBuilder = getSearchSourceBuilder(indexRequestParams,clazz);
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices(indexName);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
//封装查询到的数据
List<Object> resultList = new ArrayList<>();
if ( hits.getHits() != null && hits.getHits().length > 0 ){
for (SearchHit hit : hits) {
JSONObject jsonObj = JSONObject.parseObject(hit.getSourceAsString());
//设置高亮属性
hit.getHighlightFields().entrySet().forEach(fieldEntity->{
Text[] fragments = fieldEntity.getValue().getFragments();
if(fragments !=null && fragments.length > 0 ){
jsonObj.put(fieldEntity.getKey(),fragments[0]);
}
});
jsonObj.put("categoryCode",hit.getIndex().replace("_document",""));
resultList.add(jsonObj.toJavaObject(clazz));
}
}
queryData.setDataList(resultList);
PagingInfo pagingInfo = indexRequestParams.getPagingInfo();
pagingInfo.setTotalCount(hits.getTotalHits().value);
queryData.setPagingInfo(pagingInfo);
return queryData;
} catch (NoNodeAvailableException e) {
logger.error("Elasticsearch服务不可用: ", e);
throw new RuntimeException("Elasticsearch服务不可用");
} catch (ElasticsearchStatusException e){
logger.error("Elasticsearch状态异常: ", e);
List<String> collect = Arrays.stream(indexName).map(name -> name.replace("_document", "")).collect(Collectors.toList());
throw new RuntimeException("Elasticsearch索引不存在,索引编码:"+StringUtils.join(collect));
}catch (Exception e) {
logger.error("Elasticsearch数据异常: ", e);
throw new RuntimeException("Elasticsearch数据异常");
}
}
/**
* 构建查询条件
* @author
* @date 2021/9/13 17:42
* @param
* @return
*/
private SearchSourceBuilder getSearchSourceBuilder(IndexRequestParams requestParams,Class clazz){
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
Set<String> keywordFields = getKeyWordFields(clazz);
PagingInfo pagingInfo = requestParams.getPagingInfo();
if (pagingInfo == null){
pagingInfo = new PagingInfo();
pagingInfo.setCurrentPage(1);
pagingInfo.setPageSize(10);
requestParams.setPagingInfo(pagingInfo);
}
int currentPage = pagingInfo.getCurrentPage();
int pageSize = pagingInfo.getPageSize();
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
if (!StringUtils.isEmpty(requestParams.getKeyword())) {
boolQueryBuilder.must(QueryBuilders.multiMatchQuery(requestParams.getKeyword(),keywordFields.toArray(new String[]{})));
}
filterTime(boolQueryBuilder,requestParams,clazz);
//过滤系统,有效
boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete",0));//SpringSecurityUtils.getCurrentUserUnitId()));
// 构建完成
sourceBuilder.query(boolQueryBuilder);
// 分页
sourceBuilder.from((currentPage-1)*pageSize);
sourceBuilder.size(pageSize);
//高亮
if (!StringUtils.isEmpty(requestParams.getKeyword())) {
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<font color='#e75213'>");
highlightBuilder.postTags("</font>");
for (String keywordField : keywordFields) {
highlightBuilder.field(keywordField).fragmentSize(requestParams.getFragmentSize()).numOfFragments(1);
}
sourceBuilder.highlighter(highlightBuilder);
}
//增加排序
if (requestParams.getOrder()!=null) {
sourceBuilder.sort(new FieldSortBuilder(requestParams.getOrder().getProperty()).order(Sort.Direction.ASC == requestParams.getOrder().getDirection() ? SortOrder.ASC : SortOrder.DESC));
}
return sourceBuilder;
}
private void filterTime(BoolQueryBuilder boolQueryBuilder, IndexRequestParams params,Class clazz) {
Set<String> timeRangeField = params.getOrder() != null && StringUtils.isNotBlank(params.getOrder().getProperty()) ? Sets.newHashSet(params.getOrder().getProperty()) : getTimeField(clazz);
List<RangeQueryBuilder> rangeQueryBuilders = Lists.newArrayList();
if (params.getEndTime() != null || params.getStartTime() != null) {// 有自定义时间范围的
for (String tf : timeRangeField) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(tf);
if (params.getStartTime() != null) {
rangeQueryBuilder.gte(params.getStartTime().getTime());
}
if (params.getEndTime() != null) {
rangeQueryBuilder.lte(params.getEndTime().getTime());
}
if (params.getStartTime() != null || params.getEndTime() != null) {
rangeQueryBuilders.add(rangeQueryBuilder);
}
}
if (!rangeQueryBuilders.isEmpty()) {
boolQueryBuilder.filter(orQuery(rangeQueryBuilders.toArray(new RangeQueryBuilder[]{})));
}
return;
}
if (params.getDateRange() != null) { // 定义时间范围类型的
Date startTime = null;
Date endTime = new Date();
switch (params.getDateRange()) {
case ONE_DAY:
startTime = DateUtils.addDays(endTime, -1);
break;
case ONE_WEEK:
startTime = DateUtils.addWeeks(endTime, -1);
break;
case ONE_MONTH:
startTime = DateUtils.addMonths(endTime, -1);
break;
case ONE_YEAR:
startTime = DateUtils.addYears(endTime, -1);
break;
}
for (String tf : timeRangeField) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(tf);
rangeQueryBuilder.gte(startTime);
rangeQueryBuilder.lte(endTime);
rangeQueryBuilders.add(rangeQueryBuilder);
}
if (!rangeQueryBuilders.isEmpty()) {
boolQueryBuilder.filter(orQuery(rangeQueryBuilders.toArray(new RangeQueryBuilder[]{})));
}
}
}
public QueryBuilder orQuery(RangeQueryBuilder... rangeQueryBuilders){
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
for (RangeQueryBuilder rangeQueryBuilder : rangeQueryBuilders) {
queryBuilder.should(rangeQueryBuilder);
}
return queryBuilder;
}
private Set<String> getKeyWordFields(Class clazz){
Set<String> keywordFields = Sets.newHashSet();
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Field.class)) {
Field fieldAnnotation = field.getAnnotation(Field.class);
if (fieldAnnotation.index() && (FieldType.Keyword == fieldAnnotation.type() || FieldType.Text == fieldAnnotation.type())){
keywordFields.add(field.getName());
}
}
}
return keywordFields;
}
private Set<String> getTimeField(Class clazz){
Set<String> timeField = Sets.newHashSet();
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Field.class)) {
Field fieldAnnotation = field.getAnnotation(Field.class);
if (fieldAnnotation.index() && FieldType.Date == fieldAnnotation.type()){
timeField.add(field.getName());
}
}
}
return timeField;
}
}