feat: 主键字段也可以自定义es中名称

This commit is contained in:
jaime 2025-02-26 12:02:07 +08:00
parent 4f193f0f24
commit 42aef5f199
24 changed files with 657 additions and 571 deletions

View File

@ -90,7 +90,7 @@ Easy-Es是一款简化ElasticSearch搜索引擎操作的开源框架,全自动
TermsQueryBuilder creatorTerm = QueryBuilders.termsQuery("creator", "码保国");
boolQueryBuilder.must(titleTerm);
boolQueryBuilder.must(creatorTerm);
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
try {

View File

@ -77,7 +77,7 @@ String indexName = "document";
TermsQueryBuilder creatorTerm = QueryBuilders.termsQuery("creator", "Guy");
boolQueryBuilder.must(titleTerm);
boolQueryBuilder.must(creatorTerm);
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
try {

View File

@ -15,6 +15,14 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface IndexId {
/**
* 自定义字段在es中的名称
*
* @return 字段在es中的名称
*/
String value() default "";
/**
* 主键ID
*

View File

@ -15,6 +15,14 @@ public class JoinField {
*/
private String parent;
public JoinField() {
}
public JoinField(String name, String parent) {
this.name = name;
this.parent = parent;
}
public String getName() {
return name;
}

View File

@ -0,0 +1,40 @@
package org.dromara.easyes.common.join;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
@Setter
public class BaseJoin {
public Map<String, Map<String, String>> joinFiled;
@JsonAnyGetter
public Map<String, Map<String, String>> getJoinField() {
return joinFiled;
}
/**
* 添加join字段信息. json示例如下:
* "fieldName": {
* "name": xxx,
* "parentId": xxx
* }
*
* @param fieldName join字段名称(json中的key)
* @param name 名称
* @param parentId 父id
*/
public void addJoinField(String fieldName, String name, String parentId) {
joinFiled = new HashMap<>() {{
put(fieldName, new HashMap<>() {{
put("name", name);
if (parentId != null) {
put("parent", parentId);
}
}});
}};
}
}

View File

@ -119,7 +119,7 @@ public class EsClientUtils {
return requestConfigBuilder;
});
return new ElasticsearchClient(new RestClientTransport(builder.build(), new JacksonJsonpMapper(JsonUtils.base())));
return new ElasticsearchClient(new RestClientTransport(builder.build(), new JacksonJsonpMapper(JsonUtils.OM_DEFAULT)));
}
public ElasticsearchClient getClient(String clientId) {

View File

@ -26,10 +26,8 @@ public class JsonUtils {
/**
* 默认jackson配置
* 不打印类信息
* 时间序列化为字符串
*/
public static final ObjectMapper OM_DEFAULT = base();
public static ObjectMapper OM_DEFAULT = base();
private static final DefaultPrettyPrinter DEFAULT_PRETTY_PRINTER = new DefaultPrettyPrinter();
public static JsonMapper base() {

View File

@ -25,14 +25,20 @@ import java.util.Map;
*/
public class JacksonCache {
public static JsonInclude.Value NON_NULL = JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, null);
public static JsonInclude.Value NON_EMPTY = JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY, null);
public static void init(Map<Class<?>, EntityInfo> entityInfoMap) {
if (entityInfoMap.isEmpty()) {
return;
}
entityInfoMap.forEach((clz,e) -> {
// 当前类
if (!JacksonCustomConfig.jacksonConfigMap.containsKey(clz)) {
JacksonCustomConfig config = init(clz, e.getMappingColumnMap(), e.getClassDateFormatMap().get(clz), e.getFieldList());
config.includeMap.put(e.getKeyProperty(), NON_NULL);
config.includeMap.put(getterMethod(clz, e.getKeyProperty()), NON_NULL);
JacksonCustomConfig.jacksonConfigMap.put(clz, config);
}
@ -95,14 +101,12 @@ public class JacksonCache {
}
switch (f.getFieldStrategy()) {
case NOT_NULL:
JsonInclude.Value v = JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, null);
config.includeMap.put(getterName, v);
config.includeMap.put(f.getColumn(), v);
config.includeMap.put(getterName, NON_NULL);
config.includeMap.put(f.getColumn(), NON_NULL);
break;
case NOT_EMPTY:
JsonInclude.Value j = JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY, null);
config.includeMap.put(getterName, j);
config.includeMap.put(f.getColumn(), j);
config.includeMap.put(getterName, NON_EMPTY);
config.includeMap.put(f.getColumn(), NON_EMPTY);
break;
default:
break;

View File

@ -37,6 +37,7 @@ import org.dromara.easyes.annotation.rely.RefreshPolicy;
import org.dromara.easyes.common.constants.BaseEsConstants;
import org.dromara.easyes.common.enums.EsQueryTypeEnum;
import org.dromara.easyes.common.enums.OrderTypeEnum;
import org.dromara.easyes.common.join.BaseJoin;
import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.common.utils.*;
import org.dromara.easyes.core.biz.*;
@ -198,12 +199,54 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
return getSearchResponse(wrapper, null, false);
}
@Override
public SearchResponse<T> search(SearchRequest searchRequest, TransportOptions requestOptions) throws IOException {
printDSL(searchRequest);
SearchResponse<T> response = client.withTransportOptions(requestOptions).search(searchRequest, entityClass);
printResponseErrors(response);
return response;
/**
* 根据全局配置决定是否控制台打印DSL语句
*
* @param request es请求参数
* @param client es客户端
*/
public static void printDSL(RequestBase request, ElasticsearchClient client) {
if (request == null) {
return;
}
String method = "";
String requestUrl = "";
String fullUrl = "";
String dsl = "";
try {
@SuppressWarnings("unchecked")
Endpoint<RequestBase, ?, ?> endpoint = (Endpoint<RequestBase, ?, ?>) request.getClass()
.getDeclaredField("_ENDPOINT").get(null);
method = endpoint.method(request);
requestUrl = endpoint.requestUrl(request);
Map<String, String> params = endpoint.queryParameters(request);
StringBuilder fullUrlSb = new StringBuilder(requestUrl);
String delim = "?";
for (Map.Entry<String, String> param : params.entrySet()) {
fullUrlSb.append(delim);
delim = "&";
fullUrlSb.append(param.getKey()).append("=").append(URLEncoder.encode(param.getValue(), StandardCharsets.UTF_8));
}
fullUrl = fullUrlSb.toString();
if (request instanceof JsonpSerializable) {
dsl = JsonpUtils.toJsonString(request, client._transport().jsonpMapper());
}
} catch (Exception e) {
// No endpoint, ignore
}
GlobalConfig globalConfig = GlobalConfigCache.getGlobalConfig();
if (globalConfig.isPrintDsl()) {
String prefix = globalConfig.isIKunMode() ? I_KUN_PREFIX : DSL_PREFIX;
LogUtils.info(prefix +
"\n" + method + " " + fullUrl +
"\n" + dsl
);
}
}
@Override
@ -285,32 +328,11 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
@Override
public Long selectCount(Wrapper<T> wrapper, boolean distinct) {
if (distinct) {
// 去重, 总数来源于桶, 只查id列,节省内存 拷贝是防止追加的只查id列影响到count后的其它查询
Wrapper<T> clone = wrapper.clone();
clone.include = new String[]{DEFAULT_ES_ID_NAME};
SearchResponse<T> response = getSearchResponse(clone);
return parseCount(response, Objects.nonNull(clone.distinctField));
} else {
// 不去重,直接count获取,效率更高
BoolQuery query = getBoolQuery(wrapper);
CountRequest req = CountRequest.of(a -> a
.index(WrapperProcessor.getIndexName(entityClass, wrapper.indexNames))
.routing(wrapper.routing)
.preference(wrapper.preference)
.query(query._toQuery())
);
CountResponse rsp;
try {
printDSL(req);
rsp = client.withTransportOptions(getTransportOptions()).count(req);
} catch (IOException e) {
throw ExceptionUtils.eee("selectCount exception", e);
}
return rsp.count();
}
public SearchResponse<T> search(SearchRequest searchRequest, TransportOptions requestOptions) throws IOException {
printDSL(searchRequest, client);
SearchResponse<T> response = client.withTransportOptions(requestOptions).search(searchRequest, entityClass);
printResponseErrors(response);
return response;
}
/**
@ -445,24 +467,31 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
@Override
public Integer delete(Wrapper<T> wrapper) {
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
public Long selectCount(Wrapper<T> wrapper, boolean distinct) {
if (distinct) {
// 去重, 总数来源于桶, 只查id列,节省内存 拷贝是防止追加的只查id列影响到count后的其它查询
Wrapper<T> clone = wrapper.clone();
clone.include = new String[]{EntityInfoHelper.getEntityInfo(entityClass).getKeyProperty()};
SearchResponse<T> response = getSearchResponse(clone);
return parseCount(response, Objects.nonNull(clone.distinctField));
} else {
// 不去重,直接count获取,效率更高
BoolQuery query = getBoolQuery(wrapper);
DeleteByQueryRequest request = DeleteByQueryRequest.of(a -> a
CountRequest req = CountRequest.of(a -> a
.index(WrapperProcessor.getIndexName(entityClass, wrapper.indexNames))
.query(getBoolQuery(wrapper)._toQuery())
.routing(wrapper.routing)
.refresh(Refresh.True.equals(getRefreshPolicy()))
.scrollSize(entityInfo == null ? null : entityInfo.getMaxResultWindow())
.preference(wrapper.preference)
.query(query._toQuery())
);
printDSL(request);
CountResponse rsp;
try {
DeleteByQueryResponse bulkResponse = client.deleteByQuery(request);
// 单次删除通常不会超过21亿, 这里为了兼容老API设计,仍转为int 2.0版本将调整为long
return bulkResponse.deleted() == null ? BaseEsConstants.ZERO : bulkResponse.deleted().intValue();
printDSL(req, client);
rsp = client.withTransportOptions(getTransportOptions()).count(req);
} catch (IOException e) {
throw ExceptionUtils.eee("delete error, dsl:%s", e);
throw ExceptionUtils.eee("selectCount exception", e);
}
return rsp.count();
}
}
@ -715,35 +744,25 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
}
/**
* 执行插入单条数据
*
* @param entity 插入对象
* @param routing 路由
* @param parentId 父id
* @param indexName 索引名
* @return 成功条数
*/
private Integer doInsert(T entity, String routing, String parentId, String indexName) {
// 构建请求入参
IndexRequest.Builder<T> indexRequest = buildIndexRequest(entity, routing, parentId, indexName);
@Override
public Integer delete(Wrapper<T> wrapper) {
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
Optional.ofNullable(routing).ifPresent(indexRequest::routing);
indexRequest.refresh(getRefreshPolicy());
DeleteByQueryRequest request = DeleteByQueryRequest.of(a -> a
.index(WrapperProcessor.getIndexName(entityClass, wrapper.indexNames))
.query(getBoolQuery(wrapper)._toQuery())
.routing(wrapper.routing)
.refresh(Refresh.True.equals(getRefreshPolicy()))
.scrollSize(entityInfo == null ? null : entityInfo.getMaxResultWindow())
);
printDSL(request, client);
try {
IndexResponse indexResponse = client.withTransportOptions(getTransportOptions()).index(indexRequest.build());
if (Objects.equals(indexResponse.result(), Result.Created)) {
setId(entity, indexResponse.id());
return BaseEsConstants.ONE;
} else if (Objects.equals(indexResponse.result(), Result.Updated)) {
// 该id已存在,数据被更新的情况
return BaseEsConstants.ZERO;
} else {
throw ExceptionUtils.eee("insert failed, result:%s entity:%s", indexResponse.result(), entity);
}
DeleteByQueryResponse bulkResponse = client.deleteByQuery(request);
// 单次删除通常不会超过21亿, 这里为了兼容老API设计,仍转为int 2.0版本将调整为long
return bulkResponse.deleted() == null ? BaseEsConstants.ZERO : bulkResponse.deleted().intValue();
} catch (IOException e) {
throw ExceptionUtils.eee("insert entity:%s exception", e, entity.toString());
throw ExceptionUtils.eee("delete error, dsl:%s", e);
}
}
@ -788,6 +807,36 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
return doBulkRequest(bulkRequest, getTransportOptions(), entityList);
}
/**
* 执行插入单条数据
*
* @param entity 插入对象
* @param routing 路由
* @param parentId 父id
* @param indexName 索引名
* @return 成功条数
*/
private Integer doInsert(T entity, String routing, String parentId, String indexName) {
// 构建请求入参
IndexRequest<T> indexRequest = buildIndexRequest(entity, routing, parentId, indexName)
.refresh(getRefreshPolicy()).build();
printDSL(indexRequest, client);
try {
IndexResponse indexResponse = client.withTransportOptions(getTransportOptions()).index(indexRequest);
if (Objects.equals(indexResponse.result(), Result.Created)) {
setId(entity, indexResponse.id());
return BaseEsConstants.ONE;
} else if (Objects.equals(indexResponse.result(), Result.Updated)) {
// 该id已存在,数据被更新的情况
return BaseEsConstants.ZERO;
} else {
throw ExceptionUtils.eee("insert failed, result:%s entity:%s", indexResponse.result(), entity);
}
} catch (IOException e) {
throw ExceptionUtils.eee("insert entity:%s exception", e, entity.toString());
}
}
/**
* 执行根据id删除指定数据
@ -803,7 +852,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
.refresh(getRefreshPolicy())
.build();
printDSL(request);
printDSL(request, client);
try {
DeleteResponse deleteResponse = client.withTransportOptions(getTransportOptions()).delete(request);
if (Objects.equals(deleteResponse.result(), Result.Deleted)) {
@ -815,7 +864,6 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
return BaseEsConstants.ZERO;
}
/**
* 执行根据id批量删除
*
@ -847,7 +895,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
.operations(operations)
);
printDSL(request);
printDSL(request, client);
return doBulkRequest(request, getTransportOptions());
}
@ -867,7 +915,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
.refresh(getRefreshPolicy())
.build();
printDSL(updateRequest);
printDSL(updateRequest, client);
// 执行更新
try {
@ -882,43 +930,6 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
return BaseEsConstants.ZERO;
}
/**
* 执行根据id批量更新
*
* @param entityList 更新数据列表
* @param routing 路由
* @param indexName 索引名
* @return 总成功条数
*/
private Integer doUpdateBatchByIds(Collection<T> entityList, String routing, String indexName) {
// 封装批量请求参数
List<BulkOperation> operations = new ArrayList<>();
entityList.forEach(e -> {
String idValue = getIdValue(e);
UpdateRequest<T, T> updateRequest = buildUpdateRequest(e, idValue, indexName).build();
BulkOperation operation = BulkOperation.of(a ->
a.update(b -> b
.id(updateRequest.id())
.ifPrimaryTerm(updateRequest.ifPrimaryTerm())
.ifSeqNo(updateRequest.ifSeqNo())
.index(updateRequest.index())
.requireAlias(updateRequest.requireAlias())
.retryOnConflict(updateRequest.retryOnConflict())
.routing(updateRequest.routing())
));
operations.add(operation);
});
BulkRequest request = BulkRequest.of(a -> a
.routing(routing)
.refresh(getRefreshPolicy())
.operations(operations)
);
printDSL(request);
return doBulkRequest(request, getTransportOptions());
}
/**
* 执行根据条件更新
*
@ -957,6 +968,42 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
return doBulkRequest(bulkRequest, getTransportOptions());
}
/**
* 执行根据id批量更新
*
* @param entityList 更新数据列表
* @param routing 路由
* @param indexName 索引名
* @return 总成功条数
*/
private Integer doUpdateBatchByIds(Collection<T> entityList, String routing, String indexName) {
// 封装批量请求参数
List<BulkOperation> operations = new ArrayList<>();
entityList.forEach(e -> {
String idValue = getIdValue(e);
UpdateRequest<T, T> updateRequest = buildUpdateRequest(e, idValue, indexName).build();
BulkOperation operation = BulkOperation.of(a ->
a.update(b -> b
.id(updateRequest.id())
.ifPrimaryTerm(updateRequest.ifPrimaryTerm())
.ifSeqNo(updateRequest.ifSeqNo())
.index(updateRequest.index())
.requireAlias(updateRequest.requireAlias())
.retryOnConflict(updateRequest.retryOnConflict())
.routing(updateRequest.routing())
));
operations.add(operation);
});
BulkRequest request = BulkRequest.of(a -> a
.routing(routing)
.refresh(getRefreshPolicy())
.operations(operations)
);
printDSL(request, client);
return doBulkRequest(request, getTransportOptions());
}
/**
* 执行根据id批量查询
@ -974,8 +1021,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
.routing(routing)
.query(QueryBuilders.ids().values(ids).build()._toQuery())
.size(idList.size())
.build()
;
.build();
// 请求es获取数据
List<Hit<T>> searchHits = getSearchHits(searchRequest);
@ -1003,8 +1049,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
.index(indexName)
.routing(routing)
.query(QueryBuilders.ids().values(List.of(id.toString())).build()._toQuery())
.build()
;
.build();
// 请求es获取数据
List<Hit<T>> searchHits = getSearchHits(searchRequest);
if (CollectionUtils.isEmpty(searchHits)) {
@ -1016,6 +1061,22 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
/**
* 生成DelRequest请求参数
*
* @param id id
* @param indexName 索引名
* @return DelRequest
*/
private DeleteRequest.Builder generateDelRequest(Serializable id, String indexName) {
if (Objects.isNull(id) || StringUtils.isEmpty(id.toString())) {
throw ExceptionUtils.eee("id must not be null or empty");
}
return new DeleteRequest.Builder()
.id(id.toString())
.index(indexName);
}
/**
* 获取es查询结果返回体
*
@ -1039,7 +1100,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
if (needSearchAfter && searchRequest.sort().isEmpty()) {
throw ExceptionUtils.eee("searchAfter必须要进行排序");
}
printDSL(searchRequest);
printDSL(searchRequest, client);
try {
// 执行查询
@ -1051,23 +1112,6 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
}
/**
* 生成DelRequest请求参数
*
* @param id id
* @param indexName 索引名
* @return DelRequest
*/
private DeleteRequest.Builder generateDelRequest(Serializable id, String indexName) {
if (Objects.isNull(id) || StringUtils.isEmpty(id.toString())) {
throw ExceptionUtils.eee("id must not be null or empty");
}
return new DeleteRequest.Builder()
.id(id.toString())
.index(indexName);
}
/**
* 查询数据列表
*
@ -1086,11 +1130,15 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
builder.query(wrapper.searchBuilder.build().query());
} else {
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
int size = entityInfo == null ? GlobalConfigCache.getGlobalConfig().getDbConfig().getBatchUpdateThreshold()
: entityInfo.getMaxResultWindow().intValue();
if (entityInfo == null) {
throw ExceptionUtils.eee("entityClass must not be null or empty");
}
Integer batchUpdateThreshold = GlobalConfigCache.getGlobalConfig().getDbConfig().getBatchUpdateThreshold();
int maxResultWindow = entityInfo.getMaxResultWindow().intValue();
int size = batchUpdateThreshold > maxResultWindow ? maxResultWindow : batchUpdateThreshold;
builder
// 只查id列,节省内存
.source(a -> a.filter(b -> b.includes(DEFAULT_ES_ID_NAME)))
.source(a -> a.filter(b -> b.includes(entityInfo.getKeyProperty())))
.trackTotalHits(a -> a.enabled(true))
.query(WrapperProcessor.initBoolQueryBuilder(wrapper.paramQueue, entityClass).build()._toQuery())
.size(size)
@ -1098,7 +1146,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
SearchRequest searchRequest = builder.build();
printDSL(searchRequest);
printDSL(searchRequest, client);
try {
// 查询数据明细
SearchResponse<T> response = client.withTransportOptions(getTransportOptions()).search(searchRequest, entityClass);
@ -1112,32 +1160,6 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
}
/**
* 构建创建数据请求参数
*
* @param entity 实体
* @param routing 路由
* @param parentId 父id
* @param indexName 索引名
* @return es请求参数
*/
private IndexRequest.Builder<T> buildIndexRequest(T entity, String routing, String parentId, String indexName) {
IndexRequest.Builder<T> indexRequest = new IndexRequest.Builder<T>()
.index(indexName)
.document(entity);
// id预处理,除下述情况,其它情况使用es默认的id
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
if (IdType.UUID.equals(entityInfo.getIdType())) {
indexRequest.id(UUID.randomUUID().toString());
} else if (IdType.CUSTOMIZE.equals(entityInfo.getIdType())) {
indexRequest.id(getIdValue(entity));
}
return indexRequest;
}
/**
* 构建更新数据请求参数
*
@ -1417,6 +1439,41 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
return search(wrapper);
}
/**
* 构建创建数据请求参数
*
* @param entity 实体
* @param routing 路由
* @param parentId 父id
* @param indexName 索引名
* @return es请求参数
*/
private IndexRequest.Builder<T> buildIndexRequest(T entity, String routing, String parentId, String indexName) {
IndexRequest.Builder<T> indexRequest = new IndexRequest.Builder<T>()
.routing(routing)
.index(indexName)
.document(entity);
// id预处理,除下述情况,其它情况使用es默认的id
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
if (IdType.UUID.equals(entityInfo.getIdType())) {
indexRequest.id(UUID.randomUUID().toString());
} else if (IdType.CUSTOMIZE.equals(entityInfo.getIdType())) {
indexRequest.id(getIdValue(entity));
}
// 针对父子类型-追加joinField信息
if (StringUtils.isNotBlank(entityInfo.getJoinAlias())) {
if (!(entity instanceof BaseJoin b)) {
throw ExceptionUtils.eee("实体类" + entityClass.getName() + "必须继承BaseJoin实现Join功能");
}
b.addJoinField(entityInfo.getJoinFieldName(), entityInfo.getJoinAlias(), entityInfo.isChild() ? parentId : null);
}
return indexRequest;
}
/**
* 从es中请求获取searchHit数组
*
@ -1424,7 +1481,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
* @return searchHit数组
*/
private List<Hit<T>> getSearchHits(SearchRequest searchRequest) {
printDSL(searchRequest);
printDSL(searchRequest, client);
SearchResponse<T> response;
try {
response = client.withTransportOptions(getTransportOptions()).search(searchRequest, entityClass);
@ -1435,29 +1492,6 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
return parseSearchHitArray(response);
}
/**
* 从es中请求获取searchHit数组
*
* @param wrapper 参数包装类
* @return searchHit数组
*/
private List<Hit<T>> getSearchHits(Wrapper<T> wrapper) {
// 用户在wrapper中指定的混合查询条件优先级最高
SearchRequest searchRequest = Optional.ofNullable(wrapper.searchBuilder)
.orElse(WrapperProcessor.buildSearchSourceBuilder(wrapper, entityClass)).build();
printDSL(searchRequest);
SearchResponse<T> response;
try {
response = client.withTransportOptions(getTransportOptions()).search(searchRequest, entityClass);
} catch (IOException e) {
throw ExceptionUtils.eee("getSearchHitArray IOException, searchRequest:%s", e, searchRequest.toString());
}
printResponseErrors(response);
return parseSearchHitArray(response);
}
/**
* 构建更新文档的json
*
@ -1501,31 +1535,25 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
/**
* 执行bulk创建请求,并返回成功个数,封装id
* 从es中请求获取searchHit数组
*
* @param bulkRequest 批量请求参数
* @param requestOptions 类型
* @param entityList 实体列表
* @return 成功个数
* @param wrapper 参数包装类
* @return searchHit数组
*/
private int doBulkRequest(BulkRequest bulkRequest, TransportOptions requestOptions, Collection<T> entityList) {
int totalSuccess = 0;
try {
BulkResponse bulkResponse = client.withTransportOptions(requestOptions).bulk(bulkRequest);
if (bulkResponse.errors()) {
LogUtils.error(bulkResponse.toString());
}
private List<Hit<T>> getSearchHits(Wrapper<T> wrapper) {
// 用户在wrapper中指定的混合查询条件优先级最高
SearchRequest searchRequest = Optional.ofNullable(wrapper.searchBuilder)
.orElse(WrapperProcessor.buildSearchSourceBuilder(wrapper, entityClass)).build();
for (BulkResponseItem item : bulkResponse.items()) {
if (Objects.equals(item.status(), 200)) {
setId(entityList.toArray()[totalSuccess], item.id());
totalSuccess++;
}
}
printDSL(searchRequest, client);
SearchResponse<T> response;
try {
response = client.withTransportOptions(getTransportOptions()).search(searchRequest, entityClass);
} catch (IOException e) {
throw ExceptionUtils.eee("bulkRequest exception", e);
throw ExceptionUtils.eee("getSearchHitArray IOException, searchRequest:%s", e, searchRequest.toString());
}
return totalSuccess;
printResponseErrors(response);
return parseSearchHitArray(response);
}
/**
@ -1627,55 +1655,34 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
}
/**
* 根据全局配置决定是否控制台打印DSL语句
* 执行bulk创建请求,并返回成功个数,封装id
*
* @param request es请求参数
* @param bulkRequest 批量请求参数
* @param requestOptions 类型
* @param entityList 实体列表
* @return 成功个数
*/
private void printDSL(RequestBase request) {
if (request == null) {
return;
}
private int doBulkRequest(BulkRequest bulkRequest, TransportOptions requestOptions, Collection<T> entityList) {
printDSL(bulkRequest, client);
String method = "";
String requestUrl = "";
String fullUrl = "";
String dsl = "";
int totalSuccess = 0;
try {
@SuppressWarnings("unchecked")
Endpoint<RequestBase, ?, ?> endpoint = (Endpoint<RequestBase, ?, ?>) this.getClass()
.getDeclaredField("_ENDPOINT").get(null);
method = endpoint.method(request);
requestUrl = endpoint.requestUrl(request);
Map<String, String> params = endpoint.queryParameters(request);
StringBuilder fullUrlSb = new StringBuilder(requestUrl);
String delim = "?";
for (Map.Entry<String, String> param : params.entrySet()) {
fullUrlSb.append(delim);
delim = "&";
fullUrlSb.append(param.getKey()).append("=").append(URLEncoder.encode(param.getValue(), StandardCharsets.UTF_8));
}
fullUrl = fullUrlSb.toString();
if (this instanceof JsonpSerializable) {
dsl = JsonpUtils.toString((JsonpSerializable) this, new StringBuilder()).toString();
}
} catch (Exception e) {
// No endpoint, ignore
BulkResponse bulkResponse = client.withTransportOptions(requestOptions).bulk(bulkRequest);
if (bulkResponse.errors()) {
LogUtils.error(bulkResponse.toString());
}
GlobalConfig globalConfig = GlobalConfigCache.getGlobalConfig();
if (globalConfig.isPrintDsl()) {
String prefix = globalConfig.isIKunMode() ? I_KUN_PREFIX : DSL_PREFIX;
LogUtils.info(prefix +
"\nmethod: " + method +
"\nrequestUrl: " + requestUrl +
"\nfullUrl: " + fullUrl +
"\nDSL" + dsl
);
for (BulkResponseItem item : bulkResponse.items()) {
if (Objects.equals(item.status(), 201)) {
// setId(entityList.toArray()[totalSuccess], item.id());
totalSuccess++;
}
}
} catch (IOException e) {
throw ExceptionUtils.eee("bulkRequest exception", e);
}
return totalSuccess;
}
/**
* 对响应结构进行判断如果有错误则抛出异常

View File

@ -661,9 +661,11 @@ public class EntityInfoHelper {
.setIdClass(field.getType())
.setKeyProperty(field.getName());
entityInfo.getNotSerializeField().add(DEFAULT_ID_NAME);
entityInfo.getNotSerializeField().add(field.getName());
entityInfo.getMappingColumnMap().putIfAbsent(field.getName(), DEFAULT_ID_NAME);
String mappingColumn = !StringUtils.isBlank(tableId.value().trim()) ? tableId.value():
getMappingColumn(dbConfig, field);
entityInfo.getMappingColumnMap().putIfAbsent(field.getName(), mappingColumn);
entityInfo.getColumnMappingMap().putIfAbsent(mappingColumn, field.getName());
return true;
}
return false;
@ -688,9 +690,10 @@ public class EntityInfoHelper {
.setKeyField(field)
.setIdClass(field.getType())
.setClazz(field.getDeclaringClass());
entityInfo.getNotSerializeField().add(DEFAULT_ID_NAME);
entityInfo.getNotSerializeField().add(field.getName());
entityInfo.getMappingColumnMap().putIfAbsent(field.getName(), DEFAULT_ID_NAME);
entityInfo.getNotSerializeField().add(column);
String mappingColumn = getMappingColumn(dbConfig, field);
entityInfo.getMappingColumnMap().putIfAbsent(column, mappingColumn);
entityInfo.getColumnMappingMap().putIfAbsent(mappingColumn, column);
return true;
}
return false;
@ -781,10 +784,10 @@ public class EntityInfoHelper {
if (settings == null) {
return;
}
IndexSettings.Builder builder = entityInfo.getIndexSettings();
builder.numberOfReplicas(settings.replicasNum() + "");
builder.numberOfShards(settings.shardsNum() + "");
builder.maxResultWindow((int)settings.maxResultWindow());
IndexSettings.Builder builder = entityInfo.getIndexSettings()
.numberOfReplicas(settings.replicasNum() + "")
.numberOfShards(settings.shardsNum() + "")
.maxResultWindow((int) settings.maxResultWindow());
if (StringUtils.isNotBlank(settings.refreshInterval())) {
builder.refreshInterval(a -> a.time(settings.refreshInterval()));
}

View File

@ -19,7 +19,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
import static org.dromara.easyes.common.constants.BaseEsConstants.KEYWORD_SUFFIX;
/**
* 核心 处理字段名称工具类
@ -36,12 +36,7 @@ public class FieldUtils {
* @return 泛型
*/
public static <R> String getFieldName(R func) {
String fieldName = getFieldNameNotConvertId(func);
if (DEFAULT_ID_NAME.equals(fieldName)) {
// id统一转为_id
fieldName = DEFAULT_ES_ID_NAME;
}
return fieldName;
return getFieldNameNotConvertId(func);
}
/**
@ -172,7 +167,7 @@ public class FieldUtils {
public static String getRealField(String field, Map<String, String> mappingColumnMap) {
String customField = mappingColumnMap.get(field);
if (Objects.nonNull(customField)) {
return DEFAULT_ID_NAME.equals(customField) ? DEFAULT_ES_ID_NAME : customField;
return customField;
} else {
GlobalConfig.DbConfig dbConfig = GlobalConfigCache.getGlobalConfig().getDbConfig();
if (dbConfig.isMapUnderscoreToCamelCase()) {

View File

@ -22,6 +22,7 @@ import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.common.utils.*;
import org.dromara.easyes.core.biz.*;
import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.core.kernel.BaseEsMapperImpl;
import java.io.IOException;
import java.util.*;
@ -147,6 +148,7 @@ public class IndexUtils {
// 创建索引
try {
BaseEsMapperImpl.printDSL(createIndexRequest, client);
CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest);
return createIndexResponse.acknowledged();
} catch (IOException e) {
@ -165,6 +167,7 @@ public class IndexUtils {
CreateIndexRequest request = CreateIndexRequest.of(x -> x.index(indexName));
CreateIndexResponse createIndexResponse;
try {
BaseEsMapperImpl.printDSL(request, client);
createIndexResponse = client.indices().create(request);
} catch (IOException e) {
LogUtils.info("===> distribute lock index has created");
@ -195,6 +198,7 @@ public class IndexUtils {
public static GetIndexResponse getIndex(ElasticsearchClient client, String indexName) {
GetIndexRequest request = GetIndexRequest.of(x -> x.index(indexName));
try {
BaseEsMapperImpl.printDSL(request, client);
return client.indices().get(request);
} catch (IOException e) {
throw ExceptionUtils.eee("getIndex exception indexName: %s", e, indexName);
@ -221,9 +225,10 @@ public class IndexUtils {
*/
public static Boolean addAliases(ElasticsearchClient client, String indexName, String... aliases) {
Action action = Action.of(x -> x.add(y -> y.aliases(Arrays.asList(aliases)).index(indexName)));
UpdateAliasesRequest aliasesRequest = UpdateAliasesRequest.of(x -> x.actions(action));
UpdateAliasesRequest request = UpdateAliasesRequest.of(x -> x.actions(action));
try {
UpdateAliasesResponse response = client.indices().updateAliases(aliasesRequest);
BaseEsMapperImpl.printDSL(request, client);
UpdateAliasesResponse response = client.indices().updateAliases(request);
return response.acknowledged();
} catch (IOException e) {
LogUtils.warn("addDefaultAlias exception", e.toString());
@ -242,7 +247,7 @@ public class IndexUtils {
*/
public static boolean reindex(ElasticsearchClient client, String oldIndexName, String releaseIndexName, Long maxResultWindow) {
int reindexTimeOutHours = GlobalConfigCache.getGlobalConfig().getReindexTimeOutHours();
ReindexRequest reindexRequest = ReindexRequest.of(a -> {
ReindexRequest request = ReindexRequest.of(a -> {
a
.source(b -> b.index(oldIndexName))
.dest(c -> c.index(releaseIndexName).opType(BaseEsConstants.DEFAULT_DEST_OP_TYPE))
@ -256,7 +261,8 @@ public class IndexUtils {
return a;
});
try {
ReindexResponse response = client.reindex(reindexRequest);
BaseEsMapperImpl.printDSL(request, client);
ReindexResponse response = client.reindex(request);
List<BulkIndexByScrollFailure> failures = response.failures();
return CollectionUtils.isEmpty(failures);
} catch (IOException e) {
@ -315,8 +321,7 @@ public class IndexUtils {
.runtime(mappings.runtime())
.enabled(mappings.enabled())
.subobjects(mappings.subobjects())
.dataStreamTimestamp(mappings.dataStreamTimestamp())
;
.dataStreamTimestamp(mappings.dataStreamTimestamp());
esIndexInfo.setMapping(builder);
}
@ -438,6 +443,7 @@ public class IndexUtils {
ByteNumberProperty property = ByteNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -447,6 +453,7 @@ public class IndexUtils {
ShortNumberProperty property = ShortNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -456,6 +463,7 @@ public class IndexUtils {
IntegerNumberProperty property = IntegerNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -465,6 +473,7 @@ public class IndexUtils {
LongNumberProperty property = LongNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -474,6 +483,7 @@ public class IndexUtils {
FloatNumberProperty property = FloatNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -483,6 +493,7 @@ public class IndexUtils {
DoubleNumberProperty property = DoubleNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -492,6 +503,7 @@ public class IndexUtils {
HalfFloatNumberProperty property = HalfFloatNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -503,6 +515,7 @@ public class IndexUtils {
ScaledFloatNumberProperty property = ScaledFloatNumberProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
a.scalingFactor(scalingFactor);
return a;
});
@ -513,6 +526,7 @@ public class IndexUtils {
BooleanProperty property = BooleanProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -522,6 +536,7 @@ public class IndexUtils {
DateProperty property = DateProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
a.format(indexParam.getDateFormat());
return a;
});
@ -531,6 +546,7 @@ public class IndexUtils {
if (FieldType.BINARY.getType().equals(indexParam.getFieldType())) {
BinaryProperty property = BinaryProperty.of(a -> {
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -540,9 +556,8 @@ public class IndexUtils {
KeywordProperty property = KeywordProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
if (indexParam.isIgnoreCase()) {
a.normalizer(LOWERCASE_NORMALIZER);
}
buildInnerFields(a, indexParam);
a.normalizer(indexParam.isIgnoreCase() ? LOWERCASE_NORMALIZER : null);
return a;
});
properties.put(fieldName, property._toProperty());
@ -552,10 +567,11 @@ public class IndexUtils {
int ignoreAbove = Optional.ofNullable(indexParam.getIgnoreAbove()).orElse(DEFAULT_IGNORE_ABOVE);
TextProperty property = TextProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
Optional.ofNullable(indexParam.getAnalyzer()).map(String::toLowerCase).ifPresent(a::analyzer);
Optional.ofNullable(indexParam.getSearchAnalyzer()).map(String::toLowerCase).ifPresent(a::searchAnalyzer);
MyOptional.ofNullable(indexParam.getFieldData()).ifTrue(a::fielddata);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
return a;
});
properties.put(fieldName, property._toProperty());
@ -566,6 +582,7 @@ public class IndexUtils {
TextProperty property = TextProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
a.fields(FieldType.KEYWORD.getType(), c -> c
.keyword(d -> {
d.ignoreAbove(ignoreAbove);
@ -587,6 +604,7 @@ public class IndexUtils {
int ignoreAbove = Optional.ofNullable(indexParam.getIgnoreAbove()).orElse(DEFAULT_IGNORE_ABOVE);
WildcardProperty property = WildcardProperty.of(a -> {
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -599,6 +617,7 @@ public class IndexUtils {
Map<String, Property> nested = initInfo(entityInfo, dbConfig, new HashMap<>(), esIndexParams);
NestedProperty property = NestedProperty.of(a -> {
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
a.properties(nested);
return a;
});
@ -612,6 +631,7 @@ public class IndexUtils {
Map<String, Property> nested = initInfo(entityInfo, dbConfig, new HashMap<>(), esIndexParams);
ObjectProperty property = ObjectProperty.of(a -> {
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
a.properties(nested);
return a;
});
@ -624,6 +644,7 @@ public class IndexUtils {
if (FieldType.GEO_POINT.getType().equals(indexParam.getFieldType())) {
GeoPointProperty property = GeoPointProperty.of(a -> {
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -632,6 +653,7 @@ public class IndexUtils {
if (FieldType.GEO_SHAPE.getType().equals(indexParam.getFieldType())) {
GeoShapeProperty property = GeoShapeProperty.of(a -> {
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -641,6 +663,7 @@ public class IndexUtils {
IpProperty property = IpProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -649,6 +672,7 @@ public class IndexUtils {
if (FieldType.COMPLETION.getType().equals(indexParam.getFieldType())) {
CompletionProperty property = CompletionProperty.of(a -> {
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
Optional.ofNullable(indexParam.getAnalyzer()).map(String::toLowerCase).ifPresent(a::analyzer);
Optional.ofNullable(indexParam.getSearchAnalyzer()).map(String::toLowerCase).ifPresent(a::searchAnalyzer);
return a;
@ -660,6 +684,7 @@ public class IndexUtils {
TokenCountProperty property = TokenCountProperty.of(a -> {
Optional.ofNullable(indexParam.getBoost()).ifPresent(a::boost);
buildCopyTo(a, entityInfo.isIndexEqualStage(), indexParam.getCopyToList());
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
@ -669,7 +694,10 @@ public class IndexUtils {
return;
}
if (FieldType.PERCOLATOR.getType().equals(indexParam.getFieldType())) {
PercolatorProperty property = PercolatorProperty.of(a -> a);
PercolatorProperty property = PercolatorProperty.of(a -> {
buildInnerFields(a, indexParam);
return a;
});
properties.put(fieldName, property._toProperty());
return;
}
@ -971,8 +999,7 @@ public class IndexUtils {
* @return 索引参数列表
*/
public static List<EsIndexParam> initIndexParam(EntityInfo entityInfo, Class<?> clazz, List<EntityFieldInfo> fieldList) {
List<EntityFieldInfo> copyFieldList = new ArrayList<>();
copyFieldList.addAll(fieldList);
List<EntityFieldInfo> copyFieldList = new ArrayList<>(fieldList);
List<EsIndexParam> esIndexParamList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(copyFieldList)) {
@ -983,7 +1010,7 @@ public class IndexUtils {
String esFieldType = IndexUtils.getEsFieldType(field.getFieldType(), field.getColumnType());
esIndexParam.setFieldType(esFieldType);
if (field.isFieldData()) {
esIndexParam.setFieldData(field.isFieldData());
esIndexParam.setFieldData(true);
}
esIndexParam.setFieldName(field.getMappingColumn());
esIndexParam.setScalingFactor(field.getScalingFactor());

View File

@ -5,6 +5,7 @@ import lombok.Data;
import lombok.experimental.Accessors;
import org.dromara.easyes.annotation.*;
import org.dromara.easyes.annotation.rely.*;
import org.dromara.easyes.common.join.BaseJoin;
import org.dromara.easyes.test.settings.MySettingsProvider;
import java.math.BigDecimal;
@ -25,9 +26,9 @@ import java.util.List;
@Data
@Accessors(chain = true)
@Settings(shardsNum = 3, replicasNum = 2, settingsProvider = MySettingsProvider.class)
@IndexName(value = "easyes_solon_document", keepGlobalPrefix = true, refreshPolicy = RefreshPolicy.IMMEDIATE)
@IndexName(value = "easyes_solon_document_8", keepGlobalPrefix = true, refreshPolicy = RefreshPolicy.IMMEDIATE)
@Join(nodes = {@Node(parentClass = Document.class, childClasses = {Author.class, Comment.class}), @Node(parentClass = Author.class, childClasses = Contact.class)})
public class Document {
public class Document extends BaseJoin {
/**
* es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等.
* 如果你想自定义es中的id为你提供的id,比如MySQL中的id,请将注解中的type指定为customize或直接在全局配置文件中指定,如此id便支持任意数据类型)

View File

@ -1,22 +1,18 @@
package org.dromara.easyes.test.settings;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import org.dromara.easyes.annotation.rely.DefaultSettingsProvider;
import java.util.HashMap;
import java.util.Map;
/**
* 由于es索引的settings灵活多变,框架只能针对一部分场景作简化,其余场景需要用户自定义实现
* <p>
* Copyright © 2024 xpc1024 All Rights Reserved
**/
public class MySettingsProvider extends DefaultSettingsProvider {
@Override
public Map<String, Object> getSettings() {
// TODO 这里可以自定义你的settings实现,将自定义的settings置入map并返回即可
Map<String, Object> mySettings = new HashMap<>();
// 例如指定查询操作的慢日志阈值为30秒,当查询操作的执行时间超过此阈值时Elasticsearch会记录相应的慢日志并发出警告
mySettings.put("index.search.slowlog.threshold.query.warn", "30s");
return mySettings;
public void settings(IndexSettings.Builder builder) {
builder.index(a -> a.search(b -> b
.slowlog(c -> c.threshold(d -> d.query(e -> e.warn(f -> f.time("30s")))))));
}
}

View File

@ -1,45 +1,34 @@
package org.dromara.easyes.test.all;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.GeoLocation;
import co.elastic.clients.elasticsearch._types.*;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.LongTermsBucket;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.transport.rest_client.RestClientOptions;
import org.dromara.easyes.common.constants.BaseEsConstants;
import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.biz.EsPageInfo;
import org.dromara.easyes.core.biz.OrderByParam;
import org.dromara.easyes.core.biz.SAPageInfo;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.dromara.easyes.core.conditions.update.LambdaEsUpdateWrapper;
import org.dromara.easyes.core.kernel.EsWrappers;
import org.dromara.easyes.core.kernel.WrapperProcessor;
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.Document;
import org.dromara.easyes.test.mapper.DocumentMapper;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.HttpAsyncResponseConsumerFactory;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.geo.GeoShapeRelation;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.geometry.Circle;
import org.elasticsearch.geometry.Point;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.ParsedMax;
import org.elasticsearch.search.aggregations.metrics.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.*;
import org.noear.solon.annotation.Inject;
import org.noear.solon.test.SolonTest;
@ -96,6 +85,7 @@ public class AllTest {
document.setEnglish("Calcium Gluconate");
document.setBigNum(new BigDecimal("66.66"));
document.setVector(new double[]{0.39684247970581666, 0.768707156181666, 0.5145490765571666});
// System.out.println(JsonUtils.toJsonPrettyStr(document));
int successCount = documentMapper.insert(document);
Assertions.assertEquals(successCount, 1);
}
@ -116,7 +106,6 @@ public class AllTest {
document.setGeoLocation(point.toString());
document.setStarNum(i);
document.setVector(new double[]{35.89684247970581666, 86.268707156181666, 133.1145490765571666});
// 针对个别数据 造一些差异项 方便测试不同场景
if (i == 2) {
document.setLocation("40.17836693398477,116.64002551005981");
@ -168,8 +157,12 @@ public class AllTest {
@Order(4)
public void testUpdateBySetSearchSourceBuilder() {
LambdaEsUpdateWrapper<Document> wrapper = new LambdaEsUpdateWrapper<>();
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.termQuery(FieldUtils.val(Document::getTitle) + KEYWORD_SUFFIX, "测试文档2"));
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(QueryBuilders.term()
.field(FieldUtils.val(Document::getTitle) + KEYWORD_SUFFIX)
.value("测试文档2")
.build()._toQuery()
);
wrapper.setSearchSourceBuilder(searchSourceBuilder);
Document document = new Document();
@ -433,11 +426,10 @@ public class AllTest {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.match(Document::getContent, "测试")
.groupBy(Document::getStarNum);
SearchResponse response = documentMapper.search(wrapper);
ParsedLongTerms parsedLongTerms = response.getAggregations()
.get("starNumTerms");
Terms.Bucket bucket = parsedLongTerms.getBuckets().get(0);
Assertions.assertTrue(bucket.getKey().equals(1L) && bucket.getDocCount() == 2L);
SearchResponse<Document> response = documentMapper.search(wrapper);
Aggregate aggregate = response.aggregations().get("starNumTerms");
LongTermsBucket bucket = aggregate.lterms().buckets().array().get(0);
Assertions.assertTrue(bucket.key() == 1L && bucket.docCount() == 2L);
}
@Test
@ -446,10 +438,9 @@ public class AllTest {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.match(Document::getContent, "测试")
.max(Document::getStarNum);
SearchResponse response = documentMapper.search(wrapper);
ParsedMax parsedMax = response.getAggregations()
.get("starNumMax");
Assertions.assertTrue(parsedMax.getValue() > 21);
SearchResponse<Document> response = documentMapper.search(wrapper);
Aggregate agg = response.aggregations().get("starNumMax");
Assertions.assertTrue(agg.valueCount().value() > 21);
}
@Test
@ -458,10 +449,9 @@ public class AllTest {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.match(Document::getContent, "测试")
.min(Document::getStarNum);
SearchResponse response = documentMapper.search(wrapper);
ParsedMin parsedMin = response.getAggregations()
.get("starNumMin");
Assertions.assertTrue(parsedMin.getValue() > 0 && parsedMin.getValue() < 2);
SearchResponse<Document> response = documentMapper.search(wrapper);
double parsedMin = response.aggregations().get("starNumMin").valueCount().value();
Assertions.assertTrue(parsedMin > 0 && parsedMin < 2);
}
@Test
@ -470,10 +460,9 @@ public class AllTest {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.match(Document::getContent, "测试")
.sum(Document::getStarNum);
SearchResponse response = documentMapper.search(wrapper);
ParsedSum parsedSum = response.getAggregations()
.get("starNumSum");
Assertions.assertTrue(parsedSum.getValue() >= 252);
SearchResponse<Document> response = documentMapper.search(wrapper);
double parsedSum = response.aggregations().get("starNumSum").valueCount().value();
Assertions.assertTrue(parsedSum >= 252);
}
@ -483,10 +472,9 @@ public class AllTest {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.match(Document::getContent, "测试")
.avg(Document::getStarNum);
SearchResponse response = documentMapper.search(wrapper);
ParsedAvg parsedAvg = response.getAggregations()
.get("starNumAvg");
Assertions.assertTrue(parsedAvg.getValue() > 11 && parsedAvg.getValue() < 12);
SearchResponse<Document> response = documentMapper.search(wrapper);
double parsedAvg = response.aggregations().get("starNumAvg").valueCount().value();
Assertions.assertTrue(parsedAvg > 11 && parsedAvg < 12);
}
@ -534,12 +522,15 @@ public class AllTest {
@Test
@Order(6)
public void testSetSearchSourceBuilder() {
EntityInfo e = EntityInfoHelper.getEntityInfo(Document.class);
// 测试混合查询的另一种方式
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery(FieldUtils.val(Document::getCreator), "老汉"));
Optional.ofNullable(EntityInfoHelper.getEntityInfo(Document.class))
.flatMap(i -> Optional.ofNullable(i.getMaxResultWindow()))
.ifPresent(searchSourceBuilder::size);
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder()
.query(QueryBuilders.match()
.field(FieldUtils.val(Document::getCreator))
.query("老汉")
.build()._toQuery()
)
.size(e.getMaxResultWindow().intValue());
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.setSearchSourceBuilder(searchSourceBuilder);
List<Document> documents = documentMapper.selectList(wrapper);
@ -703,7 +694,7 @@ public class AllTest {
@Order(6)
public void testOrderByDistanceAsc() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
GeoLocation centerPoint = new GeoLocation(41.0, 116.0);
GeoLocation centerPoint = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(41.0).lon(116.0)));
wrapper.match(Document::getCreator, "老汉")
.geoDistance(Document::getLocation, 168.8, centerPoint)
.orderByDistanceAsc(Document::getLocation, centerPoint);
@ -716,7 +707,7 @@ public class AllTest {
@Order(6)
public void testOrderByDistanceDesc() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
GeoLocation centerPoint = new GeoLocation(41.0, 116.0);
GeoLocation centerPoint = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(41.0).lon(116.0)));
wrapper.match(Document::getCreator, "老汉")
.geoDistance(Document::getLocation, 168.8, centerPoint)
.orderByDistanceDesc(Document::getLocation, centerPoint);
@ -729,8 +720,8 @@ public class AllTest {
@Order(6)
public void testOrderByDistanceMulti() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
GeoLocation centerPoint = new GeoLocation(41.0, 116.0);
GeoLocation centerPoint1 = new GeoLocation(42.0, 118.0);
GeoLocation centerPoint = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(41.0).lon(116.0)));
GeoLocation centerPoint1 = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(42.0).lon(118.0)));
wrapper.match(Document::getCreator, "老汉")
.geoDistance(Document::getLocation, 168.8, centerPoint)
.orderByDistanceDesc(Document::getLocation, centerPoint)
@ -753,14 +744,17 @@ public class AllTest {
@Test
@Order(6)
public void testSort() {
String realField = FieldUtils.getRealField(
FieldUtils.val(Document::getStarNum),
EntityInfoHelper.getEntityInfo(Document.class).getMappingColumnMap()
);
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.match(Document::getCreator, "老汉");
FieldSortBuilder fieldSortBuilder = SortBuilders.
fieldSort(FieldUtils.getRealField(
FieldUtils.val(Document::getStarNum),
EntityInfoHelper.getEntityInfo(Document.class).getMappingColumnMap()));
fieldSortBuilder.order(SortOrder.Desc);
wrapper.sort(fieldSortBuilder);
wrapper.sort(SortOptions.of(a -> a.field(b -> b
.field(realField)
.order(SortOrder.Desc)
)));
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertEquals("22", documents.get(0).getEsId());
Assertions.assertEquals("21", documents.get(1).getEsId());
@ -781,7 +775,7 @@ public class AllTest {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.matchPhrase(Document::getContent, "测试");
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertTrue(documents.size() > 0);
Assertions.assertFalse(documents.isEmpty());
LambdaEsQueryWrapper<Document> wrapper1 = new LambdaEsQueryWrapper<>();
wrapper1.matchPhrase(Document::getContent, "内容测试");
@ -854,8 +848,8 @@ public class AllTest {
@Order(6)
public void testGeoBoundingBox() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
GeoLocation leftTop = new GeoLocation(41.187328D, 115.498353D);
GeoLocation bottomRight = new GeoLocation(39.084509D, 117.610461D);
GeoLocation leftTop = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(41.187328D).lon(115.498353D)));
GeoLocation bottomRight = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(39.084509D).lon(117.610461D)));
wrapper.geoBoundingBox(Document::getLocation, leftTop, bottomRight);
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertEquals(4, documents.size());
@ -866,14 +860,15 @@ public class AllTest {
@Order(6)
public void testGeoDistance() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
GeoLocation geoPoint = new GeoLocation(41.0, 116.0);
wrapper.geoDistance(Document::getLocation, 168.8, DistanceUnit.KILOMETERS, geoPoint);
GeoDistanceSortBuilder geoDistanceSortBuilder = SortBuilders.geoDistanceSort(FieldUtils.val(Document::getLocation), geoPoint)
.unit(DistanceUnit.KILOMETERS)
.geoDistance(GeoDistance.ARC)
.order(SortOrder.Desc);
wrapper.sort(geoDistanceSortBuilder);
GeoLocation geoPoint = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(41.0).lon(116.0)));
wrapper.geoDistance(Document::getLocation, 168.8, DistanceUnit.Kilometers, geoPoint);
wrapper.sort(SortOptions.of(a -> a.geoDistance(b -> b
.field(FieldUtils.val(Document::getLocation))
.location(geoPoint)
.unit(DistanceUnit.Kilometers)
.distanceType(GeoDistanceType.Arc)
.order(SortOrder.Desc)
)));
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertEquals(4, documents.size());
}
@ -883,9 +878,9 @@ public class AllTest {
public void testGeoPolygon() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
List<GeoLocation> geoPoints = new ArrayList<>();
GeoLocation geoPoint = new GeoLocation(40.178012, 116.577188);
GeoLocation geoPoint1 = new GeoLocation(40.169329, 116.586315);
GeoLocation geoPoint2 = new GeoLocation(40.178288, 116.591813);
GeoLocation geoPoint = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(40.178012).lon(116.577188)));
GeoLocation geoPoint1 = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(40.169329).lon(116.586315)));
GeoLocation geoPoint2 = GeoLocation.of(a -> a.latlon(a1 -> a1.lat(40.178288).lon(116.591813)));
geoPoints.add(geoPoint);
geoPoints.add(geoPoint1);
geoPoints.add(geoPoint2);
@ -899,7 +894,7 @@ public class AllTest {
public void testGeoShape() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
Circle circle = new Circle(13, 14, 100);
wrapper.geoShape(Document::getGeoLocation, circle, GeoShapeRelation.DISJOINT);
wrapper.geoShape(Document::getGeoLocation, circle, GeoShapeRelation.Disjoint);
List<Document> documents = documentMapper.selectList(wrapper);
Assertions.assertEquals(22, documents.size());
}
@ -923,13 +918,16 @@ public class AllTest {
@Order(6)
public void testVector() {
// 向量查询, 查询条件构造
Map<String, Object> params = new HashMap<>();
params.put("vector", new double[]{0.39684247970581055, 0.7687071561813354, 0.5145490765571594});
String scriptCode = "cosineSimilarity(params.vector, 'vector') + 1.0";
QueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptCode, params));
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(queryBuilder);
Query query = Query.of(a -> a.scriptScore(b -> b
.query(QueryBuilders.matchAll().build()._toQuery())
.script(d -> d
.lang(ScriptLanguage.Painless)
.params("vector", JsonData.of(new double[]{0.39684247970581055, 0.7687071561813354, 0.5145490765571594}))
.source("cosineSimilarity(params.vector, 'vector') + 1.0")
)
));
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(query);
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.setSearchSourceBuilder(searchSourceBuilder);
@ -941,11 +939,10 @@ public class AllTest {
@Order(6)
public void testSetRequestOptions() {
// 可设置自定义请求参数,覆盖默认配置, 解决报错 entity content is too long [168583249] for the configured buffer limit [104857600]
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.setHttpAsyncResponseConsumerFactory(
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.setHttpAsyncResponseConsumerFactory(
new HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory(4 * 104857600));
final RequestOptions requestOptions = options.build();
Boolean success = documentMapper.setRequestOptions(requestOptions);
Boolean success = documentMapper.setRequestOptions(new RestClientOptions(builder.build(), true));
Assertions.assertTrue(success);
}
@ -991,12 +988,20 @@ public class AllTest {
// where business_type = 1 and (state = 9 or (state = 8 and bidding_sign = 1)) or (business_type = 2 and state in (2,3))
// ElasticsearchClient写法
List<Integer> values = Arrays.asList(2, 3);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termQuery("business_type", 1));
boolQueryBuilder.must(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("state", 9))
.should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("state", 8)).must(QueryBuilders.termQuery("bidding_sign", 1))));
boolQueryBuilder.should(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("business_type", 2)).must(QueryBuilders.termsQuery("state", values)));
List<FieldValue> values = Arrays.asList(WrapperProcessor.fieldValue(2), WrapperProcessor.fieldValue(3));
BoolQuery.Builder boolQueryBuilder = QueryBuilders.bool()
.must(a -> a.term(b -> b.field("business_type").value(1)))
.must(a -> a.bool(b -> b
.must(c -> c.term(d -> d.field("state").value(9)))
.should(c -> c.bool(d -> d
.must(f -> f.term(e -> e.field("state").value(8)))
.must(f -> f.term(e -> e.field("bidding_sign").value(1)))
))
))
.should(a -> a.bool(c -> c
.must(d -> d.term(e -> e.field("business_type").value(2)))
.must(d -> d.terms(e -> e.field("state").terms(f -> f.value(values))))
));
System.out.println(boolQueryBuilder);
System.out.println("--------------------");

View File

@ -1,137 +1,137 @@
package org.dromara.easyes.test.index;
import org.dromara.easyes.annotation.rely.Analyzer;
import org.dromara.easyes.annotation.rely.FieldType;
import org.dromara.easyes.core.conditions.index.LambdaEsIndexWrapper;
import org.dromara.easyes.test.TestEasyEsApplication;
import org.dromara.easyes.test.entity.Document;
import org.dromara.easyes.test.mapper.DocumentMapper;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.noear.solon.annotation.Inject;
import org.noear.solon.test.SolonTest;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
/**
* 不了解Es索引概念的建议先去了解 懒汉可以简单理解为MySQL中的一张表
* 索引测试 注意,此测试类下所有方法请先关闭自动挡模式,开启手动挡 配置: process-index-mode=manual
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Disabled
@SolonTest(classes = TestEasyEsApplication.class)
public class IndexTest {
@Inject
private DocumentMapper documentMapper;
/**
* 测试创建索引 根据实体类字段及其注解配置创建索引 大多数场景适用,最为简单,但灵活性稍差
* 创建的索引与自动挡-运动模式一样,但触发方式为手动调用 区别是自动挡模式下索引创建及更新随spring容器启动时自动执行
*/
@Test
public void testCreateIndexByEntity() {
// 绝大多数场景推荐使用 简单至上
boolean ok = documentMapper.createIndex();
Assertions.assertTrue(ok);
}
/**
* 测试创建索引 根据自定义信息去创建,最为灵活,用此种方式可支持任何es支持的索引
*/
@Test
public void testCreateIndex() {
// 复杂场景使用
LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
// 此处简单起见 索引名称须保持和实体类名称一致,字母小写 后面章节会教大家更如何灵活配置和使用索引
wrapper.indexName(Document.class.getSimpleName().toLowerCase());
// 此处将文章标题映射为keyword类型(不支持分词),文档内容映射为text类型(支持分词查询)
wrapper.mapping(Document::getTitle, FieldType.KEYWORD, 2.0f)
.mapping(Document::getLocation, FieldType.GEO_POINT)
.mapping(Document::getGeoLocation, FieldType.GEO_SHAPE)
.mapping(Document::getContent, FieldType.TEXT, Analyzer.IK_SMART, Analyzer.IK_MAX_WORD);
// 0.9.8+版本,增加对符串字段名称的支持,Document实体中须在对应字段上加上@Tablefield(value="wu-la")用于映射此字段值
wrapper.mapping("wu-la", FieldType.TEXT, Analyzer.IK_MAX_WORD, Analyzer.IK_MAX_WORD);
// 设置分片及副本信息,可缺省
wrapper.settings(3, 2);
// 设置别名信息,可缺省
String aliasName = "daily";
wrapper.createAlias(aliasName);
// 设置父子信息,若无父子文档关系则无需设置
wrapper.join("joinField", "document", "comment");
// 创建索引
boolean isOk = documentMapper.createIndex(wrapper);
Assertions.assertTrue(isOk);
}
@Test
public void testExistsIndex() {
// 测试是否存在指定名称的索引
String indexName = Document.class.getSimpleName().toLowerCase();
boolean existsIndex = documentMapper.existsIndex(indexName);
Assertions.assertTrue(existsIndex);
}
@Test
public void testGetIndex() {
GetIndexResponse indexResponse = documentMapper.getIndex();
// 这里打印下索引结构信息 其它分片等信息皆可从indexResponse中取
indexResponse.getMappings().forEach((k, v) -> System.out.println(v.getSourceAsMap()));
}
@Test
public void testUpdateIndex() {
// 测试更新索引
LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
// 指定要更新哪个索引
String indexName = Document.class.getSimpleName().toLowerCase();
wrapper.indexName(indexName);
wrapper.mapping(Document::getCreator, FieldType.KEYWORD);
wrapper.mapping(Document::getGmtCreate, FieldType.DATE);
boolean isOk = documentMapper.updateIndex(wrapper);
Assertions.assertTrue(isOk);
}
@Test
public void testDeleteIndex() {
// 测试删除索引
// 指定要删除哪个索引
String indexName = Document.class.getSimpleName().toLowerCase();
boolean isOk = documentMapper.deleteIndex(indexName);
Assertions.assertTrue(isOk);
}
@Test
public void testCreateIndexByMap() {
// 演示通过自定义map创建索引,最为灵活,若我提供的创建索引API不能满足时可用此方法
LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
wrapper.indexName(Document.class.getSimpleName().toLowerCase());
wrapper.settings(3, 2);
Map<String, Object> map = new HashMap<>();
Map<String, Object> prop = new HashMap<>();
Map<String, String> field = new HashMap<>();
field.put("type", FieldType.KEYWORD.getType());
prop.put("this_is_field", field);
map.put("properties", prop);
wrapper.mapping(map);
boolean isOk = documentMapper.createIndex(wrapper);
Assertions.assertTrue(isOk);
}
@Test
public void testActiveIndex(){
String indexName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
documentMapper.setCurrentActiveIndex(indexName);
}
}
//package org.dromara.easyes.test.index;
//
//import org.dromara.easyes.annotation.rely.Analyzer;
//import org.dromara.easyes.annotation.rely.FieldType;
//import org.dromara.easyes.core.conditions.index.LambdaEsIndexWrapper;
//import org.dromara.easyes.test.TestEasyEsApplication;
//import org.dromara.easyes.test.entity.Document;
//import org.dromara.easyes.test.mapper.DocumentMapper;
//import org.elasticsearch.client.indices.GetIndexResponse;
//import org.junit.jupiter.api.Assertions;
//import org.junit.jupiter.api.Disabled;
//import org.junit.jupiter.api.Test;
//import org.noear.solon.annotation.Inject;
//import org.noear.solon.test.SolonTest;
//
//import java.time.LocalDate;
//import java.time.format.DateTimeFormatter;
//import java.util.HashMap;
//import java.util.Map;
//
///**
// * 不了解Es索引概念的建议先去了解 懒汉可以简单理解为MySQL中的一张表
// * 索引测试 注意,此测试类下所有方法请先关闭自动挡模式,开启手动挡 配置: process-index-mode=manual
// * <p>
// * Copyright © 2021 xpc1024 All Rights Reserved
// **/
//@Disabled
//@SolonTest(classes = TestEasyEsApplication.class)
//public class IndexTest {
// @Inject
// private DocumentMapper documentMapper;
//
// /**
// * 测试创建索引 根据实体类字段及其注解配置创建索引 大多数场景适用,最为简单,但灵活性稍差
// * 创建的索引与自动挡-运动模式一样,但触发方式为手动调用 区别是自动挡模式下索引创建及更新随spring容器启动时自动执行
// */
// @Test
// public void testCreateIndexByEntity() {
// // 绝大多数场景推荐使用 简单至上
// boolean ok = documentMapper.createIndex();
// Assertions.assertTrue(ok);
// }
//
// /**
// * 测试创建索引 根据自定义信息去创建,最为灵活,用此种方式可支持任何es支持的索引
// */
// @Test
// public void testCreateIndex() {
// // 复杂场景使用
// LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
// // 此处简单起见 索引名称须保持和实体类名称一致,字母小写 后面章节会教大家更如何灵活配置和使用索引
// wrapper.indexName(Document.class.getSimpleName().toLowerCase());
//
// // 此处将文章标题映射为keyword类型(不支持分词),文档内容映射为text类型(支持分词查询)
// wrapper.mapping(Document::getTitle, FieldType.KEYWORD, 2.0f)
// .mapping(Document::getLocation, FieldType.GEO_POINT)
// .mapping(Document::getGeoLocation, FieldType.GEO_SHAPE)
// .mapping(Document::getContent, FieldType.TEXT, Analyzer.IK_SMART, Analyzer.IK_MAX_WORD);
//
// // 0.9.8+版本,增加对符串字段名称的支持,Document实体中须在对应字段上加上@Tablefield(value="wu-la")用于映射此字段值
// wrapper.mapping("wu-la", FieldType.TEXT, Analyzer.IK_MAX_WORD, Analyzer.IK_MAX_WORD);
//
// // 设置分片及副本信息,可缺省
// wrapper.settings(3, 2);
//
// // 设置别名信息,可缺省
// String aliasName = "daily";
// wrapper.createAlias(aliasName);
//
// // 设置父子信息,若无父子文档关系则无需设置
// wrapper.join("joinField", "document", "comment");
//
// // 创建索引
// boolean isOk = documentMapper.createIndex(wrapper);
// Assertions.assertTrue(isOk);
// }
//
// @Test
// public void testExistsIndex() {
// // 测试是否存在指定名称的索引
// String indexName = Document.class.getSimpleName().toLowerCase();
// boolean existsIndex = documentMapper.existsIndex(indexName);
// Assertions.assertTrue(existsIndex);
// }
//
// @Test
// public void testGetIndex() {
// GetIndexResponse indexResponse = documentMapper.getIndex();
// // 这里打印下索引结构信息 其它分片等信息皆可从indexResponse中取
// indexResponse.getMappings().forEach((k, v) -> System.out.println(v.getSourceAsMap()));
// }
//
// @Test
// public void testUpdateIndex() {
// // 测试更新索引
// LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
// // 指定要更新哪个索引
// String indexName = Document.class.getSimpleName().toLowerCase();
// wrapper.indexName(indexName);
// wrapper.mapping(Document::getCreator, FieldType.KEYWORD);
// wrapper.mapping(Document::getGmtCreate, FieldType.DATE);
// boolean isOk = documentMapper.updateIndex(wrapper);
// Assertions.assertTrue(isOk);
// }
//
// @Test
// public void testDeleteIndex() {
// // 测试删除索引
// // 指定要删除哪个索引
// String indexName = Document.class.getSimpleName().toLowerCase();
// boolean isOk = documentMapper.deleteIndex(indexName);
// Assertions.assertTrue(isOk);
// }
//
// @Test
// public void testCreateIndexByMap() {
// // 演示通过自定义map创建索引,最为灵活,若我提供的创建索引API不能满足时可用此方法
// LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
// wrapper.indexName(Document.class.getSimpleName().toLowerCase());
// wrapper.settings(3, 2);
// Map<String, Object> map = new HashMap<>();
// Map<String, Object> prop = new HashMap<>();
// Map<String, String> field = new HashMap<>();
// field.put("type", FieldType.KEYWORD.getType());
// prop.put("this_is_field", field);
// map.put("properties", prop);
// wrapper.mapping(map);
// boolean isOk = documentMapper.createIndex(wrapper);
// Assertions.assertTrue(isOk);
// }
//
// @Test
// public void testActiveIndex(){
// String indexName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
// documentMapper.setCurrentActiveIndex(indexName);
// }
//}

View File

@ -1,9 +1,9 @@
easy-es:
# enable: true
address: 127.0.0.1:9200
address: cdev.rancher.good20.com:30156
# schema: http
# username: elastic
# password: WG7WVmuNMtM4GwNYkyWH
username: elastic
password: mg123456
keep-alive-millis: 18000
global-config:
i-kun-mode: true

View File

@ -35,7 +35,6 @@ import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.ParsedMax;
import org.elasticsearch.search.aggregations.metrics.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
@ -168,7 +167,7 @@ public class XmlScannerAllTest {
@Order(4)
public void testUpdateBySetSearchSourceBuilder() {
LambdaEsUpdateWrapper<Document> wrapper = new LambdaEsUpdateWrapper<>();
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(QueryBuilders.termQuery(FieldUtils.val(Document::getTitle) + KEYWORD_SUFFIX, "测试文档2"));
wrapper.setSearchSourceBuilder(searchSourceBuilder);
@ -535,7 +534,7 @@ public class XmlScannerAllTest {
@Order(6)
public void testSetSearchSourceBuilder() {
// 测试混合查询的另一种方式
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(QueryBuilders.matchQuery(FieldUtils.val(Document::getCreator), "老汉"));
Optional.ofNullable(EntityInfoHelper.getEntityInfo(Document.class))
.flatMap(i -> Optional.ofNullable(i.getMaxResultWindow()))
@ -928,7 +927,7 @@ public class XmlScannerAllTest {
String scriptCode = "cosineSimilarity(params.vector, 'vector') + 1.0";
QueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptCode, params));
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(queryBuilder);
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.setSearchSourceBuilder(searchSourceBuilder);

View File

@ -36,7 +36,6 @@ import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.ParsedMax;
import org.elasticsearch.search.aggregations.metrics.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
@ -170,7 +169,7 @@ public class AllTest {
@Order(4)
public void testUpdateBySetSearchSourceBuilder() {
LambdaEsUpdateWrapper<Document> wrapper = new LambdaEsUpdateWrapper<>();
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(QueryBuilders.termQuery(FieldUtils.val(Document::getTitle) + KEYWORD_SUFFIX, "测试文档2"));
wrapper.setSearchSourceBuilder(searchSourceBuilder);
@ -537,7 +536,7 @@ public class AllTest {
@Order(6)
public void testSetSearchSourceBuilder() {
// 测试混合查询的另一种方式
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(QueryBuilders.matchQuery(FieldUtils.val(Document::getCreator), "老汉"));
Optional.ofNullable(EntityInfoHelper.getEntityInfo(Document.class))
.flatMap(i -> Optional.ofNullable(i.getMaxResultWindow()))
@ -930,7 +929,7 @@ public class AllTest {
String scriptCode = "cosineSimilarity(params.vector, 'vector') + 1.0";
QueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptCode, params));
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(queryBuilder);
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.setSearchSourceBuilder(searchSourceBuilder);

View File

@ -12,7 +12,6 @@ import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -46,7 +45,7 @@ public class CompareTest {
TermsQueryBuilder creatorTerm = QueryBuilders.termsQuery("creator", "老汉");
boolQueryBuilder.must(titleTerm);
boolQueryBuilder.must(creatorTerm);
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
try {

View File

@ -20,7 +20,7 @@ public class IgnoreTest {
//
// @Test
// public void testSearch0() throws IOException {
// SearchRequest.Builder builder = new SearchSourceBuilder();
// SearchRequest.Builder builder = new SearchRequest.Builder();
// BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//
//// boolQueryBuilder.must(QueryBuilders.termQuery("overt", Boolean.TRUE));

View File

@ -13,7 +13,6 @@ import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.ScriptSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
@ -69,7 +68,7 @@ public class MixTest {
@Test
public void testMix1() {
// ElasticsearchClient原生语法
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(QueryBuilders.matchQuery("content", "推*").minimumShouldMatch("80%"));
// 仅利用EE查询并解析数据功能
@ -170,7 +169,7 @@ public class MixTest {
.match(Document::getContent, "推*");
// SearchSourceBuilder的构造是自己new出来的,不是通过mapper.getSearchSourceBuilder(wrapper)构造 相当于脱裤子放P,那么上面的查询条件老汉推*自然不会生效
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.minScore(10.5);
wrapper.setSearchSourceBuilder(searchSourceBuilder);
List<Document> documents = documentMapper.selectList(wrapper);

View File

@ -17,7 +17,6 @@ import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.xcontent.XContentType;
import org.junit.jupiter.api.Disabled;
@ -74,7 +73,7 @@ public class PerformanceTest {
public void testSelectByElasticsearchClient() {
// 构建查询条件
StopWatch stopwatch = StopWatch.createStarted();
SearchRequest.Builder builder = new SearchSourceBuilder();
SearchRequest.Builder builder = new SearchRequest.Builder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("title", "茶叶"));
boolQueryBuilder.must(QueryBuilders.matchQuery("content", "茶叶"));

View File

@ -10,7 +10,6 @@ import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@ -60,7 +59,7 @@ public class VectorTest {
String scriptCode = "cosineSimilarity(params.vector, 'vector') + 1.0";
QueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptCode, params));
SearchRequest.Builder searchSourceBuilder = new SearchSourceBuilder();
SearchRequest.Builder searchSourceBuilder = new SearchRequest.Builder();
searchSourceBuilder.query(queryBuilder);
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.setSearchSourceBuilder(searchSourceBuilder);