You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by xx...@apache.org on 2022/12/13 10:25:24 UTC
[kylin] 17/25: KYLIN-5318 Create model API calls fail when CC expressions are the same
This is an automated email from the ASF dual-hosted git repository.
xxyu pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git
commit 3bee29fcc3ae029c780ffbe3fa289f68e5a34387
Author: Jiale He <35...@users.noreply.github.com>
AuthorDate: Fri Oct 14 14:59:53 2022 +0800
KYLIN-5318 Create model API calls fail when CC expressions are the same
---
.../resources/kylin_error_msg_conf_cn.properties | 2 +-
.../resources/kylin_error_msg_conf_en.properties | 2 +-
.../metadata/model/util/ComputedColumnUtil.java | 8 +-
.../apache/kylin/rest/service/ModelService.java | 53 ++++++++++-
.../kylin/rest/service/ModelServiceTest.java | 102 ++++++++++++++++++---
5 files changed, 147 insertions(+), 20 deletions(-)
diff --git a/src/core-common/src/main/resources/kylin_error_msg_conf_cn.properties b/src/core-common/src/main/resources/kylin_error_msg_conf_cn.properties
index 27641ca5b2..e6a11efcc1 100644
--- a/src/core-common/src/main/resources/kylin_error_msg_conf_cn.properties
+++ b/src/core-common/src/main/resources/kylin_error_msg_conf_cn.properties
@@ -96,7 +96,7 @@ KE-010031201=因为查询结果行数超过最大值 ”%s”,无法完成查
KE-010031202=SQL 语法或格式异常,请检查并修正后重试。
## 100102XX computed column
-KE-010010201=模型中定义的可计算列的名和表达式与其它模型存在冲突,请修改名称以保持一致,或使用其他的表达式。
+KE-010010201=模型中定义的可计算列的名和表达式与其它模型存在冲突。
KE-010010202=重复的可计算列名,名为 “%s” 表达式为 “%s” 的可计算列,与模型 “%s” 中的可计算列名存在冲突。
KE-010010203=重复的可计算列表达式,名为 “%s” 表达式为 “%s” 的可计算列,与模型 “%s” 中的可计算列表达式存在冲突。
KE-010010204=名为 “%s” 表达式为 “%s” 的可计算列,与项目中名为 “%s” 表达式为 “%s” 的可计算列表达式存在冲突,将当前可计算列重命名为 “%s” 。
diff --git a/src/core-common/src/main/resources/kylin_error_msg_conf_en.properties b/src/core-common/src/main/resources/kylin_error_msg_conf_en.properties
index 3f87894a80..b4130c7b2a 100644
--- a/src/core-common/src/main/resources/kylin_error_msg_conf_en.properties
+++ b/src/core-common/src/main/resources/kylin_error_msg_conf_en.properties
@@ -94,7 +94,7 @@ KE-010031201=Can't get query result, as the rows of query result exceeds the max
KE-010031202=SQL syntax or format is abnormal, please check and fix and try again.
## 100102XX computed column
-KE-010010201=The name and expression of the computed column defined in the model conflict with other models. Please modify the name to be consistent, or use another expression.
+KE-010010201=The name and expression of the computed column defined in the model conflict with other models.
KE-010010202=Duplicate computed column name, defined computed column named "%s" with expression "%s", conflicts with a computed column name in model "%s".
KE-010010203=Duplicate computed column expression, defined computed column named "%s" with expression "%s", conflicts with a computed column expression in model "%s".
KE-010010204=Defined computed column named "%s" with expression "%s" is inconsistent with the name of the computed column named "%s" with the expression "%s" in the project. Renamed to "%s".
diff --git a/src/core-metadata/src/main/java/org/apache/kylin/metadata/model/util/ComputedColumnUtil.java b/src/core-metadata/src/main/java/org/apache/kylin/metadata/model/util/ComputedColumnUtil.java
index b07c7cf5b0..ead8a3e8fd 100644
--- a/src/core-metadata/src/main/java/org/apache/kylin/metadata/model/util/ComputedColumnUtil.java
+++ b/src/core-metadata/src/main/java/org/apache/kylin/metadata/model/util/ComputedColumnUtil.java
@@ -626,10 +626,10 @@ public class ComputedColumnUtil {
return exceptionList;
}
- public Pair<List<ComputedColumnDesc>, List<KylinException>> getAdjustedCCList(
+ public Pair<List<ComputedColumnDesc>, List<CCConflictDetail>> getAdjustedCCList(
List<ComputedColumnDesc> inputCCDescList) {
List<ComputedColumnDesc> resultCCDescList = Lists.newArrayList();
- List<KylinException> adjustExceptionList = Lists.newArrayList();
+ List<CCConflictDetail> adjustDetails = Lists.newArrayList();
for (ComputedColumnDesc ccDesc : inputCCDescList) {
for (CCConflictDetail detail : this.sameExprDiffNameDetails) {
@@ -638,13 +638,13 @@ public class ComputedColumnUtil {
if (newCC.equals(ccDesc)) {
logger.info("adjust cc name {} to {}", newCC.getColumnName(), existingCC.getColumnName());
ccDesc.setColumnName(existingCC.getColumnName());
- adjustExceptionList.add(detail.getAdjustKylinException());
+ adjustDetails.add(detail);
break;
}
}
resultCCDescList.add(ccDesc);
}
- return Pair.newPair(resultCCDescList, adjustExceptionList);
+ return Pair.newPair(resultCCDescList, adjustDetails);
}
}
diff --git a/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelService.java b/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelService.java
index e1441556d7..b836937033 100644
--- a/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelService.java
+++ b/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelService.java
@@ -4356,8 +4356,59 @@ public class ModelService extends AbstractModelService implements TableModelSupp
List<ComputedColumnDesc> inputCCDescList = Lists.newArrayList(modelRequest.getComputedColumnDescs());
// deal with conflicts
val pair = ccConflictInfo.getAdjustedCCList(inputCCDescList);
+ val adjustExceptions = pair.getSecond().stream() //
+ .map(ComputedColumnUtil.CCConflictDetail::getAdjustKylinException).collect(Collectors.toList());
+ ModelRequest resultModelRequest = adjustModelRequestCCName(modelRequest, pair);
+
+ return Pair.newPair(resultModelRequest, handleOnConflictResponse(adjustExceptions));
+ }
+
+ public ModelRequest adjustModelRequestCCName(ModelRequest modelRequest,
+ Pair<List<ComputedColumnDesc>, List<ComputedColumnUtil.CCConflictDetail>> pair) {
+ val adjustDetails = pair.getSecond();
+ // adjust cc name
modelRequest.setComputedColumnDescs(pair.getFirst());
- return Pair.newPair(modelRequest, handleOnConflictResponse(pair.getSecond()));
+
+ val dimensions = modelRequest.getSimplifiedDimensions();
+ val measures = modelRequest.getSimplifiedMeasures();
+ for (val detail : adjustDetails) {
+ String newCCFullName = detail.getNewCC().getFullName();
+ String existingCCFullName = detail.getExistingCC().getFullName();
+
+ // adjust dimensions
+ dimensions.stream() //
+ .filter(NDataModel.NamedColumn::isExist) //
+ // column equals
+ .filter(d -> StringUtils.equalsIgnoreCase(d.getAliasDotColumn(), newCCFullName))
+ .forEach(d -> d.setAliasDotColumn(existingCCFullName));
+
+ // adjust measures
+ measures.forEach(m -> m.getParameterValue().stream() //
+ // type = column
+ .filter(pr -> StringUtils.equalsIgnoreCase(pr.getType(), PARAMETER_TYPE_COLUMN))
+ // value equals
+ .filter(pr -> StringUtils.equalsIgnoreCase(pr.getValue(), newCCFullName))
+ .forEach(pr -> pr.setValue(existingCCFullName)));
+ }
+
+ // adjust filter condition
+ String filterCondition = modelRequest.getFilterCondition();
+ if (StringUtils.isEmpty(filterCondition)) {
+ return modelRequest;
+ }
+ for (val detail : adjustDetails) {
+ String newCCFullName = detail.getNewCC().getFullName();
+ String existingCCFullName = detail.getExistingCC().getFullName();
+ if (StringUtils.containsIgnoreCase(filterCondition, newCCFullName)) {
+ filterCondition = replaceAllIgnoreCase(filterCondition, newCCFullName, existingCCFullName);
+ }
+ }
+ modelRequest.setFilterCondition(filterCondition);
+ return modelRequest;
+ }
+
+ public String replaceAllIgnoreCase(String input, String regex, String replacement) {
+ return Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(input).replaceAll(replacement);
}
public ComputedColumnConflictResponse handleOnConflictResponse(List<KylinException> exceptionList) {
diff --git a/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelServiceTest.java b/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelServiceTest.java
index 7d3b71bcbc..696347e093 100644
--- a/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelServiceTest.java
+++ b/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelServiceTest.java
@@ -5666,8 +5666,8 @@ public class ModelServiceTest extends SourceTestCase {
testCheckCCConflictAllExprConflict(originRequest);
testCheckCCConflictExprAndNameConflict(originRequest);
testCheckCCConflictExprAndNameConflict2(originRequest);
- testCheckCCConflictAdjust(originRequest);
testNoCCConflict(originRequest);
+ testCheckCCConflictAdjust(originRequest);
}
private void testCheckCCConflictAllExprConflict(ModelRequest originRequest) {
@@ -5759,18 +5759,78 @@ public class ModelServiceTest extends SourceTestCase {
}
private void testCheckCCConflictAdjust(ModelRequest originRequest) {
- val ccList = Lists.newArrayList(//
- getComputedColumnDesc("CC_1", "CUSTOMER.C_NAME +'USA'", "DOUBLE"),
- getComputedColumnDesc("CC_LTAX", "LINEORDER.LO_TAX + 1", "BIGINT"));
- originRequest.setComputedColumnDescs(ccList);
- originRequest.setComputedColumnNameAutoAdjust(true);
- val pair = modelService.checkCCConflict(originRequest);
- val details = pair.getSecond().getConflictDetails();
- Assert.assertEquals(1, details.size());
- Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getErrorCode().getCode(),
- details.get(0).getDetailCode());
- Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getMsg("CC_1", "CUSTOMER.C_NAME +'USA'",
- "CC_CNAME", "CUSTOMER.C_NAME +'USA'", "CC_CNAME"), details.get(0).getDetailMsg());
+ {
+ val ccList = Lists.newArrayList(//
+ getComputedColumnDesc("CC_1", "CUSTOMER.C_NAME +'USA'", "DOUBLE"),
+ getComputedColumnDesc("CC_LTAX", "LINEORDER.LO_TAX + 1", "BIGINT"));
+ originRequest.setComputedColumnDescs(ccList);
+ originRequest.setComputedColumnNameAutoAdjust(true);
+ val pair = modelService.checkCCConflict(originRequest);
+ val details = pair.getSecond().getConflictDetails();
+ Assert.assertEquals(1, details.size());
+ Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getErrorCode().getCode(),
+ details.get(0).getDetailCode());
+ Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getMsg("CC_1", "CUSTOMER.C_NAME +'USA'",
+ "CC_CNAME", "CUSTOMER.C_NAME +'USA'", "CC_CNAME"), details.get(0).getDetailMsg());
+ }
+
+ {
+ val ccList = Lists.newArrayList(//
+ getComputedColumnDesc("CC_1", "CUSTOMER.C_NAME +'USA'", "DOUBLE"),
+ getComputedColumnDesc("CC_LTAX", "LINEORDER.LO_TAX + 1", "BIGINT"));
+ originRequest.setComputedColumnDescs(ccList);
+ originRequest.setComputedColumnNameAutoAdjust(true);
+ originRequest.setFilterCondition("LINEORDER.LO_TAX = 'Kylin' or LINEORDER.LO_TAX = 'Kylin2'");
+ val pair = modelService.checkCCConflict(originRequest);
+ val details = pair.getSecond().getConflictDetails();
+ Assert.assertEquals(1, details.size());
+ Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getErrorCode().getCode(),
+ details.get(0).getDetailCode());
+ Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getMsg("CC_1", "CUSTOMER.C_NAME +'USA'",
+ "CC_CNAME", "CUSTOMER.C_NAME +'USA'", "CC_CNAME"), details.get(0).getDetailMsg());
+ Assert.assertEquals("LINEORDER.LO_TAX = 'Kylin' or LINEORDER.LO_TAX = 'Kylin2'",
+ pair.getFirst().getFilterCondition());
+ }
+
+ {
+ val dimList = Lists.newArrayList(getNamedColumn("CC_1", "LINEORDER.CC_1"));
+ val measureList = Lists.newArrayList(//
+ getSimplifiedMeasure("cc_count", "COUNT", "column", "LINEORDER.CC_1"),
+ getSimplifiedMeasure("COUNT_ALL", "COUNT", "constant", "1"));
+ val ccList = Lists.newArrayList(//
+ getComputedColumnDesc("CC_1", "CUSTOMER.C_NAME +'USA'", "DOUBLE"),
+ getComputedColumnDesc("CC_LTAX", "LINEORDER.LO_TAX + 1", "BIGINT"));
+ originRequest.setComputedColumnDescs(ccList);
+ originRequest.setComputedColumnNameAutoAdjust(true);
+ originRequest.setSimplifiedDimensions(dimList);
+ originRequest.setSimplifiedMeasures(measureList);
+ originRequest.setFilterCondition("LINEORDER.Cc_1 = 'Kylin' or LINEORDER.cC_1 = 'Kylin2'");
+ val pair = modelService.checkCCConflict(originRequest);
+ val details = pair.getSecond().getConflictDetails();
+ Assert.assertEquals(1, details.size());
+ Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getErrorCode().getCode(),
+ details.get(0).getDetailCode());
+ Assert.assertEquals(COMPUTED_COLUMN_CONFLICT_ADJUST_INFO.getMsg("CC_1", "CUSTOMER.C_NAME +'USA'",
+ "CC_CNAME", "CUSTOMER.C_NAME +'USA'", "CC_CNAME"), details.get(0).getDetailMsg());
+
+ ModelRequest modelRequest = pair.getFirst();
+ val simplifiedDimensions = modelRequest.getSimplifiedDimensions();
+ Assert.assertEquals(1, simplifiedDimensions.size());
+ Assert.assertEquals("LINEORDER.CC_CNAME", simplifiedDimensions.get(0).getAliasDotColumn());
+ Assert.assertEquals("CC_1", simplifiedDimensions.get(0).getName());
+
+ List<SimplifiedMeasure> simplifiedMeasures = modelRequest.getSimplifiedMeasures();
+ Assert.assertEquals(2, simplifiedMeasures.size());
+ simplifiedMeasures = simplifiedMeasures.stream().filter(measure -> measure.getName().equals("cc_count"))
+ .collect(Collectors.toList());
+ Assert.assertEquals(1, simplifiedMeasures.size());
+ Assert.assertEquals("COUNT", simplifiedMeasures.get(0).getExpression());
+ Assert.assertEquals("column", simplifiedMeasures.get(0).getParameterValue().get(0).getType());
+ Assert.assertEquals("LINEORDER.CC_CNAME", simplifiedMeasures.get(0).getParameterValue().get(0).getValue());
+
+ Assert.assertEquals("LINEORDER.CC_CNAME = 'Kylin' or LINEORDER.CC_CNAME = 'Kylin2'",
+ modelRequest.getFilterCondition());
+ }
}
private void testNoCCConflict(ModelRequest originRequest) {
@@ -5828,4 +5888,20 @@ public class ModelServiceTest extends SourceTestCase {
return ccDesc;
}
+ private NamedColumn getNamedColumn(String name, String aliasDotName) {
+ NamedColumn namedColumn = new NamedColumn();
+ namedColumn.setName(name);
+ namedColumn.setAliasDotColumn(aliasDotName);
+ namedColumn.setStatus(NDataModel.ColumnStatus.DIMENSION);
+ return namedColumn;
+ }
+
+ private SimplifiedMeasure getSimplifiedMeasure(String name, String expr, String type, String value) {
+ ParameterResponse parameterResponse = new ParameterResponse(type, value);
+ SimplifiedMeasure measure = new SimplifiedMeasure();
+ measure.setName(name);
+ measure.setExpression(expr);
+ measure.setParameterValue(Lists.newArrayList(parameterResponse));
+ return measure;
+ }
}