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 618c2e37c72a40774cbfdb2222676b06210f4319 Author: Pengfei Zhan <pengfei.z...@kyligence.io> AuthorDate: Fri Nov 11 22:57:51 2022 +0800 KYLIN-5402 fix performance of checking computed columns 1. promote the performance of checking computed columns; 2. promote the performance of saving model; 3. resolve the code complexity of ModelService#checkModelMeasures. --- .../kylin/rest/service/ModelServiceBuildTest.java | 2 +- .../kylin/rest/service/ModelSemanticHelper.java | 2 +- .../apache/kylin/rest/service/ModelService.java | 79 ++++++++++++---------- .../kylin/rest/service/ModelServiceTest.java | 20 +++++- .../kylin/rest/service/ModelServiceQueryTest.java | 2 +- .../service/ModelServiceWithSecondStorageTest.java | 2 +- .../apache/kylin/rest/util/AclPermissionUtil.java | 4 +- 7 files changed, 69 insertions(+), 42 deletions(-) diff --git a/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/ModelServiceBuildTest.java b/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/ModelServiceBuildTest.java index 72df60801a..de7cef0bf1 100644 --- a/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/ModelServiceBuildTest.java +++ b/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/ModelServiceBuildTest.java @@ -201,7 +201,7 @@ public class ModelServiceBuildTest extends SourceTestCase { ReflectionTestUtils.setField(semanticService, "expandableMeasureUtil", new ExpandableMeasureUtil((model, ccDesc) -> { String ccExpression = QueryUtil.massageComputedColumn(model, model.getProject(), ccDesc, - AclPermissionUtil.prepareQueryContextACLInfo(model.getProject(), + AclPermissionUtil.createAclInfo(model.getProject(), semanticService.getCurrentUserGroups())); ccDesc.setInnerExpression(ccExpression); ComputedColumnEvalUtil.evaluateExprAndType(model, ccDesc); diff --git a/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelSemanticHelper.java b/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelSemanticHelper.java index f6866f2708..54190bcd77 100644 --- a/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelSemanticHelper.java +++ b/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelSemanticHelper.java @@ -131,7 +131,7 @@ public class ModelSemanticHelper extends BasicService { private static final Logger logger = LoggerFactory.getLogger(ModelSemanticHelper.class); private final ExpandableMeasureUtil expandableMeasureUtil = new ExpandableMeasureUtil((model, ccDesc) -> { String ccExpression = QueryUtil.massageComputedColumn(model, model.getProject(), ccDesc, - AclPermissionUtil.prepareQueryContextACLInfo(model.getProject(), getCurrentUserGroups())); + AclPermissionUtil.createAclInfo(model.getProject(), getCurrentUserGroups())); ccDesc.setInnerExpression(ccExpression); ComputedColumnEvalUtil.evaluateExprAndType(model, ccDesc); }); 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 77fd3c6c5f..1f915c3dfa 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 @@ -108,6 +108,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.kylin.common.KapConfig; import org.apache.kylin.common.KylinConfig; +import org.apache.kylin.common.QueryContext; import org.apache.kylin.common.event.ModelAddEvent; import org.apache.kylin.common.event.ModelDropEvent; import org.apache.kylin.common.exception.JobErrorCode; @@ -303,6 +304,7 @@ public class ModelService extends AbstractModelService implements TableModelSupp public static final Pattern VALID_NAME_FOR_MEASURE = Pattern.compile("^[\\u4E00-\\u9FA5a-zA-Z0-9 _\\-()%?().]+$"); private static final List<String> MODEL_CONFIG_BLOCK_LIST = Lists.newArrayList("kylin.index.rule-scheduler-data"); + private static final Set<String> STRING_TYPE_SET = Sets.newHashSet("STRING", "CHAR", "VARCHAR"); //The front-end supports only the following formats private static final List<String> SUPPORTED_FORMATS = ImmutableList.of("ZZ", "DD", "D", "Do", "dddd", "ddd", "dd", // @@ -1714,8 +1716,9 @@ public class ModelService extends AbstractModelService implements TableModelSupp @VisibleForTesting public void checkFlatTableSql(NDataModel dataModel) { - if (KylinConfig.getInstanceFromEnv().isUTEnv() || getManager(NProjectManager.class) - .getProject(dataModel.getProject()).getConfig().isSkipCheckFlatTable()) { + String project = dataModel.getProject(); + ProjectInstance prjInstance = getManager(NProjectManager.class).getProject(project); + if (KylinConfig.getInstanceFromEnv().isUTEnv() || prjInstance.getConfig().isSkipCheckFlatTable()) { return; } if (getModelConfig(dataModel).skipCheckFlatTable()) { @@ -1729,15 +1732,13 @@ public class ModelService extends AbstractModelService implements TableModelSupp } try { - ProjectInstance projectInstance = getManager(NProjectManager.class).getProject(dataModel.getProject()); - if (projectInstance.getSourceType() == ISourceAware.ID_SPARK + if (prjInstance.getSourceType() == ISourceAware.ID_SPARK && dataModel.getModelType() == NDataModel.ModelType.BATCH) { SparkSession ss = SparderEnv.getSparkSession(); String flatTableSql = JoinedFlatTable.generateSelectDataStatement(dataModel, false); - QueryParams queryParams = new QueryParams(dataModel.getProject(), flatTableSql, "default", false); - queryParams.setKylinConfig(projectInstance.getConfig()); - queryParams.setAclInfo( - AclPermissionUtil.prepareQueryContextACLInfo(dataModel.getProject(), getCurrentUserGroups())); + QueryParams queryParams = new QueryParams(project, flatTableSql, "default", false); + queryParams.setKylinConfig(prjInstance.getConfig()); + queryParams.setAclInfo(AclPermissionUtil.createAclInfo(project, getCurrentUserGroups())); String pushdownSql = QueryUtil.massagePushDownSql(queryParams); ss.sql(pushdownSql); } @@ -2163,27 +2164,38 @@ public class ModelService extends AbstractModelService implements TableModelSupp } } - @VisibleForTesting - public void checkModelMeasures(ModelRequest request) { - Set<String> measureNames = new HashSet<>(); - Set<SimplifiedMeasure> measures = new HashSet<>(); - KylinConfig kylinConfig = getManager(NProjectManager.class).getProject(request.getProject()).getConfig(); - int maxModelDimensionMeasureNameLength = kylinConfig.getMaxModelDimensionMeasureNameLength(); - + private void checkMeasureNameValid(ModelRequest request) { + int maxLen = NProjectManager.getProjectConfig(request.getProject()).getMaxModelDimensionMeasureNameLength(); + String invalidPattern = MsgPicker.getMsg().getInvalidMeasureName(); for (SimplifiedMeasure measure : request.getSimplifiedMeasures()) { - measure.setName(StringUtils.trim(measure.getName())); - // check if the measure name is valid - if (StringUtils.length(measure.getName()) > maxModelDimensionMeasureNameLength - || !checkIsValidMeasureName(measure.getName())) - throw new KylinException(INVALID_NAME, - String.format(Locale.ROOT, MsgPicker.getMsg().getInvalidMeasureName(), measure.getName(), - maxModelDimensionMeasureNameLength)); + String name = measure.getName(); + if (StringUtils.length(name) <= maxLen && checkIsValidMeasureName(name)) { + continue; + } + throw new KylinException(INVALID_NAME, String.format(Locale.ROOT, invalidPattern, name, maxLen)); + } + } - // check duplicate measure names - if (measureNames.contains(measure.getName())) + private void checkMeasureNameDuplicate(ModelRequest modelRequest) { + Set<String> measureNames = Sets.newHashSet(); + for (SimplifiedMeasure measure : modelRequest.getSimplifiedMeasures()) { + if (measureNames.contains(measure.getName())) { throw new KylinException(DUPLICATE_MEASURE_NAME, String.format(Locale.ROOT, MsgPicker.getMsg().getDuplicateMeasureName(), measure.getName())); + } else { + measureNames.add(measure.getName()); + } + } + } + @VisibleForTesting + public void checkModelMeasures(ModelRequest request) { + Set<SimplifiedMeasure> measures = new HashSet<>(); + request.getSimplifiedMeasures().forEach(measure -> measure.setName(StringUtils.trim(measure.getName()))); + checkMeasureNameValid(request); + checkMeasureNameDuplicate(request); + + for (SimplifiedMeasure measure : request.getSimplifiedMeasures()) { // check duplicate measure definitions SimplifiedMeasure dupMeasure = null; for (SimplifiedMeasure m : measures) { @@ -2207,7 +2219,6 @@ public class ModelService extends AbstractModelService implements TableModelSupp MsgPicker.getMsg().getDuplicateMeasureDefinition(), measure.getName())); } - measureNames.add(measure.getName()); measures.add(measure); } } @@ -2630,6 +2641,7 @@ public class ModelService extends AbstractModelService implements TableModelSupp checkCCNameAmbiguity(model); ComputedColumnDesc checkedCC = null; + QueryContext.AclInfo aclInfo = AclPermissionUtil.createAclInfo(project, getCurrentUserGroups()); Set<String> excludedTables = getManager(FavoriteRuleManager.class, project).getExcludedTables(); ExcludedLookupChecker checker = new ExcludedLookupChecker(excludedTables, model.getJoinTables(), model); for (ComputedColumnDesc cc : model.getComputedColumnDescs()) { @@ -2645,8 +2657,7 @@ public class ModelService extends AbstractModelService implements TableModelSupp MsgPicker.getMsg().getccOnAntiFlattenLookup(), antiFlattenLookup)); } ComputedColumnDesc.simpleParserCheck(cc.getExpression(), model.getAliasMap().keySet()); - String innerExpression = QueryUtil.massageComputedColumn(model, project, cc, - AclPermissionUtil.prepareQueryContextACLInfo(project, getCurrentUserGroups())); + String innerExpression = QueryUtil.massageComputedColumn(model, project, cc, aclInfo); cc.setInnerExpression(innerExpression); //check by data source, this could be slow @@ -2746,9 +2757,9 @@ public class ModelService extends AbstractModelService implements TableModelSupp checkCCNameAmbiguity(model); // Update CC expression from query transformers + QueryContext.AclInfo aclInfo = AclPermissionUtil.createAclInfo(project, getCurrentUserGroups()); for (ComputedColumnDesc ccDesc : model.getComputedColumnDescs()) { - String ccExpression = QueryUtil.massageComputedColumn(model, project, ccDesc, - AclPermissionUtil.prepareQueryContextACLInfo(project, getCurrentUserGroups())); + String ccExpression = QueryUtil.massageComputedColumn(model, project, ccDesc, aclInfo); ccDesc.setInnerExpression(ccExpression); TblColRef tblColRef = model.findColumn(ccDesc.getTableAlias(), ccDesc.getColumnName()); tblColRef.getColumnDesc().setComputedColumn(ccExpression); @@ -3599,7 +3610,7 @@ public class ModelService extends AbstractModelService implements TableModelSupp } String massagedFilterCond = QueryUtil.massageExpression(model, model.getProject(), model.getFilterCondition(), - AclPermissionUtil.prepareQueryContextACLInfo(model.getProject(), getCurrentUserGroups()), false); + AclPermissionUtil.createAclInfo(model.getProject(), getCurrentUserGroups()), false); String filterConditionWithTableName = addTableNameIfNotExist(massagedFilterCond, model); @@ -3853,7 +3864,7 @@ public class ModelService extends AbstractModelService implements TableModelSupp } public NDataModel updateResponseAcl(NDataModel model, String project) { - List<NDataModel> models = updateResponseAcl(Arrays.asList(model), project); + List<NDataModel> models = updateResponseAcl(Collections.singletonList(model), project); return models.get(0); } @@ -3905,8 +3916,6 @@ public class ModelService extends AbstractModelService implements TableModelSupp } } - private static final Set<String> StringTypes = Sets.newHashSet("STRING", "CHAR", "VARCHAR"); - private boolean matchCCDataType(String actual, String expected) { if (actual == null) { return false; @@ -3915,8 +3924,8 @@ public class ModelService extends AbstractModelService implements TableModelSupp actual = actual.toUpperCase(Locale.ROOT); expected = expected.toUpperCase(Locale.ROOT); // char, varchar, string are of the same - if (StringTypes.contains(actual)) { - return StringTypes.contains(expected); + if (STRING_TYPE_SET.contains(actual)) { + return STRING_TYPE_SET.contains(expected); } // if actual type is of decimal type with no prec, scala 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 e8edf45716..26a2cf1eaf 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 @@ -18,6 +18,7 @@ package org.apache.kylin.rest.service; +import static org.apache.kylin.common.exception.ServerErrorCode.FAILED_EXECUTE_MODEL_SQL; import static org.apache.kylin.common.exception.ServerErrorCode.INVALID_PARTITION_COLUMN; import static org.apache.kylin.common.exception.ServerErrorCode.PERMISSION_DENIED; import static org.apache.kylin.common.exception.code.ErrorCodeServer.COMPUTED_COLUMN_CONFLICT; @@ -289,7 +290,7 @@ public class ModelServiceTest extends SourceTestCase { ReflectionTestUtils.setField(semanticService, "expandableMeasureUtil", new ExpandableMeasureUtil((model, ccDesc) -> { String ccExpression = QueryUtil.massageComputedColumn(model, model.getProject(), ccDesc, - AclPermissionUtil.prepareQueryContextACLInfo(model.getProject(), + AclPermissionUtil.createAclInfo(model.getProject(), semanticService.getCurrentUserGroups())); ccDesc.setInnerExpression(ccExpression); ComputedColumnEvalUtil.evaluateExprAndType(model, ccDesc); @@ -4870,6 +4871,23 @@ public class ModelServiceTest extends SourceTestCase { Assert.assertNull(model.getMeasures().get(1).getComment()); } + @Test + public void testCheckFlatTableSql() { + String project = "default"; + String modelId = "a8ba3ff1-83bd-4066-ad54-d2fb3d1f0e94"; + NDataModel model = NDataModelManager.getInstance(getTestConfig(), project).getDataModelDesc(modelId); + modelService.checkFlatTableSql(model); + + getTestConfig().setProperty("kylin.env", "PROD"); + try { + modelService.checkFlatTableSql(model); + Assert.fail(); + } catch (KylinException e) { + Assert.assertEquals(FAILED_EXECUTE_MODEL_SQL.toErrorCode().getCodeString(), + e.getErrorCode().getCodeString()); + } + } + @Test public void testUpdateModelWithDirtyMeasures() { String project = "gc_test"; diff --git a/src/query-service/src/test/java/org/apache/kylin/rest/service/ModelServiceQueryTest.java b/src/query-service/src/test/java/org/apache/kylin/rest/service/ModelServiceQueryTest.java index c112280a1b..b28c4e96b6 100644 --- a/src/query-service/src/test/java/org/apache/kylin/rest/service/ModelServiceQueryTest.java +++ b/src/query-service/src/test/java/org/apache/kylin/rest/service/ModelServiceQueryTest.java @@ -115,7 +115,7 @@ public class ModelServiceQueryTest extends SourceTestCase { ReflectionTestUtils.setField(semanticService, "expandableMeasureUtil", new ExpandableMeasureUtil((model, ccDesc) -> { String ccExpression = QueryUtil.massageComputedColumn(model, model.getProject(), ccDesc, - AclPermissionUtil.prepareQueryContextACLInfo(model.getProject(), + AclPermissionUtil.createAclInfo(model.getProject(), semanticService.getCurrentUserGroups())); ccDesc.setInnerExpression(ccExpression); ComputedColumnEvalUtil.evaluateExprAndType(model, ccDesc); diff --git a/src/second-storage/core-ui/src/test/java/org/apache/kylin/rest/service/ModelServiceWithSecondStorageTest.java b/src/second-storage/core-ui/src/test/java/org/apache/kylin/rest/service/ModelServiceWithSecondStorageTest.java index 3df761f6c2..787b16f4c6 100644 --- a/src/second-storage/core-ui/src/test/java/org/apache/kylin/rest/service/ModelServiceWithSecondStorageTest.java +++ b/src/second-storage/core-ui/src/test/java/org/apache/kylin/rest/service/ModelServiceWithSecondStorageTest.java @@ -142,7 +142,7 @@ public class ModelServiceWithSecondStorageTest extends NLocalFileMetadataTestCas ReflectionTestUtils.setField(semanticService, "expandableMeasureUtil", new ExpandableMeasureUtil((model, ccDesc) -> { String ccExpression = QueryUtil.massageComputedColumn(model, model.getProject(), ccDesc, - AclPermissionUtil.prepareQueryContextACLInfo(model.getProject(), + AclPermissionUtil.createAclInfo(model.getProject(), semanticService.getCurrentUserGroups())); ccDesc.setInnerExpression(ccExpression); ComputedColumnEvalUtil.evaluateExprAndType(model, ccDesc); diff --git a/src/systools/src/main/java/org/apache/kylin/rest/util/AclPermissionUtil.java b/src/systools/src/main/java/org/apache/kylin/rest/util/AclPermissionUtil.java index 36b5b3723a..6a70456aba 100644 --- a/src/systools/src/main/java/org/apache/kylin/rest/util/AclPermissionUtil.java +++ b/src/systools/src/main/java/org/apache/kylin/rest/util/AclPermissionUtil.java @@ -33,6 +33,7 @@ import org.apache.kylin.common.QueryContext; import org.apache.kylin.common.exception.KylinException; import org.apache.kylin.common.msg.MsgPicker; import org.apache.kylin.common.persistence.AclEntity; +import org.apache.kylin.metadata.project.NProjectManager; import org.apache.kylin.metadata.project.ProjectInstance; import org.apache.kylin.rest.constant.Constant; import org.apache.kylin.rest.security.AclEntityFactory; @@ -43,7 +44,6 @@ import org.apache.kylin.rest.security.AclPermissionFactory; import org.apache.kylin.rest.security.CompositeAclPermission; import org.apache.kylin.rest.security.MutableAclRecord; import org.apache.kylin.rest.security.ObjectIdentityImpl; -import org.apache.kylin.metadata.project.NProjectManager; import org.springframework.security.acls.domain.BasePermission; import org.springframework.security.acls.domain.GrantedAuthoritySid; import org.springframework.security.acls.domain.PrincipalSid; @@ -231,7 +231,7 @@ public class AclPermissionUtil { } } - public static QueryContext.AclInfo prepareQueryContextACLInfo(String project, Set<String> groups) { + public static QueryContext.AclInfo createAclInfo(String project, Set<String> groups) { return new QueryContext.AclInfo(getCurrentUsername(), groups, isAdminInProject(project, groups)); }