diff --git a/easy-es-common/src/main/java/org/dromara/easyes/common/constants/BaseEsConstants.java b/easy-es-common/src/main/java/org/dromara/easyes/common/constants/BaseEsConstants.java index 59462784..df57e130 100644 --- a/easy-es-common/src/main/java/org/dromara/easyes/common/constants/BaseEsConstants.java +++ b/easy-es-common/src/main/java/org/dromara/easyes/common/constants/BaseEsConstants.java @@ -194,10 +194,6 @@ public interface BaseEsConstants { * 更新索引时自动创建的索引后缀s1 */ String S1_SUFFIX = "_s1"; - /** - * 分布式锁提示内容 - */ - String DISTRIBUTED_LOCK_TIP_JSON = "{\"tip\":\"Do not delete unless deadlock occurs\"}"; /** * 获取/释放 分布式锁 最大失败重试次数 */ diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexInfo.java b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexInfo.java index a8c95491..3e644d37 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexInfo.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexInfo.java @@ -32,5 +32,5 @@ public class EsIndexInfo { /** * 索引字段信息 */ - private TypeMapping.Builder mapping; + private TypeMapping.Builder builder; } diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/Generator.java b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/Generator.java index b8fa32e2..b0b7a89f 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/Generator.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/Generator.java @@ -40,7 +40,7 @@ public abstract class Generator { public void generateEntity(GeneratorConfig config, ElasticsearchClient client) { // get index info EsIndexInfo esIndexInfo = IndexUtils.getIndexInfo(client, config.getIndexName()); - TypeMapping.Builder mapping = esIndexInfo.getMapping(); + TypeMapping.Builder mapping = esIndexInfo.getBuilder(); if (mapping == null) { return; } diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java index 4686994e..e741fcc3 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java @@ -323,9 +323,8 @@ public class IndexUtils { .size(mappings.size()) .source(mappings.source()) .runtime(mappings.runtime()) - .enabled(mappings.enabled()) - ; - esIndexInfo.setMapping(builder); + .enabled(mappings.enabled()); + esIndexInfo.setBuilder(builder); } return esIndexInfo; @@ -416,7 +415,7 @@ public class IndexUtils { // 父子类型 if (CollectionUtils.isNotEmpty(entityInfo.getRelationMap())) { mapping.properties(entityInfo.getJoinFieldName(), x -> x.join(y -> y - .relations(entityInfo.getRelationMap()) + .relations(entityInfo.getRelationMap()) // .eagerGlobalOrdinals(entityInfo.isEagerGlobalOrdinals()) )); } @@ -967,7 +966,7 @@ public class IndexUtils { * 根据配置生成创建索引参数 * * @param entityInfo 配置信息 - * @param clazz 实体类 + * @param clazz 实体类 * @return 创建索引参数 */ public static CreateIndexParam getCreateIndexParam(EntityInfo entityInfo, Class clazz) { @@ -1000,7 +999,7 @@ public class IndexUtils { * * @param entityInfo 实体信息 * @param fieldList 字段列表 - * @param clazz 实体类 + * @param clazz 实体类 * @return 索引参数列表 */ public static List initIndexParam(EntityInfo entityInfo, Class clazz, List fieldList) { @@ -1088,10 +1087,13 @@ public class IndexUtils { // 根据实体类注解信息构建mapping entityInfo.setIndexEqualStage(true); - TypeMapping.Builder mapping = IndexUtils.initMapping(entityInfo, esIndexParamList); + TypeMapping.Builder builderFromEntity = IndexUtils.initMapping(entityInfo, esIndexParamList); // 与查询到的已知index对比是否发生改变 - return !mapping.equals(esIndexInfo.getMapping()); + TypeMapping.Builder builderFromIndex = esIndexInfo.getBuilder(); + Map propertiesOfEntity = builderFromEntity.build().properties(); + Map propertiesOfIndex = builderFromIndex.build().properties(); + return !PropertyComparator.isPropertyMapEqual(propertiesOfEntity,propertiesOfIndex); } /** @@ -1174,7 +1176,8 @@ public class IndexUtils { ); SearchResponse> response = null; try { - response = client.search(searchRequest, new TypeReference>(){}.getType()); + response = client.search(searchRequest, new TypeReference>() { + }.getType()); } catch (Throwable e) { LogUtils.warn("Active failed, The machine that acquired lock is migrating, will try again later"); } diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/LockUtils.java b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/LockUtils.java index 6b4e34f2..2cf897a2 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/LockUtils.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/LockUtils.java @@ -7,6 +7,8 @@ import co.elastic.clients.elasticsearch.core.*; import org.dromara.easyes.common.constants.BaseEsConstants; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import static org.dromara.easyes.common.constants.BaseEsConstants.LOCK_INDEX; @@ -24,6 +26,14 @@ public class LockUtils { * 重试等待时间 */ private final static Integer WAIT_SECONDS = 1; + /** + * 分布式锁内容 + */ + private final static Map LOCK_DOC; + static { + LOCK_DOC = new HashMap<>(2); + LOCK_DOC.put("tip","Do not delete unless deadlock occurs"); + } /** * 尝试获取es分布式锁 @@ -64,12 +74,12 @@ public class LockUtils { */ private static boolean createLock(ElasticsearchClient client, String idValue) { IndexRequest indexRequest = IndexRequest.of(x -> x - .index(LOCK_INDEX).id(idValue).document(BaseEsConstants.DISTRIBUTED_LOCK_TIP_JSON) + .index(LOCK_INDEX).id(idValue).document(LOCK_DOC) ); IndexResponse response; try { response = client.index(indexRequest); - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); return Boolean.FALSE; } diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/PropertyComparator.java b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/PropertyComparator.java new file mode 100644 index 00000000..68c6a920 --- /dev/null +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/PropertyComparator.java @@ -0,0 +1,184 @@ +package org.dromara.easyes.core.toolkit; + +import co.elastic.clients.elasticsearch._types.mapping.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 索引属性变化比较器 + *

+ * Copyright © 2022 xpc1024 All Rights Reserved + **/ +public class PropertyComparator { + + public static boolean isPropertyMapEqual(Map map1, Map map2) { + // 直接引用相等性检查 + if (map1 == map2) { + return true; + } + + // 基础检查:大小是否一致 + if (map1.size() != map2.size()) { + return false; + } + + // 遍历所有键进行深度比较 + for (String key : map1.keySet()) { + Property prop1 = map1.get(key); + // 检查键是否存在 + if (!map2.containsKey(key)) { + return false; + } + Property prop2 = map2.get(key); + // 深度比较属性 + if (!deepCompareProperties(prop1, prop2)) { + return false; + } + } + + return true; + } + + private static boolean deepCompareProperties(Property prop1, Property prop2) { + // 快速引用相等检查 + if (prop1 == prop2) return true; + + // 类型基础检查 + if (prop1._kind() != prop2._kind()) return false; + + // 按类型分发处理逻辑 + switch (prop1._kind()) { + case Nested: + return compareNested(prop1.nested(), prop2.nested()); + case Object: + return compareObject(prop1.object(), prop2.object()); + case Text: + return compareText(prop1.text(), prop2.text()); + case Keyword: + return compareKeyword(prop1.keyword(), prop2.keyword()); + case Date: + return compareDate(prop1.date(), prop2.date()); + case GeoPoint: + return compareGeoPoint(prop1.geoPoint(), prop2.geoPoint()); + case Ip: + return compareIp(prop1.ip(), prop2.ip()); + case ScaledFloat: + return compareScaledFloat(prop1.scaledFloat(), prop2.scaledFloat()); + case Completion: + return compareCompletion(prop1.completion(), prop2.completion()); + case Flattened: + return compareFlattened(prop1.flattened(), prop2.flattened()); + case DenseVector: + return compareDenseVector(prop1.denseVector(), prop2.denseVector()); + case GeoShape: + return compareGeoShape(prop1.geoShape(), prop2.geoShape()); + case Wildcard: + return compareWildcard(prop1.wildcard(), prop2.wildcard()); + case Byte: + case Short: + case Float: + case HalfFloat: + case Double: + case Integer: + case Long: + return compareNumberType((NumberPropertyBase) prop1._get(), (NumberPropertyBase) prop2._get()); + default: + // 其他非常用类型 比较了key和type相同即认为相同 后续会随对应功能迭代继续完善 + return true; + } + } + + // 新增GeoShape和Wildcard的比较方法 + private static boolean compareGeoShape(GeoShapeProperty p1, GeoShapeProperty p2) { + return Objects.equals(p1.ignoreMalformed(), p2.ignoreMalformed()) && + Objects.equals(p1.ignoreZValue(), p2.ignoreZValue()) && + Objects.equals(p1.coerce(), p2.coerce()) && + Objects.equals(p1.orientation(), p2.orientation()); + } + + private static boolean compareNumberType(NumberPropertyBase p1, NumberPropertyBase p2) { + return Objects.equals(p1.docValues(), p2.docValues()) && + Objects.equals(p1.ignoreMalformed(), p2.ignoreMalformed()); + } + + private static boolean compareWildcard(WildcardProperty p1, WildcardProperty p2) { + return Objects.equals(p1.ignoreAbove(), p2.ignoreAbove()) && + unorderedEquals(p1.copyTo(), p2.copyTo()); + } + + + // 各类型详细比较逻辑 + private static boolean compareNested(NestedProperty p1, NestedProperty p2) { + return Objects.equals(p1.dynamic(), p2.dynamic()) && + isPropertyMapEqual(p1.properties(), p2.properties()); + } + + private static boolean compareObject(ObjectProperty p1, ObjectProperty p2) { + return Objects.equals(p1.dynamic(), p2.dynamic()) && + isPropertyMapEqual(p1.properties(), p2.properties()); + } + + private static boolean compareText(TextProperty p1, TextProperty p2) { + return Objects.equals(p1.analyzer(), p2.analyzer()) && + Objects.equals(p1.searchAnalyzer(), p2.searchAnalyzer()) && + unorderedEquals(p1.copyTo(), p2.copyTo()) && + isPropertyMapEqual(p1.fields(), p2.fields()); + } + + private static boolean compareKeyword(KeywordProperty p1, KeywordProperty p2) { + return Objects.equals(p1.ignoreAbove(), p2.ignoreAbove()) && + unorderedEquals(p1.copyTo(), p2.copyTo()); + } + + private static boolean compareDate(DateProperty p1, DateProperty p2) { + return Objects.equals(p1.format(), p2.format()) && + Objects.equals(p1.ignoreMalformed(), p2.ignoreMalformed()); + } + + private static boolean compareGeoPoint(GeoPointProperty p1, GeoPointProperty p2) { + return Objects.equals(p1.ignoreMalformed(), p2.ignoreMalformed()) && + Objects.equals(p1.ignoreZValue(), p2.ignoreZValue()); + } + + private static boolean compareIp(IpProperty p1, IpProperty p2) { + return Objects.equals(p1.boost(), p2.boost()) && + Objects.equals(p1.docValues(), p2.docValues()); + } + + private static boolean compareScaledFloat(ScaledFloatNumberProperty p1, + ScaledFloatNumberProperty p2) { + return Objects.equals(p1.scalingFactor(), p2.scalingFactor()) && + Objects.equals(p1.coerce(), p2.coerce()); + } + + private static boolean compareCompletion(CompletionProperty p1, + CompletionProperty p2) { + return Objects.equals(p1.preserveSeparators(), p2.preserveSeparators()) && + Objects.equals(p1.preservePositionIncrements(), + p2.preservePositionIncrements()); + } + + private static boolean compareFlattened(FlattenedProperty p1, + FlattenedProperty p2) { + return Objects.equals(p1.boost(), p2.boost()) && + Objects.equals(p1.depthLimit(), p2.depthLimit()); + } + + + private static boolean compareDenseVector(DenseVectorProperty p1, + DenseVectorProperty p2) { + return Objects.equals(p1.dims(), p2.dims()) && + Objects.equals(p1.similarity(), p2.similarity()); + } + + // 辅助方法:处理无序集合比较 + private static boolean unorderedEquals(List list1, List list2) { + if (list1 == list2) return true; + if (list1 == null || list2 == null) return false; + return new HashSet<>(list1).equals(new HashSet<>(list2)); + } + +} diff --git a/easy-es-springboot-sample/src/main/resources/application.yml b/easy-es-springboot-sample/src/main/resources/application.yml index aedf665d..80dd181d 100644 --- a/easy-es-springboot-sample/src/main/resources/application.yml +++ b/easy-es-springboot-sample/src/main/resources/application.yml @@ -16,4 +16,4 @@ easy-es: id-type: customize field-strategy: not_empty refresh-policy: immediate - enable-track-total-hits: true \ No newline at end of file + enable-track-total-hits: true