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