diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Join.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Join.java
index 32065ea8..12b863a4 100644
--- a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Join.java
+++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Join.java
@@ -5,6 +5,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import static org.dromara.easyes.annotation.rely.AnnotationConstants.DEFAULT_JOIN_FIELD_NAME;
+
/**
* 父子类型
*
@@ -13,8 +15,24 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Join {
- String joinField() default "joinField";
+ /**
+ * join字段在es中的名字
+ *
+ * @return 索引中的join字段名称 默认为joinField
+ */
+ String joinField() default DEFAULT_JOIN_FIELD_NAME;
+
+ /**
+ * 根节点别名 不指定则默认使用加了当前注解的根类的名称小写作为根节点别名(推荐)
+ *
+ * @return 根节点别名
+ */
String rootAlias() default "";
- Child[] children() default {};
+ /**
+ * 非根节点
+ *
+ * @return 非根节点列表
+ */
+ Node[] nodes() default {};
}
diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Child.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Node.java
similarity index 75%
rename from easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Child.java
rename to easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Node.java
index c5eb2410..8da47c95 100644
--- a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Child.java
+++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/Node.java
@@ -12,9 +12,9 @@ import java.lang.annotation.Target;
**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
-public @interface Child {
+public @interface Node {
/**
- * 父文档别名 非必填,默认值为当前类名小写
+ * 父文档别名 非必填,不指定时默认值为parentClass类名小写(推荐)
*
* @return 父文档别名
*/
@@ -28,9 +28,9 @@ public @interface Child {
Class> parentClass();
/**
- * 子文档别名列表
+ * 子文档别名列表,不指定则为子文档类名小写列表(推荐) 若要自定义必须与childClasses数量和顺序一致
*
- * @return 子文档别名列表 非必填,默认值为子文档类名小写
+ * @return 子文档别名列表 非必填,默认值为子文档类名小写列表
*/
String[] childAliases() default {};
diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/AnnotationConstants.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/AnnotationConstants.java
index 097d6525..91e1d4aa 100644
--- a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/AnnotationConstants.java
+++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/AnnotationConstants.java
@@ -34,4 +34,8 @@ public interface AnnotationConstants {
* 默认索引别名
*/
String DEFAULT_ALIAS = "ee_default_alias";
+ /**
+ * 默认join字段名称
+ */
+ String DEFAULT_JOIN_FIELD_NAME = "joinField";
}
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Func.java b/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Func.java
index d7932245..6e2475b7 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Func.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Func.java
@@ -6,6 +6,7 @@ import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
@@ -13,8 +14,8 @@ import org.elasticsearch.search.sort.SortOrder;
import java.io.Serializable;
import java.util.*;
-import static org.dromara.easyes.common.constants.BaseEsConstants.DEFAULT_BOOST;
import static java.util.stream.Collectors.toList;
+import static org.dromara.easyes.common.constants.BaseEsConstants.DEFAULT_BOOST;
/**
* 高阶语法相关
@@ -1704,4 +1705,45 @@ public interface Func extends Serializable {
* @return wrapper
*/
Children mix(boolean condition, QueryBuilder queryBuilder);
+
+
+ /**
+ * 聚合桶排序
+ *
+ * @param bucketOrder 排序规则
+ * @return wrapper
+ */
+ default Children bucketOrder(BucketOrder bucketOrder) {
+ return bucketOrder(true, bucketOrder);
+ }
+
+ /**
+ * 聚合桶排序
+ *
+ * @param condition 条件
+ * @param bucketOrder 桶排序规则
+ * @return wrapper
+ */
+ default Children bucketOrder(boolean condition, BucketOrder bucketOrder) {
+ return bucketOrder(condition, Arrays.asList(bucketOrder));
+ }
+
+ /**
+ * 聚合桶排序
+ *
+ * @param bucketOrders 排序规则列表
+ * @return wrapper
+ */
+ default Children bucketOrder(List bucketOrders) {
+ return bucketOrder(true, bucketOrders);
+ }
+
+ /**
+ * 聚合桶排序
+ *
+ * @param condition 条件
+ * @param bucketOrders 排序规则列表
+ * @return wrapper
+ */
+ Children bucketOrder(boolean condition, List bucketOrders);
}
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Nested.java b/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Nested.java
index 94f4aefa..fd0d2527 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Nested.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/conditions/function/Nested.java
@@ -214,6 +214,15 @@ public interface Nested extends Serializable {
*/
Children hasChild(boolean condition, String type, Consumer consumer, ScoreMode scoreMode);
+ /**
+ * 父子类型-根据子查父匹配 返回子文档 无需指定父,由框架根据@Join注解自行推断其父
+ *
+ * @param consumer 嵌套条件函数
+ * @return wrapper
+ */
+ default Children hasParent(Consumer consumer) {
+ return hasParent(true, null, consumer);
+ }
/**
* 父子类型-根据子查父匹配 返回子文档
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractChainWrapper.java b/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractChainWrapper.java
index 3e8592b5..13336063 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractChainWrapper.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractChainWrapper.java
@@ -13,6 +13,7 @@ import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
@@ -654,6 +655,13 @@ public abstract class AbstractChainWrapper bucketOrders) {
+ getWrapper().bucketOrder(condition, bucketOrders);
+ return typedThis;
+ }
+
@Override
public Children select(String... columns) {
getWrapper().select(columns);
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractWrapper.java b/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractWrapper.java
index 711c3451..2f03f3b7 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractWrapper.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/core/AbstractWrapper.java
@@ -17,6 +17,7 @@ import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.geometry.Geometry;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
@@ -567,6 +568,14 @@ public abstract class AbstractWrapper bucketOrders) {
+ if (condition) {
+ this.bucketOrders = bucketOrders;
+ }
+ return typedThis;
+ }
+
@Override
public Children select(String... columns) {
this.include = columns;
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapper.java b/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapper.java
index a59954e3..0452e774 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapper.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapper.java
@@ -224,11 +224,21 @@ public interface BaseEsMapper {
/**
* 插入一条记录 可指定路由
*
- * @param entity 插入的数据对象
* @param routing 路由
+ * @param entity 插入的数据对象
* @return 成功条数
*/
- Integer insert(T entity, String routing);
+ Integer insert(String routing, T entity);
+
+ /**
+ * 父子类型 插入一条记录 可指定路由, 父id
+ *
+ * @param routing 路由
+ * @param parentId 父id
+ * @param entity 插入的数据对象
+ * @return 成功条数
+ */
+ Integer insert(String routing, String parentId, T entity);
/**
* 插入一条记录,可指定多索引插入
@@ -240,7 +250,7 @@ public interface BaseEsMapper {
Integer insert(T entity, String... indexNames);
/**
- * 插入一条记录,可指定路由及多索引插入
+ * 插入数据,可指定路由及多索引插入
*
* @param routing 路由
* @param entity 插入的数据对象
@@ -249,6 +259,16 @@ public interface BaseEsMapper {
*/
Integer insert(String routing, T entity, String... indexNames);
+ /**
+ * 父子类型 插入数据,可指定路由,父id及多索引插入
+ *
+ * @param routing 路由
+ * @param parentId 父id
+ * @param entity 插入的数据对象
+ * @param indexNames 指定插入的索引名数组
+ * @return 总成功条数
+ */
+ Integer insert(String routing, String parentId, T entity, String... indexNames);
/**
* 批量插入
@@ -261,11 +281,21 @@ public interface BaseEsMapper {
/**
* 批量插入 可指定路由
*
- * @param entityList 插入的数据对象列表
* @param routing 路由
+ * @param entityList 插入的数据对象列表
* @return 总成功条数
*/
- Integer insertBatch(Collection entityList, String routing);
+ Integer insertBatch(String routing, Collection entityList);
+
+ /**
+ * 父子类型 批量插入 可指定路由, 父id
+ *
+ * @param routing 路由
+ * @param parentId 父id
+ * @param entityList 插入的数据对象列表
+ * @return 总成功条数
+ */
+ Integer insertBatch(String routing, String parentId, Collection entityList);
/**
* 批量插入 可指定多索引
@@ -286,6 +316,17 @@ public interface BaseEsMapper {
*/
Integer insertBatch(String routing, Collection entityList, String... indexNames);
+ /**
+ * 父子类型 批量插入 可指定路由,父id及多索引
+ *
+ * @param routing 路由
+ * @param parentId 父id
+ * @param entityList 插入的数据对象列表
+ * @param indexNames 指定插入的索引名数组
+ * @return 总成功条数
+ */
+ Integer insertBatch(String routing, String parentId, Collection entityList, String... indexNames);
+
/**
* 根据 ID 删除
*
@@ -297,11 +338,11 @@ public interface BaseEsMapper {
/**
* 根据 ID 删除 可指定路由
*
- * @param id 主键
* @param routing 路由
+ * @param id 主键
* @return 成功条数
*/
- Integer deleteById(Serializable id, String routing);
+ Integer deleteById(String routing, Serializable id);
/**
* 根据 ID 删除 可指定多索引
@@ -334,11 +375,11 @@ public interface BaseEsMapper {
/**
* 删除(根据ID 批量删除)可指定路由
*
- * @param idList 主键列表
* @param routing 路由
+ * @param idList 主键列表
* @return 总成功条数
*/
- Integer deleteBatchIds(Collection extends Serializable> idList, String routing);
+ Integer deleteBatchIds(String routing, Collection extends Serializable> idList);
/**
* 删除(根据ID 批量删除)
@@ -378,11 +419,11 @@ public interface BaseEsMapper {
/**
* 根据 ID 更新 可指定路由
*
- * @param entity 更新对象
* @param routing 路由
+ * @param entity 更新对象
* @return 总成功条数
*/
- Integer updateById(T entity, String routing);
+ Integer updateById(String routing, T entity);
/**
* 根据 ID 更新 可指定多索引
@@ -414,11 +455,11 @@ public interface BaseEsMapper {
/**
* 根据ID 批量更新 可指定路由
*
- * @param entityList 更新对象列表
* @param routing 路由
+ * @param entityList 更新对象列表
* @return 总成功条数
*/
- Integer updateBatchByIds(Collection entityList, String routing);
+ Integer updateBatchByIds(String routing, Collection entityList);
/**
* 根据ID 批量更新 可指定多索引
@@ -459,11 +500,11 @@ public interface BaseEsMapper {
/**
* 根据 ID 查询 可指定路由
*
- * @param id 主键
* @param routing 路由
+ * @param id 主键
* @return 指定的返回对象
*/
- T selectById(Serializable id, String routing);
+ T selectById(String routing, Serializable id);
/**
* 根据 ID 查询 可指定多索引
@@ -493,13 +534,13 @@ public interface BaseEsMapper {
List selectBatchIds(Collection extends Serializable> idList);
/**
- * 查询(根据ID 批量查询)
+ * 查询(根据ID 批量查询) 可指定路由
*
- * @param idList 主键列表
* @param routing 路由
+ * @param idList 主键列表
* @return 指定的返回对象列表
*/
- List selectBatchIds(Collection extends Serializable> idList, String routing);
+ List selectBatchIds(String routing, Collection extends Serializable> idList);
/**
* 查询(根据ID 批量查询) 可指定多索引
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java b/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java
index 3af44f6b..df80b932 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java
@@ -330,48 +330,66 @@ public class BaseEsMapperImpl implements BaseEsMapper {
@Override
public Integer insert(T entity) {
- Assert.notNull(entity, "insert entity must not be null");
- return insert(null, entity, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
+ return insert(null, null, entity, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@Override
- public Integer insert(T entity, String routing) {
- Assert.notNull(entity, "insert entity must not be null");
- return insert(routing, entity, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
+ public Integer insert(String routing, T entity) {
+ return insert(routing, null, entity, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
+ }
+
+ @Override
+ public Integer insert(String routing, String parentId, T entity) {
+ return insert(routing, parentId, entity, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@Override
public Integer insert(T entity, String... indexNames) {
- return insert(null, entity, indexNames);
+ return insert(null, null, entity, indexNames);
}
@Override
public Integer insert(String routing, T entity, String... indexNames) {
+ return insert(routing, null, entity, indexNames);
+ }
+
+ @Override
+ public Integer insert(String routing, String parentId, T entity, String... indexNames) {
Assert.notNull(entity, "insert entity must not be null");
// 执行插入
return Arrays.stream(getIndexNames(indexNames))
- .mapToInt(indexName -> doInsert(entity, routing, indexName))
+ .mapToInt(indexName -> doInsert(entity, routing, parentId, indexName))
.sum();
}
@Override
public Integer insertBatch(Collection entityList) {
- return insertBatch(null, entityList, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
+ return insertBatch(null, null, entityList, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@Override
- public Integer insertBatch(Collection entityList, String routing) {
+ public Integer insertBatch(String routing, Collection entityList) {
return insertBatch(routing, entityList, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
+ @Override
+ public Integer insertBatch(String routing, String parentId, Collection entityList) {
+ return insertBatch(routing, parentId, entityList, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
+ }
+
@Override
public Integer insertBatch(Collection entityList, String... indexNames) {
- return insertBatch(null, entityList, indexNames);
+ return insertBatch(null, null, entityList, indexNames);
}
@Override
public Integer insertBatch(String routing, Collection entityList, String... indexNames) {
+ return insertBatch(routing, null, entityList, indexNames);
+ }
+
+ @Override
+ public Integer insertBatch(String routing, String parentId, Collection entityList, String... indexNames) {
// 老汉裤子都脱了 你告诉我没有数据 怎么*入?
if (CollectionUtils.isEmpty(entityList)) {
return BaseEsConstants.ZERO;
@@ -379,7 +397,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
// 在每条指定的索引上批量执行数据插入
return Arrays.stream(getIndexNames(indexNames))
- .mapToInt(indexName -> doInsertBatch(entityList, routing, indexName))
+ .mapToInt(indexName -> doInsertBatch(entityList, routing, parentId, indexName))
.sum();
}
@@ -389,7 +407,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
}
@Override
- public Integer deleteById(Serializable id, String routing) {
+ public Integer deleteById(String routing, Serializable id) {
return deleteById(routing, id, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@@ -411,7 +429,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
}
@Override
- public Integer deleteBatchIds(Collection extends Serializable> idList, String routing) {
+ public Integer deleteBatchIds(String routing, Collection extends Serializable> idList) {
return deleteBatchIds(routing, idList, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@@ -457,7 +475,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
}
@Override
- public Integer updateById(T entity, String routing) {
+ public Integer updateById(String routing, T entity) {
return updateById(routing, entity, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@@ -485,7 +503,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
}
@Override
- public Integer updateBatchByIds(Collection entityList, String routing) {
+ public Integer updateBatchByIds(String routing, Collection entityList) {
return updateBatchByIds(routing, entityList, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@@ -524,7 +542,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
}
@Override
- public T selectById(Serializable id, String routing) {
+ public T selectById(String routing, Serializable id) {
return selectById(routing, id, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@@ -553,7 +571,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
}
@Override
- public List selectBatchIds(Collection extends Serializable> idList, String routing) {
+ public List selectBatchIds(String routing, Collection extends Serializable> idList) {
return selectBatchIds(routing, idList, EntityInfoHelper.getEntityInfo(entityClass).getIndexName());
}
@@ -686,12 +704,14 @@ public class BaseEsMapperImpl implements BaseEsMapper {
*
* @param entity 插入对象
* @param routing 路由
+ * @param parentId 父id
* @param indexName 索引名
* @return 成功条数
*/
- private Integer doInsert(T entity, String routing, String indexName) {
+ private Integer doInsert(T entity, String routing, String parentId, String indexName) {
// 构建请求入参
- IndexRequest indexRequest = buildIndexRequest(entity, routing, indexName);
+ IndexRequest indexRequest = buildIndexRequest(entity, routing, parentId, indexName);
+
Optional.ofNullable(routing).ifPresent(indexRequest::routing);
indexRequest.setRefreshPolicy(getRefreshPolicy());
@@ -716,16 +736,17 @@ public class BaseEsMapperImpl implements BaseEsMapper {
*
* @param entityList 数据列表
* @param routing 路由
+ * @param parentId 父id
* @param indexName 索引名
* @return 总成功条数
*/
- private Integer doInsertBatch(Collection entityList, String routing, String indexName) {
+ private Integer doInsertBatch(Collection entityList, String routing, String parentId, String indexName) {
// 构建批量请求参数
BulkRequest bulkRequest = new BulkRequest();
Optional.ofNullable(routing).ifPresent(bulkRequest::routing);
bulkRequest.setRefreshPolicy(getRefreshPolicy());
entityList.forEach(entity -> {
- IndexRequest indexRequest = buildIndexRequest(entity, routing, indexName);
+ IndexRequest indexRequest = buildIndexRequest(entity, routing, parentId, indexName);
bulkRequest.add(indexRequest);
});
@@ -1033,10 +1054,11 @@ public class BaseEsMapperImpl implements BaseEsMapper {
*
* @param entity 实体
* @param routing 路由
+ * @param parentId 父id
* @param indexName 索引名
* @return es请求参数
*/
- private IndexRequest buildIndexRequest(T entity, String routing, String indexName) {
+ private IndexRequest buildIndexRequest(T entity, String routing, String parentId, String indexName) {
IndexRequest indexRequest = new IndexRequest();
// id预处理,除下述情况,其它情况使用es默认的id
@@ -1058,7 +1080,7 @@ public class BaseEsMapperImpl implements BaseEsMapper {
joinField.setName(entityInfo.getJoinAlias());
if (entityInfo.isChild()) {
// 子类型,需要追加父
- joinField.setParent(routing);
+ joinField.setParent(parentId);
}
jsonObject.put(entityInfo.getJoinFieldName(), joinField);
jsonData = jsonObject.toJSONString();
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/core/Wrapper.java b/easy-es-core/src/main/java/org/dromara/easyes/core/core/Wrapper.java
index d842d689..8d3a2daf 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/core/Wrapper.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/core/Wrapper.java
@@ -4,6 +4,7 @@ package org.dromara.easyes.core.core;
import lombok.SneakyThrows;
import org.dromara.easyes.core.biz.*;
import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import java.util.LinkedList;
@@ -78,6 +79,11 @@ public abstract class Wrapper implements Cloneable {
*/
protected List aggregationParamList;
+ /**
+ * 聚合桶排序规则列表
+ */
+ List bucketOrders;
+
/**
* 排序参数列表
*/
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/core/WrapperProcessor.java b/easy-es-core/src/main/java/org/dromara/easyes/core/core/WrapperProcessor.java
index 968e995e..82816bbe 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/core/WrapperProcessor.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/core/WrapperProcessor.java
@@ -21,6 +21,7 @@ import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.join.query.ParentIdQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.collapse.CollapseBuilder;
@@ -246,7 +247,9 @@ public class WrapperProcessor {
setBool(bool, nestedQueryBuilder, param.getPrevQueryType());
break;
case HAS_PARENT:
- realField = getRealField(param.getColumn(), mappingColumnMap);
+ // 如果用户没指定type框架可根据entityInfo上下文自行推断出其父type
+ String column = Optional.ofNullable(param.getColumn()).orElse(entityInfo.getParentJoinAlias());
+ realField = getRealField(column, mappingColumnMap);
queryBuilder = getBool(children, QueryBuilders.boolQuery(), entityInfo, param.getColumn());
HasParentQueryBuilder hasParentQueryBuilder = new HasParentQueryBuilder(realField, queryBuilder, (boolean) param.getVal());
setBool(bool, hasParentQueryBuilder, param.getPrevQueryType());
@@ -555,7 +558,7 @@ public class WrapperProcessor {
AggregationBuilder cursor = null;
for (AggregationParam aggParam : aggregationParamList) {
String realField = getRealField(aggParam.getField(), mappingColumnMap);
- AggregationBuilder builder = getRealAggregationBuilder(aggParam.getAggregationType(), aggParam.getName(), realField);
+ AggregationBuilder builder = getRealAggregationBuilder(aggParam.getAggregationType(), aggParam.getName(), realField, wrapper.size, wrapper.bucketOrders);
if (aggParam.isEnablePipeline()) {
// 管道聚合, 构造聚合树
if (root == null) {
@@ -588,9 +591,10 @@ public class WrapperProcessor {
* @param aggType 聚合类型
* @param name 聚合返回桶的名称 保持原字段名称
* @param realField 原字段名称
+ * @param size 聚合桶大小
* @return 聚合建造者
*/
- private static AggregationBuilder getRealAggregationBuilder(AggregationTypeEnum aggType, String name, String realField) {
+ private static AggregationBuilder getRealAggregationBuilder(AggregationTypeEnum aggType, String name, String realField, Integer size, List bucketOrders) {
AggregationBuilder aggregationBuilder;
// 解决同一个字段聚合多次,如min(starNum), max(starNum) 字段名重复问题
name += aggType.getValue();
@@ -608,7 +612,10 @@ public class WrapperProcessor {
aggregationBuilder = AggregationBuilders.sum(name).field(realField);
break;
case TERMS:
- aggregationBuilder = AggregationBuilders.terms(name).field(realField);
+ TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(name).field(realField);
+ Optional.ofNullable(size).ifPresent(termsAggregationBuilder::size);
+ Optional.ofNullable(bucketOrders).ifPresent(termsAggregationBuilder::order);
+ aggregationBuilder = termsAggregationBuilder;
break;
default:
throw new UnsupportedOperationException("不支持的聚合类型,参见AggregationTypeEnum");
diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java
index 6f37779f..dc4dd0bc 100644
--- a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java
+++ b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java
@@ -107,7 +107,7 @@ public class EntityInfoHelper {
*/
private static void initJoin(Class> clazz, GlobalConfig globalConfig, EntityInfo entityInfo) {
Join join = clazz.getAnnotation(Join.class);
- if (join == null || ArrayUtils.isEmpty(join.children())) {
+ if (join == null || ArrayUtils.isEmpty(join.nodes())) {
return;
}
boolean camelCase = globalConfig.getDbConfig().isMapUnderscoreToCamelCase();
@@ -119,7 +119,7 @@ public class EntityInfoHelper {
entityInfo.setJoinAlias(underlineJoinAlias);
Map> relationMap = entityInfo.getRelationMap();
- Arrays.stream(join.children())
+ Arrays.stream(join.nodes())
.forEach(child -> {
String parentAlias = StringUtils.isBlank(child.parentAlias()) ? child.parentClass().getSimpleName().toLowerCase() : child.parentAlias();
String underlineParentAlias = camelToUnderline(parentAlias, camelCase);
diff --git a/easy-es-sample/src/main/java/org/dromara/easyes/sample/entity/Document.java b/easy-es-sample/src/main/java/org/dromara/easyes/sample/entity/Document.java
index 2217523f..b6358673 100644
--- a/easy-es-sample/src/main/java/org/dromara/easyes/sample/entity/Document.java
+++ b/easy-es-sample/src/main/java/org/dromara/easyes/sample/entity/Document.java
@@ -2,10 +2,7 @@ package org.dromara.easyes.sample.entity;
import lombok.Data;
import lombok.experimental.Accessors;
-import org.dromara.easyes.annotation.HighLight;
-import org.dromara.easyes.annotation.IndexField;
-import org.dromara.easyes.annotation.IndexId;
-import org.dromara.easyes.annotation.IndexName;
+import org.dromara.easyes.annotation.*;
import org.dromara.easyes.annotation.rely.Analyzer;
import org.dromara.easyes.annotation.rely.FieldStrategy;
import org.dromara.easyes.annotation.rely.FieldType;
@@ -18,7 +15,8 @@ import org.dromara.easyes.annotation.rely.IdType;
**/
@Data
@Accessors(chain = true)
-@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true, maxResultWindow = 100)
+@Settings(shardsNum = 3, replicasNum = 2, maxResultWindow = 1000)
+@IndexName(value = "easyes_document", keepGlobalPrefix = true)
public class Document {
/**
* es中的唯一id,如果你想自定义es中的id为你提供的id,比如MySQL中的id,请将注解中的type指定为customize或直接在全局配置文件中指定,如此id便支持任意数据类型)
diff --git a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Author.java b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Author.java
index cf335dd1..0ccbdf9e 100644
--- a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Author.java
+++ b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Author.java
@@ -3,26 +3,25 @@ package org.dromara.easyes.test.entity;
import lombok.Data;
import org.dromara.easyes.annotation.IndexField;
-import org.dromara.easyes.annotation.IndexName;
-import org.dromara.easyes.annotation.rely.Analyzer;
+import org.dromara.easyes.annotation.IndexId;
import org.dromara.easyes.annotation.rely.FieldType;
/**
- * es 作者 数据模型 Document的子文档,Document是其父文档
+ * 作者 数据模型 Document的子文档,Document是其父文档
*
- * Copyright © 2021 xpc1024 All Rights Reserved
+ * Copyright © 2024 xpc1024 All Rights Reserved
**/
@Data
public class Author {
/**
* 作者id
*/
- @IndexField(fieldType = FieldType.KEYWORD)
+ @IndexId
private String authorId;
/**
* 作者姓名
*/
- @IndexField(fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART, searchAnalyzer = Analyzer.IK_SMART)
+ @IndexField(fieldType = FieldType.KEYWORD)
private String authorName;
}
diff --git a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Contact.java b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Contact.java
index b9d5a07f..2de73225 100644
--- a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Contact.java
+++ b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Contact.java
@@ -3,25 +3,25 @@ package org.dromara.easyes.test.entity;
import lombok.Data;
import org.dromara.easyes.annotation.IndexField;
-import org.dromara.easyes.annotation.IndexName;
+import org.dromara.easyes.annotation.IndexId;
import org.dromara.easyes.annotation.rely.FieldType;
/**
- * es 联系方式 数据模型 Author的子文档,Author是其父文档
+ * 联系方式 数据模型 Author的子文档,Author是其父文档,Document是其爷文档
*
- * Copyright © 2021 xpc1024 All Rights Reserved
+ * Copyright © 2024 xpc1024 All Rights Reserved
**/
@Data
public class Contact {
/**
- * 手机号
+ * 联系人id
*/
- @IndexField(fieldType = FieldType.KEYWORD)
- private String phone;
+ @IndexId
+ private String contactId;
/**
- * 邮箱
+ * 地址
*/
@IndexField(fieldType = FieldType.TEXT)
- private String email;
+ private String address;
}
diff --git a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java
index 94e09ebc..46b8eb63 100644
--- a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java
+++ b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java
@@ -11,7 +11,14 @@ import java.math.BigDecimal;
import java.util.List;
/**
- * es 数据模型
+ * es 数据模型 其中Join父子类型结构如下所示
+ *
+ * Document
+ * / \
+ * Comment Author
+ * \
+ * Contact
+ *
*
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@@ -19,7 +26,7 @@ import java.util.List;
@Accessors(chain = true)
@Settings(shardsNum = 3, replicasNum = 2, settingsProvider = MySettingsProvider.class)
@IndexName(value = "easyes_document", keepGlobalPrefix = true, refreshPolicy = RefreshPolicy.IMMEDIATE)
-@Join(children = {@Child(parentClass = Document.class, childClasses = {Author.class, Comment.class}), @Child(parentClass = Author.class, childClasses = Contact.class)})
+@Join(nodes = {@Node(parentClass = Document.class, childClasses = {Author.class, Comment.class}), @Node(parentClass = Author.class, childClasses = Contact.class)})
public class Document {
/**
* es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等.
diff --git a/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/AuthorMapper.java b/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/AuthorMapper.java
index 8703b7ab..d9d666dc 100644
--- a/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/AuthorMapper.java
+++ b/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/AuthorMapper.java
@@ -1,6 +1,7 @@
package org.dromara.easyes.test.mapper;
+import org.dromara.easyes.annotation.EsDS;
import org.dromara.easyes.core.core.BaseEsMapper;
import org.dromara.easyes.test.entity.Author;
@@ -9,5 +10,6 @@ import org.dromara.easyes.test.entity.Author;
*
* Copyright © 2024 xpc1024 All Rights Reserved
**/
+@EsDS("ds1")
public interface AuthorMapper extends BaseEsMapper {
}
diff --git a/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/ContactMapper.java b/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/ContactMapper.java
index d8d1221b..1cac7ecc 100644
--- a/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/ContactMapper.java
+++ b/easy-es-test/src/main/java/org/dromara/easyes/test/mapper/ContactMapper.java
@@ -1,6 +1,7 @@
package org.dromara.easyes.test.mapper;
+import org.dromara.easyes.annotation.EsDS;
import org.dromara.easyes.core.core.BaseEsMapper;
import org.dromara.easyes.test.entity.Contact;
@@ -9,5 +10,6 @@ import org.dromara.easyes.test.entity.Contact;
*
* Copyright © 2024 xpc1024 All Rights Reserved
**/
+@EsDS("ds1")
public interface ContactMapper extends BaseEsMapper {
}
diff --git a/easy-es-test/src/test/java/org/dromara/easyes/test/join/JoinTest.java b/easy-es-test/src/test/java/org/dromara/easyes/test/join/JoinTest.java
index 8ec57c4b..3860de8f 100644
--- a/easy-es-test/src/test/java/org/dromara/easyes/test/join/JoinTest.java
+++ b/easy-es-test/src/test/java/org/dromara/easyes/test/join/JoinTest.java
@@ -6,9 +6,13 @@ import org.dromara.easyes.core.conditions.update.LambdaEsUpdateWrapper;
import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.core.toolkit.FieldUtils;
import org.dromara.easyes.test.TestEasyEsApplication;
+import org.dromara.easyes.test.entity.Author;
import org.dromara.easyes.test.entity.Comment;
+import org.dromara.easyes.test.entity.Contact;
import org.dromara.easyes.test.entity.Document;
+import org.dromara.easyes.test.mapper.AuthorMapper;
import org.dromara.easyes.test.mapper.CommentMapper;
+import org.dromara.easyes.test.mapper.ContactMapper;
import org.dromara.easyes.test.mapper.DocumentMapper;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;
@@ -17,7 +21,16 @@ import javax.annotation.Resource;
import java.util.List;
/**
- * 父子类型测试
+ * 父子类型测试 其结构如下所示,Document文档有子文档Author(作者)和Comment(评论),其中Author还有个子文档Contact(联系方式)
+ * 下述结构可参考加在Document上的自定义注解@Join和@Node来表达
+ *
+ * Document
+ * / \
+ * Comment Author
+ * \
+ * Contact
+ *
+ *
*
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@@ -29,6 +42,16 @@ public class JoinTest {
private DocumentMapper documentMapper;
@Resource
private CommentMapper commentMapper;
+ @Resource
+ private AuthorMapper authorMapper;
+ @Resource
+ private ContactMapper contactMapper;
+
+ /**
+ * 固定路由,确保后续CRUD中所有父子文档均在统一分片上
+ */
+ private final static String FIXED_ROUTING = "testRouting";
+
@Test
@Order(0)
@@ -41,29 +64,59 @@ public class JoinTest {
@Test
@Order(1)
public void testInsert() throws InterruptedException {
- // 测试新增父子文档,此处开启自动挡模式,父子类型索引已被自动处理
// 新新增父文档,然后再插入子文档
String parentId = "doc-1";
- Document document = new Document();
- // 此处id为自定义id,也可去掉注解@IndexId(type = IdType.CUSTOMIZE),让es自行生成id(推荐), insert完成后 es生成的id直接从document中取获取
- document.setEsId(parentId);
- document.setTitle("我是父文档的标题");
- document.setContent("我是父文档的内容 father content ");
- documentMapper.insert(document);
+ Document root = new Document();
+ root.setEsId(parentId);
+ root.setTitle("我是父文档的标题");
+ root.setContent("father doc");
+ documentMapper.insert(FIXED_ROUTING, root);
+ Thread.sleep(2000);
- // 插入子文档
- Comment comment = new Comment();
- comment.setId("comment-1");
- comment.setCommentContent("test1");
- // 这里特别注意,子文档必须指定其路由为父亲的id,否则傻儿子找不到爹别怪我没提醒 (es语法如此,非框架限制)
- commentMapper.insert(comment, parentId);
+ // 插入子文档1
+ Comment nodeA1 = new Comment();
+ nodeA1.setId("comment-1");
+ nodeA1.setCommentContent("test1");
+ // 这里特别注意,子文档必须指定其路由和父亲文档相同,否则傻儿子找不到爹别怪我没提醒 (es语法如此,非框架限制)
+ commentMapper.insert(FIXED_ROUTING, parentId, nodeA1);
// 插入子文档2
- Comment comment1 = new Comment();
- comment1.setId("comment-2");
- comment1.setCommentContent("test2");
- commentMapper.insert(comment1, parentId);
+ Comment nodeA2 = new Comment();
+ nodeA2.setId("comment-2");
+ nodeA2.setCommentContent("test2");
+ commentMapper.insert(FIXED_ROUTING, parentId, nodeA2);
+
+ // 插入子文档3
+ Author nodeB1 = new Author();
+ nodeB1.setAuthorId("author-1");
+ nodeB1.setAuthorName("tom");
+ authorMapper.insert(FIXED_ROUTING, parentId, nodeB1);
+
+ // 插入子文档4
+ Author nodeB2 = new Author();
+ nodeB2.setAuthorId("author-2");
+ nodeB2.setAuthorName("cat");
+ authorMapper.insert(FIXED_ROUTING, parentId, nodeB2);
+ Thread.sleep(2000);
+
+ // 插入孙子文档1(把孙子1挂在子文档3上)
+ Contact child1 = new Contact();
+ child1.setContactId("contact-1");
+ child1.setAddress("zhejiang province");
+ contactMapper.insert(FIXED_ROUTING, nodeB1.getAuthorId(), child1);
+
+ // 插入孙子文档2(把孙子2挂在子文档3上)
+ Contact child2 = new Contact();
+ child2.setContactId("contact-2");
+ child2.setAddress("hangzhou city");
+ contactMapper.insert(FIXED_ROUTING, nodeB1.getAuthorId(), child2);
+
+ // 插入孙子文档3(把孙子3挂在子文档4上)
+ Contact child3 = new Contact();
+ child3.setContactId("contact-3");
+ child3.setAddress("binjiang region");
+ contactMapper.insert(FIXED_ROUTING, nodeB2.getAuthorId(), child3);
// es写入数据有延迟 适当休眠 保证后续查询结果正确
Thread.sleep(2000);
@@ -72,25 +125,49 @@ public class JoinTest {
@Test
@Order(2)
public void testSelect() {
- // 温馨提示,下面wrapper中的type实际上就是JoinField字段注解@TableField中指定的parentName和childName,与原生语法是一致的
+ // 温馨提示,下面wrapper中的type实际上就是索引JoinField中指定的父子名称,与原生语法是一致的
// case1: hasChild查询,返回的是相关的父文档 所以查询用父文档实体及其mapper
LambdaEsQueryWrapper documentWrapper = new LambdaEsQueryWrapper<>();
documentWrapper.hasChild("comment", w -> w.eq(FieldUtils.val(Comment::getCommentContent), "test1"));
List documents = documentMapper.selectList(documentWrapper);
System.out.println(documents);
+ LambdaEsQueryWrapper authorWrapper = new LambdaEsQueryWrapper<>();
+ authorWrapper.hasChild("contact", w -> w.match(FieldUtils.val(Contact::getAddress), "city"));
+ List authors = authorMapper.selectList(authorWrapper);
+ System.out.println(authors);
+
// case2: hasParent查询,返回的是相关的子文档 所以查询用子文档实体及其mapper
LambdaEsQueryWrapper commentWrapper = new LambdaEsQueryWrapper<>();
+ commentWrapper.like(Comment::getCommentContent, "test");
// 字段名称你也可以不用FieldUtils.val,直接传入字符串也行
- commentWrapper.hasParent("document", w -> w.match("content", "father").or().match("content", "content"));
+ commentWrapper.hasParent("document", w -> w.match("content", "father"));
List comments = commentMapper.selectList(commentWrapper);
System.out.println(comments);
+ // case2.1: 孙子查爹的情况
+ LambdaEsQueryWrapper contactWrapper = new LambdaEsQueryWrapper<>();
+ contactWrapper.hasParent("author", w -> w.eq(FieldUtils.val(Author::getAuthorName), "cat"));
+ List contacts = contactMapper.selectList(contactWrapper);
+ System.out.println(contacts);
+
+ // case2.2: 2.1的简写
+ LambdaEsQueryWrapper contactWrapper1 = new LambdaEsQueryWrapper<>();
+ // hasParent之所以可以不指定parentType简写是因为框架可以通过@Join注解中指定的父子关系自动推断出其父type,因此用户可以不指定父type直接查询,但hasChild不能简写,因为一个父亲可能有多个孩子,但一个孩子只能有一个亲爹
+ contactWrapper1.hasParent(w -> w.eq(FieldUtils.val(Author::getAuthorName), "cat"));
+ List contacts1 = contactMapper.selectList(contactWrapper1);
+ System.out.println(contacts1);
+
// case3: parentId查询,返回的是相关的子文档,与case2类似,所以查询用子文档实体及其mapper
commentWrapper = new LambdaEsQueryWrapper<>();
commentWrapper.parentId("doc-1", "comment");
List commentList = commentMapper.selectList(commentWrapper);
System.out.println(commentList);
+
+ contactWrapper = new LambdaEsQueryWrapper<>();
+ contactWrapper.parentId("author-2", "contact");
+ List contactList = contactMapper.selectList(contactWrapper);
+ System.out.println(contactList);
}
@Test
@@ -100,13 +177,19 @@ public class JoinTest {
Document document = new Document();
document.setEsId("doc-1");
document.setTitle("我是隔壁老王标题");
- documentMapper.updateById(document);
+ documentMapper.updateById(FIXED_ROUTING, document);
+
+ Contact contact = new Contact();
+ contact.setContactId("contact-2");
+ contact.setAddress("update address");
+ contactMapper.updateById(FIXED_ROUTING, contact);
// case2: 父文档/子文档 根据各自条件更新
Comment comment = new Comment();
- comment.setCommentContent("我是隔壁老王的评论");
+ comment.setCommentContent("update comment content");
LambdaEsUpdateWrapper wrapper = new LambdaEsUpdateWrapper<>();
- wrapper.match(Comment::getCommentContent, "comment");
+ wrapper.eq(Comment::getCommentContent, "test1");
+ wrapper.routing(FIXED_ROUTING);
commentMapper.update(comment, wrapper);
}
@@ -114,11 +197,12 @@ public class JoinTest {
@Order(4)
public void testDelete() {
// case1: 父文档/子文档 根据各自的id删除
- documentMapper.deleteById("doc-1");
+ documentMapper.deleteById(FIXED_ROUTING, "doc-1");
//case2: 父文档/子文档 根据各自条件删除
LambdaEsQueryWrapper wrapper = new LambdaEsQueryWrapper<>();
- wrapper.match(Comment::getCommentContent, "comment");
+ wrapper.like(Comment::getCommentContent, "test")
+ .routing(FIXED_ROUTING);
commentMapper.delete(wrapper);
}
diff --git a/easy-es-test/src/test/resources/application.yml b/easy-es-test/src/test/resources/application.yml
index 69d30eaa..d7fc1524 100644
--- a/easy-es-test/src/test/resources/application.yml
+++ b/easy-es-test/src/test/resources/application.yml
@@ -16,7 +16,7 @@ easy-es:
field-strategy: not_empty
refresh-policy: immediate
enable-track-total-hits: true
-# index-prefix: dev_
+ # index-prefix: dev_
dynamic:
datasource:
ds1: