对日常且反复使用的功能进行封装,会大大提高我们的开发效率
Es常规查询注解
等于查询
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EsEquals {
/**
* filed name
*/
String name() default "";
}
不等于查询
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EsNotNull {
/**
* filed name
*/
String name() default "";
}
包含查询
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EsIn {
/**
* filed name
*/
String name() default "";
}
模糊匹配查询
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EsLike {
/**
* filed name
*/
String name() default "";
boolean leftLike() default false;
boolean rightLike() default false;
}
范围查询
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EsRange {
/**
* filed name
*/
String name() default "";
/**
* 大于
*/
boolean lt() default false;
/**
* 小于
*/
boolean gt() default false;
/**
* 包含上界
*/
boolean includeUpper() default false;
/**
* 包含下界
*/
boolean includeLower() default false;
}
Nested查询
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EsNested {
/**
* filed name
*/
String name() default "";
}
查询注解使用样例
@Data
@Accessors(chain = true)
public class EsDocBeanReq extends EsPageable {
@EsEquals(name = "_id")
private String id;
@EsEquals
private String firstCode;
@EsEquals
private String secordCode;
@EsLike(leftLike = true,rightLike = true)
private String content;
@EsIn(name = "type")
private List<Integer> typeList;
@EsRange(lt = true, name = "type")
private Integer typeRange;
}
ES工具类调用
public class EsQueryParse {
private static final Logger logger = LoggerFactory.getLogger(EsQueryParse.class);
private EsQueryParse() {
}
public static <T> Query convert2Query(T t) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
BoolQueryBuilder boolQueryBuilder = getBoolQueryBuilder(t);
queryBuilder.withQuery(boolQueryBuilder);
return queryBuilder.build();
}
private static <T> BoolQueryBuilder getBoolQueryBuilder(T t) {
return getBoolQueryBuilder(t, null);
}
private static <T> BoolQueryBuilder getBoolQueryBuilder(T t, String nestedPath) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
Class<?> clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
nestedPath = nestedPath == null ? "" : nestedPath;
try {
for (Field field : fields) {
Object value = ClassUtils.getPublicMethod(clazz, "get" + captureName(field.getName())).invoke(t);
if (value == null) {
continue;
}
if (field.isAnnotationPresent(EsLike.class)) {
WildcardQueryBuilder query = getLikeQuery(field, value, nestedPath);
boolQueryBuilder.must(query);
}
if (field.isAnnotationPresent(EsEquals.class)) {
MatchQueryBuilder query = getEqualsQuery(field, value, nestedPath);
boolQueryBuilder.must(query);
}
if (field.isAnnotationPresent(EsRange.class)) {
RangeQueryBuilder query = getRangeQuery(field, value, nestedPath);
boolQueryBuilder.must(query);
}
if (field.isAnnotationPresent(EsIn.class)) {
TermsQueryBuilder query = getInQuery(field, (List<?>) value, nestedPath);
boolQueryBuilder.must(query);
}
if (field.isAnnotationPresent(EsNotNull.class)) {
ExistsQueryBuilder query = getNotNullQuery(field, nestedPath);
boolQueryBuilder.must(query);
}
if (field.isAnnotationPresent(EsNotNullFields.class)) {
List<ExistsQueryBuilder> query = getNotNullQuery((List<String>) value, nestedPath);
Optional.ofNullable(query).orElse(new ArrayList<>())
.forEach(boolQueryBuilder::must);
}
if (field.isAnnotationPresent(EsNested.class)) {
NestedQueryBuilder query = getNestedQuery(field, value);
boolQueryBuilder.must(query);
}
}
} catch (Exception e) {
logger.info("ES查询解析异常:{}", e.getMessage());
}
return boolQueryBuilder;
}
private static TermsQueryBuilder getInQuery(Field field, List<?> value, String nestedPath) {
EsIn esIn = field.getAnnotation(EsIn.class);
String filedName = getFiledName(field, esIn.name(), nestedPath);
return QueryBuilders.termsQuery(filedName, value);
}
private static RangeQueryBuilder getRangeQuery(Field field, Object value, String nestedPath) {
EsRange esRange = field.getAnnotation(EsRange.class);
String filedName = getFiledName(field, esRange.name(), nestedPath);
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(filedName)
.includeLower(esRange.includeLower())
.includeUpper(esRange.includeUpper());
if (esRange.lt()) {
rangeQueryBuilder.gt(value);
}
if (esRange.gt()) {
rangeQueryBuilder.gt(value);
}
return rangeQueryBuilder;
}
private static MatchQueryBuilder getEqualsQuery(Field field, Object value, String nestedPath) {
EsEquals esEquals = field.getAnnotation(EsEquals.class);
String filedName = getFiledName(field, esEquals.name(), nestedPath);
return QueryBuilders.matchQuery(filedName, value);
}
private static WildcardQueryBuilder getLikeQuery(Field field, Object value, String nestedPath) {
String likeValue = (String) value;
EsLike esLike = field.getAnnotation(EsLike.class);
String filedName = getFiledName(field, esLike.name(), nestedPath);
if (esLike.leftLike()) {
likeValue = "*" + likeValue;
}
if (esLike.rightLike()) {
likeValue = likeValue + "*";
}
return QueryBuilders.wildcardQuery(filedName, likeValue);
}
private static ExistsQueryBuilder getNotNullQuery(Field field, String nestedPath) {
EsNotNull esNotNull = field.getAnnotation(EsNotNull.class);
String filedName = getFiledName(field, esNotNull.name(), nestedPath);
return QueryBuilders.existsQuery(filedName);
}
private static List<ExistsQueryBuilder> getNotNullQuery(List<String> value, String nestedPath) {
if (CollectionUtils.isEmpty(value)) {
return new ArrayList<>();
}
return value.stream()
.map(item-> getFiledName(item, nestedPath))
.map(QueryBuilders::existsQuery)
.collect(Collectors.toList());
}
private static NestedQueryBuilder getNestedQuery(Field field, Object object) {
EsNested esNested = field.getAnnotation(EsNested.class);
String nestedPath = getFiledName(field, esNested.name(), "");
QueryBuilder boolQueryBuilder = getBoolQueryBuilder(object, nestedPath);
return QueryBuilders.nestedQuery(nestedPath, boolQueryBuilder, ScoreMode.None);
}
private static String getFiledName(Field field, String name, String nestedPath) {
String fileName = name;
if (field != null) {
fileName = StringUtils.isBlank(name) ? field.getName() : name;
}
if (StringUtils.isBlank(nestedPath)) {
return fileName;
}
return nestedPath + "." + fileName;
}
private static String getFiledName(String name, String nestedPath) {
return getFiledName(null, name, nestedPath);
}
public static String captureName(String name) {
char[] cs = name.toCharArray();
cs[0] -= 32;
return String.valueOf(cs);
}
}
ES实现层调用工具类
public class EsDataServiceImpl implements EsDataService {
@Resource
private RestClient restClient;
@Resource
private ElasticsearchRestTemplate elasticsearchTemplate;
private static Gson gson = new Gson();
@Override
public <T> T save(T t) {
return elasticsearchTemplate.save(t);
}
@Override
public <T> boolean batchSave(List<T> tList) {
elasticsearchTemplate.save(tList);
return true;
}
@Override
public <T> boolean update(T t) {
return true;
}
@Override
public <T> boolean batchUpdate(List<T> tList) {
return true;
}
@Override
public <T> boolean delete(Class<T> clazz, String id) {
Annotation annotation = AnnotationUtils.getAnnotation(clazz, Document.class);
Document document = (Document) annotation;
IndexCoordinates index = IndexCoordinates.of(document.indexName());
elasticsearchTemplate.delete(id, index);
return true;
}
@Override
public <T> boolean batchDelete(Class<T> clazz, List<String> idList) {
Annotation annotation = AnnotationUtils.getAnnotation(clazz, Document.class);
Document document = (Document) annotation;
IndexCoordinates index = IndexCoordinates.of(document.indexName());
idList.forEach(id -> elasticsearchTemplate.delete(id, index));
return true;
}
@Override
public <T> T findById(Class<T> clazz, String id) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
queryBuilder.withQuery(QueryBuilders.matchQuery("_id", id));
SearchHit<T> searchHit = elasticsearchTemplate.searchOne(queryBuilder.build(), clazz);
return searchHit == null ? null : searchHit.getContent();
}
@Override
public <T> T findOne(Class<T> clazz, Query query) {
SearchHit<T> searchHit = elasticsearchTemplate.searchOne(query, clazz);
return searchHit == null ? null : searchHit.getContent();
}
@Override
public <T> T findOne(Class<T> clazz, EsPageable esBaseReq) {
Query query = EsQueryParse.convert2Query(esBaseReq);
SearchHit<T> searchHit = elasticsearchTemplate.searchOne(query, clazz);
return searchHit != null ? searchHit.getContent() : null;
}
@Override
public <T> EsResult<List<T>> findAll(Class<T> clazz) {
SearchHits<T> searchHits = elasticsearchTemplate.search(Query.findAll(), clazz);
List<T> data = searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
return EsResult.of(data, searchHits.getTotalHits());
}
@Override
public <T> EsResult<List<T>> findAll(Class<T> clazz, EsPageable pageable) {
Query query = new StringQuery(QueryBuilders.boolQuery().toString());
query.setPageable(EsPageable.getQueryPageable(pageable));
query.addSort(EsPageable.getQuerySort(pageable));
SearchHits<T> search = elasticsearchTemplate.search(query, clazz);
List<T> data = search.get().map(SearchHit::getContent).collect(Collectors.toList());
long recordCount = search.getTotalHits();
return EsResult.of(data, recordCount);
}
@Override
public <T> EsResult<List<T>> search(Class<T> clazz, Query query) {
SearchHits<T> searchHit = elasticsearchTemplate.search(query, clazz);
List<T> data = searchHit.get().map(SearchHit::getContent).collect(Collectors.toList());
long recordCount = searchHit.getTotalHits();
return EsResult.of(data, recordCount);
}
@Override
public <T> EsResult<List<T>> search(Class<T> t, EsPageable request) {
//组装查询
Query query = EsQueryParse.convert2Query(request);
//组装分页
query.setPageable(EsPageable.getQueryPageable(request));
//组装排序
query.addSort(EsPageable.getQuerySort(request));
SearchHits<T> searchHits = elasticsearchTemplate.search(query, t);
List<T> data = searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
long recordCount = searchHits.getTotalHits();
return EsResult.of(data, recordCount);
}
@Override
public <T> EsResult<List<T>> dslSearch(Class<T> t, String dsl) {
StringQuery stringQuery = new StringQuery(dsl);
SearchHits<T> searchHits = elasticsearchTemplate.search(stringQuery, t);
List<T> data = searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
long recordCount = searchHits.getTotalHits();
return EsResult.of(data, recordCount);
}
@Override
public <T> T sqlFindOne(Class<T> t, String sql) {
String queryStr = String.format("{"query":"%s", "fetch_size":1}", sql);
return restClientSearch(t, queryStr).stream().findFirst().orElse(null);
}
@Override
public <T> List<T> sqlSearch(Class<T> t, String sql) {
String queryStr = String.format("{"query":"%s"}", sql);
return restClientSearch(t, queryStr);
}
/**
* 使用restClient 查询数据
*
* @param t
* @param queryStr sql_dsl查询条件
* @return
*/
private <T> List<T> restClientSearch(Class<T> t, String queryStr) {
try {
Request request = new Request("POST", "/_xpack/sql");
request.setJsonEntity(queryStr);
Response response = restClient.performRequest(request);
String jsonData = EntityUtils.toString(response.getEntity());
SQLRestResponse sqlRestResponse = gson.fromJson(jsonData, SQLRestResponse.class);
SQLResult<T> sqlResult = ResultUtil.buildFetchSQLResult(sqlRestResponse, t, (SQLResult<T>) null);
return sqlResult.getDatas();
} catch (IOException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
}
总结
这套工具类经过我多次修改和调试可以完全适配ES的基本查询功能 ,下一期我准备把es的聚合查询工具类补上,希望大家喜欢,有意见也可以提,欢迎指正