环境
jdk:13
es: 7.11.1
springboot:2.6.13
依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
注意
利用反射实现了高亮替换,如果是内部类的字段,将该字段提出来设为外部类的字段
Esutil.java
@Slf4j
@Component
public class EsUtil {
@Resource
private ElasticsearchRestTemplate restTemplate;
/**
* 创建索引,并设置映射。
* 需要通过两次访问实现,1、创建索引;2、设置映射。
*/
public Boolean initIndex(Class clazz){
// 创建索引和映射,根据类型上的Document注解创建
return restTemplate.indexOps(clazz).create()||restTemplate.indexOps(clazz).putMapping();
}
/**
*删除索引
*/
public Boolean deleteIndex(Class clazz){
//创建索引,系统初始化会自动创建索引
return restTemplate.indexOps(clazz).delete();
}
/**
*检查索引是否存在
*/
public Boolean isIndex(Class clazz){
return restTemplate.indexOps(clazz).exists();
}
/**
*普通查询
* @param startTime 开始时间
* @param endTime 结束时间
* @param timestamp 时间字段
* @param field 查询字段
* @param keywords 查询关键字
* @param from 第几页(0)
* @param size 一页有几条数据
* @param clazz 数据格式化的实体类对象
*/
public SearchHits<?> search(
Date startTime,
Date endTime,
String timestamp,
String field,
String keywords,
Integer from,
Integer size,
Class clazz
){
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
if(startTime!=null && endTime!=null && timestamp!=null){
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(timestamp)
.gte(startTime)
.lte(endTime);
searchQueryBuilder.withFilter(rangeQuery);
}
//指定查询条件
if(keywords!=null){
searchQueryBuilder.withQuery(QueryBuilders.matchQuery(field,keywords));
}else {
searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
}
//指定排序
searchQueryBuilder.withSorts(SortBuilders.fieldSort("id").order(SortOrder.DESC));
//分页
searchQueryBuilder.withPageable(PageRequest.of(from,size));
//构建查询对象
NativeSearchQuery searchQuery = searchQueryBuilder.build();
//执行查询
SearchHits<?> searchHits = restTemplate.search(searchQuery,clazz);
return searchHits;
}
/**
*多字段高亮查询
* @param startTime 开始时间
* @param endTime 结束时间
* @param timestamp 时间字段
* @param highlightFields 查询字段(高亮字段)
* @param keywords 查询关键字
* @param from 第几页(0)
* @param size 一页有几条数据
* @param clazz 数据格式化的实体类对象
*
*/
public SearchHits<?> searchMulti(
Date startTime,
Date endTime,
String timestamp,
String keywords,
Integer from,
Integer size,
Class clazz,
String... highlightFields
){
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
//指定查询条件
if(startTime!=null && endTime!=null && timestamp!=null){
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(timestamp)
.gte(startTime)
.lte(endTime);
searchQueryBuilder.withFilter(rangeQuery);
}
if(keywords!=null){
searchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords,highlightFields));
} else {
searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
}
searchQueryBuilder.withSorts(SortBuilders.fieldSort("id").order(SortOrder.DESC));
//分页
searchQueryBuilder.withPageable(PageRequest.of(from,size));
//构建查询对象
NativeSearchQuery searchQuery = searchQueryBuilder.build();
//执行查询
SearchHits<?> searchHits = restTemplate.search(searchQuery,clazz);
return searchHits;
}
/**
*单一字段高亮查询
* @param startTime 开始时间
* @param endTime 结束时间
* @param timestamp 时间字段
* @param field 查询字段(高亮字段)
* @param keywords 查询关键字
* @param from 第几页(0)
* @param size 一页有几条数据
* @param clazz 数据格式化的实体类对象
*
*/
public SearchHits<?> searchWithHighlight(
Date startTime,
Date endTime,
String timestamp,
String field,
String keywords,
Integer from,
Integer size,
Class clazz
){
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
//指定查询条件
if(startTime!=null && endTime!=null){
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(timestamp)
.gte(startTime)
.lte(endTime);
searchQueryBuilder.withFilter(rangeQuery);
}
if(keywords!=null){
searchQueryBuilder.withQuery(QueryBuilders.matchQuery(field,keywords));
} else {
searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
}
//指定排序,如果不指定默认按着得分进行排序
searchQueryBuilder.withSorts(SortBuilders.fieldSort("id").order(SortOrder.DESC));
//分页
searchQueryBuilder.withPageable(PageRequest.of(from,size));
//指定高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
//指定高亮的字段
highlightBuilder.field(field);
//指定高亮的标
highlightBuilder.preTags("<span style='color:red;'>").postTags("</span>");
searchQueryBuilder.withHighlightBuilder(highlightBuilder);
//构建查询对象
NativeSearchQuery searchQuery = searchQueryBuilder.build();
//执行查询
SearchHits<?> searchHits = restTemplate.search(searchQuery,clazz);
for (SearchHit hit : searchHits.getSearchHits()){
if(hit.getHighlightFields().isEmpty()){
return searchHits;
}
//利用反射,调用所查询字段的set方法,将高亮字段里的值赋给原来的字段
hit.getHighlightFields().forEach((key,value)->
{
try {
Field resField =hit.getContent().getClass().getDeclaredField((String)key);
resField.setAccessible(true);
setValue(hit.getContent(),
hit.getContent().getClass(),
(String)key,
resField.getType(),
value.toString().substring(1,value.toString().length()-1));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
return searchHits;
}
/**
*多字段高亮查询
* @param startTime 开始时间
* @param endTime 结束时间
* @param timestamp 时间字段
* @param highlightFields 查询字段(高亮字段)
* @param keywords 查询关键字
* @param from 第几页(0)
* @param size 一页有几条数据
* @param clazz 数据格式化的实体类对象
*
*/
public SearchHits<?> searchWithHighlightMulti(
Date startTime,
Date endTime,
String timestamp,
String keywords,
Integer from,
Integer size,
Class clazz,
String... highlightFields
){
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
//指定查询条件
if(startTime!=null && endTime!=null && timestamp!=null){
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(timestamp)
.gte(startTime)
.lte(endTime);
searchQueryBuilder.withFilter(rangeQuery);
}
if(keywords!=null){
searchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords,highlightFields));
} else {
searchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
}
searchQueryBuilder.withSorts(SortBuilders.fieldSort("id").order(SortOrder.DESC));
//分页
searchQueryBuilder.withPageable(PageRequest.of(from,size));
//指定高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
//指定高亮的字段
for(String field:highlightFields){
highlightBuilder.field(field);
}
//指定高亮的标签
highlightBuilder.preTags("<span style='color:red;'>").postTags("</span>");
searchQueryBuilder.withHighlightBuilder(highlightBuilder);
//构建查询对象
NativeSearchQuery searchQuery = searchQueryBuilder.build();
//执行查询
SearchHits<?> searchHits = restTemplate.search(searchQuery,clazz);
for (SearchHit hit : searchHits.getSearchHits()){
if(hit.getHighlightFields().isEmpty()){
return searchHits;
}
//利用反射,调用所查询字段的set方法,将高亮字段里的值赋给原来的字段
hit.getHighlightFields().forEach((key,value)->
{
try {
Field resField =hit.getContent().getClass().getDeclaredField((String)key);
resField.setAccessible(true);
setValue(hit.getContent(),
hit.getContent().getClass(),
(String)key,
resField.getType(),
value.toString().substring(1,value.toString().length()-1));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
return searchHits;
}
/**
* 根据属性,拿到set方法,并把值set到对象中
* @param obj 对象
* @param clazz 对象的class
* @param filedName 需要设置值得属性
* @param typeClass
* @param value
*/
private void setValue(Object obj,Class<?> clazz,String filedName,Class<?> typeClass,Object value){
filedName = removeLine(filedName);
String methodName = "set" + filedName.substring(0,1).toUpperCase()+filedName.substring(1);
try{
Method method = clazz.getDeclaredMethod(methodName, new Class[]{typeClass});
method.invoke(obj, new Object[]{getClassTypeValue(typeClass, value)});
}catch(Exception ex){
ex.printStackTrace();
}
}
/**
* 处理字符串 如: abc_dex ---> abcDex
* @param str
* @return
*/
private String removeLine(String str){
if(null != str && str.contains("_")){
int i = str.indexOf("_");
char ch = str.charAt(i+1);
char newCh = (ch+"").substring(0, 1).toUpperCase().toCharArray()[0];
String newStr = str.replace(str.charAt(i+1), newCh);
String newStr2 = newStr.replace("_", "");
return newStr2;
}
return str;
}
/**
* 通过class类型获取获取对应类型的值
* @param typeClass class类型
* @param value 值
* @return Object
*/
private Object getClassTypeValue(Class<?> typeClass, Object value){
if(typeClass == int.class || value instanceof Integer){
if(null == value){
return 0;
}
return value;
}else if(typeClass == short.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == byte.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == double.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == long.class){
if(null == value){
return 0;
}
return value;
}else if(typeClass == String.class){
if(null == value){
return "";
}
return value;
}else if(typeClass == boolean.class){
if(null == value){
return true;
}
return value;
}else if(typeClass == BigDecimal.class){
if(null == value){
return new BigDecimal(0);
}
return new BigDecimal(value+"");
}else {
return typeClass.cast(value);
}
}
}