This is an automated email from the ASF dual-hosted git repository. pfzhan pushed a commit to branch kylin5 in repository https://gitbox.apache.org/repos/asf/kylin.git
The following commit(s) were added to refs/heads/kylin5 by this push: new 9db7d8de0a KYLIN-6031 Add OpenAPI to show internalTable info (#2280) 9db7d8de0a is described below commit 9db7d8de0a6743077fcb1bb11d75e081b89e8c34 Author: Guoliang Sun <guoliang....@kyligence.io> AuthorDate: Tue Feb 25 14:36:38 2025 +0800 KYLIN-6031 Add OpenAPI to show internalTable info (#2280) Co-authored-by: Yan Xin <206577...@qq.com> --- .../org/apache/kylin/common/msg/CnMessage.java | 30 ++++ .../java/org/apache/kylin/common/msg/Message.java | 24 +++ .../rest/service/InternalTableServiceTest.java | 162 ++++++++++++++++++--- .../job/service/InternalTableLoadingService.java | 4 +- .../rest/response/InternalTableDescResponse.java | 32 ++++ .../kylin/rest/service/InternalTableService.java | 55 +++---- .../apache/kylin/query/QueryGroupingSetsTest.java | 3 + .../rest/controller/InternalTableController.java | 43 ++++-- .../open/OpenInternalTableController.java | 26 ++-- 9 files changed, 303 insertions(+), 76 deletions(-) diff --git a/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java b/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java index 0da315c13d..4616c3e352 100644 --- a/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java +++ b/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java @@ -940,6 +940,36 @@ public class CnMessage extends Message { return "无法找到内表 \"%s\"。 请检查后重试。"; } + @Override + public String getInternalTableEmpty() { + return "无法更新非空内表 \"%s\"。 请检查后重试。"; + } + + @Override + public String getSameInternalTableNameExist() { + return "表:\"%s\" 已经存在,请检查后重试。"; + } + + @Override + public String getInternalTablePath() { + return "创建内表路径失败,请检查后重试。"; + } + + @Override + public String getInternalTableUnpartitioned() { + return "不支持增量构建为分区内表,请检查后重试。"; + } + + @Override + public String getInternalTableNullPartitionFormat() { + return "日期分区格式不能为空, 请检查后重试。"; + } + + @Override + public String getInternalTableNoDataCol() { + return "在分区列中无法找到日期列,请检查后重试。"; + } + @Override public String getTimeExceedPartitionRange() { return "刷新时间超出已加载范围 :\"%s\" ~ \"%s\",请检查后重试。 "; diff --git a/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java b/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java index 230cffe1d3..7091589691 100644 --- a/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java +++ b/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java @@ -446,6 +446,30 @@ public class Message { return "Can’t find internal table \"%s\". Please check and try again."; } + public String getInternalTableEmpty() { + return "Can't update non empty internal table \"%s\", Please check and try again."; + } + + public String getSameInternalTableNameExist() { + return "Internal table %s already exists, please choose a different name."; + } + + public String getInternalTablePath() { + return "Failed to create internal table location."; + } + + public String getInternalTableUnpartitioned() { + return "Incremental build is not supported for unPartitioned table."; + } + + public String getInternalTableNullPartitionFormat() { + return "date_partition_format can not be null, please check again."; + } + + public String getInternalTableNoDataCol() { + return "couldn't find date_col present in partition_cols, please check again. "; + } + public String getTimeExceedPartitionRange() { return "Refresh time exceed loaded range :\"%s\" ~ \"%s\", Please check and try again. "; } diff --git a/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java b/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java index 4d3f5db4da..c81b251c93 100644 --- a/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java +++ b/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java @@ -51,7 +51,9 @@ import org.apache.kylin.engine.spark.utils.SparkJobFactoryUtils; import org.apache.kylin.job.execution.ExecutableManager; import org.apache.kylin.job.execution.ExecutableState; import org.apache.kylin.job.service.InternalTableLoadingService; +import org.apache.kylin.job.util.JobContextUtil; import org.apache.kylin.junit.annotation.MetadataInfo; +import org.apache.kylin.metadata.model.ColumnDesc; import org.apache.kylin.metadata.model.NTableMetadataManager; import org.apache.kylin.metadata.model.TableDesc; import org.apache.kylin.metadata.table.InternalTableDesc; @@ -111,6 +113,7 @@ public class InternalTableServiceTest extends AbstractTestCase { @BeforeEach void setUp() throws Exception { + JobContextUtil.cleanUp(); MockitoAnnotations.openMocks(this); SecurityContextHolder.getContext() .setAuthentication(new TestingAuthenticationToken("ADMIN", "ADMIN", Constant.ROLE_ADMIN)); @@ -279,7 +282,7 @@ public class InternalTableServiceTest extends AbstractTestCase { partitionCols, dateFormat, tblProperties, InternalTableDesc.StorageType.PARQUET.name()); // check internal table metadata - List<InternalTableDescResponse> internalTables = internalTableService.getTableList(PROJECT); + List<InternalTableDescResponse> internalTables = internalTableService.getTableList(PROJECT, false, false, ""); Assertions.assertEquals(1, internalTables.size()); InternalTableDescResponse response = internalTables.get(0); Assertions.assertEquals(DATE_COL, response.getTimePartitionCol()); @@ -577,7 +580,7 @@ public class InternalTableServiceTest extends AbstractTestCase { internalTableService.createInternalTable(PROJECT, table.getName(), table.getDatabase(), null, null, new HashMap<>(), InternalTableDesc.StorageType.PARQUET.name()); - List<InternalTableDescResponse> tables = internalTableService.getTableList(PROJECT); + List<InternalTableDescResponse> tables = internalTableService.getTableList(PROJECT, false, false, ""); Assertions.assertEquals(1, tables.size()); Assertions.assertNull(tables.get(0).getTimePartitionCol()); @@ -587,7 +590,7 @@ public class InternalTableServiceTest extends AbstractTestCase { internalTableService.updateInternalTable(PROJECT, tables.get(0).getTableName(), tables.get(0).getDatabaseName(), new String[] { DATE_COL }, "yyyy-MM-dd", new HashMap<>(), InternalTableDesc.StorageType.PARQUET.name()); - tables = internalTableService.getTableList(PROJECT); + tables = internalTableService.getTableList(PROJECT, false, false, ""); Assertions.assertEquals(1, tables.size()); Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol()); @@ -669,10 +672,9 @@ public class InternalTableServiceTest extends AbstractTestCase { TransactionException exception = Assertions.assertThrows(TransactionException.class, () -> internalTableService.createInternalTable(PROJECT, table.getName(), table.getDatabase(), partitionCols, "yyyy-MM-dd", tblProperties, InternalTableDesc.StorageType.PARQUET.name())); - - Assertions.assertEquals("KE-010007011(Internal Table Operation Failed) \n" - + "org.apache.kylin.common.exception.KylinException: KE-010007011(Internal Table Operation Failed):Table is already an internal table", - exception.getCause().toString()); + Assertions.assertEquals(String.format(Locale.ROOT, MsgPicker.getMsg().getSameInternalTableNameExist(), + table.getName()), + exception.getCause().getMessage()); if (!internalTableFolder.delete()) { Assertions.fail(); } @@ -712,25 +714,23 @@ public class InternalTableServiceTest extends AbstractTestCase { () -> internalTableService.updateInternalTable(PROJECT, tableName, db, partitionCols, dateFormat, tblProperties, InternalTableDesc.StorageType.PARQUET.name())); - Assertions.assertEquals("KE-010007011(Internal Table Operation Failed) \n" - + "org.apache.kylin.common.exception.KylinException: KE-010007011(Internal Table Operation Failed):Non-empty internal table can not be updated", - exception.getCause().toString()); + Assertions.assertEquals(String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTableEmpty(), + table.getDatabase() + "." + table.getName()), exception.getCause().getMessage()); } @Test void testCreateInternalPathFailedErrorCode() throws Exception { when(tableService.getPartitionColumnFormat(any(), any(), any(), any())).thenReturn("yyyy-MM-dd"); - FileSystem mockFileSystem = Mockito.mock(FileSystem.class); + FileSystem mockFileSystem = mock(FileSystem.class); try (MockedStatic<HadoopUtil> mockedHadoopUtil = Mockito.mockStatic(HadoopUtil.class)) { mockedHadoopUtil.when(HadoopUtil::getWorkingFileSystem).thenReturn(mockFileSystem); - Mockito.doThrow(new IOException("Simulated IO error")).when(mockFileSystem).mkdirs(Mockito.any(Path.class)); + doThrow(new IOException("Simulated IO error")).when(mockFileSystem).mkdirs(any(Path.class)); KylinException exception = Assertions.assertThrows(KylinException.class, () -> { String path = "mocked/path/to/internal_table"; internalTableService.createInternalTablePath(path); }); - Assertions.assertEquals("KE-010007011(Internal Table Operation Failed) \n" - + "org.apache.kylin.common.exception.KylinException: KE-010007011(Internal Table Operation Failed):Failed to create internal table location", - exception.toString()); + Assertions.assertEquals(String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTablePath()), + exception.getMessage()); } } @@ -745,9 +745,8 @@ public class InternalTableServiceTest extends AbstractTestCase { TransactionException exception = Assertions.assertThrows(TransactionException.class, () -> internalTableService.loadIntoInternalTable(PROJECT, table.getName(), table.getDatabase(), true, false, startDate, endDate, null)); - Assertions.assertEquals("KE-010007011(Internal Table Operation Failed) \n" - + "org.apache.kylin.common.exception.KylinException: KE-010007011(Internal Table Operation Failed):Incremental build is not supported for unPartitioned table", - exception.getCause().toString()); + Assertions.assertEquals(String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTableUnpartitioned()), + exception.getCause().getMessage()); } @Test @@ -758,9 +757,9 @@ public class InternalTableServiceTest extends AbstractTestCase { when(tableService.getPartitionColumnFormat(any(), any(), any(), any())).thenReturn("yyyy-MM-dd"); KylinException exception = Assertions.assertThrows(KylinException.class, () -> internalTableService.checkParameters(null, table, "yyyy-MM-dd")); - Assertions.assertEquals("KE-010007013(Internal Table Parameter Invalid) \n" - + "org.apache.kylin.common.exception.KylinException: KE-010007013(Internal Table Parameter Invalid):Can’t find the partition column. Please check and try again.", - exception.toString()); + Assertions.assertEquals( + String.format(Locale.ROOT, MsgPicker.getMsg().getPartitionColumnNotExist(), table.getIdentity()), + exception.getMessage()); } @Test @@ -771,8 +770,123 @@ public class InternalTableServiceTest extends AbstractTestCase { when(tableService.getPartitionColumnFormat(any(), any(), any(), any())).thenReturn("yyyy-MM-dd"); KylinException exception = Assertions.assertThrows(KylinException.class, () -> internalTableService.checkParameters(new String[] { "TRANS_ID", "CAL_DT" }, table, "yyyy-MM")); - Assertions.assertEquals("KE-010007013(Internal Table Parameter Invalid) \n" - + "org.apache.kylin.common.exception.KylinException: KE-010007013(Internal Table Parameter Invalid):Date partition format \"yyyy-MM\" is not correct.", - exception.toString()); + Assertions.assertEquals(String.format(Locale.ROOT, MsgPicker.getMsg().getIncorrectDateformat(), "yyyy-MM"), + exception.getMessage()); + } + + @Test + void testInternalTableShowDetailsFuzzy() throws Exception { + KylinConfig config = KylinConfig.getInstanceFromEnv(); + NTableMetadataManager tManager = NTableMetadataManager.getInstance(config, PROJECT); + InternalTableManager internalTableManager = InternalTableManager.getInstance(config, PROJECT); + TableDesc table = tManager.getTableDesc(TABLE_INDENTITY); + String[] partitionCols = new String[] { DATE_COL }; + Map<String, String> tblProperties = new HashMap<>(); + String tableIdentity = table.getDatabase() + "." + table.getName(); + boolean isFuzzy = true; + boolean needDetails = true; + when(tableService.getPartitionColumnFormat(any(), any(), any(), any())).thenReturn("yyyy-MM-dd"); + + internalTableService.createInternalTable(PROJECT, table.getName(), table.getDatabase(), partitionCols, + "yyyy-MM-dd", tblProperties, InternalTableDesc.StorageType.PARQUET.name()); + InternalTableDesc internalTable = internalTableManager.getInternalTableDesc(TABLE_INDENTITY); + Assertions.assertNotNull(internalTable); + String workingDir = config.getHdfsWorkingDirectory().replace("file://", ""); + File internalTableFolder = new File(workingDir, INTERNAL_DIR); + Assertions.assertTrue(internalTableFolder.exists() && internalTableFolder.isDirectory()); + + List<InternalTableDescResponse> tables = internalTableService.getTableList(PROJECT, isFuzzy, needDetails, + tableIdentity); + Assertions.assertEquals(tables.get(0).getTableName(), table.getName()); + Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol()); + List<ColumnDesc> tableColumn = tables.get(0).getColumns(); + ColumnDesc[] columns = internalTable.getColumns(); + Assertions.assertEquals(tableColumn.size(), columns.length); + for (int i = 0; i < columns.length; i++) { + ColumnDesc columninfo = tableColumn.get(i); + Assertions.assertEquals(columns[i].getName(), columninfo.getName()); + Assertions.assertEquals(columns[i].getId(), columninfo.getId()); + Assertions.assertEquals(columns[i].getDatatype(), columninfo.getDatatype()); + } + + tableIdentity = "E.S"; + tables.clear(); + tables = internalTableService.getTableList(PROJECT, isFuzzy, needDetails, tableIdentity); + Assertions.assertEquals(tables.get(0).getTableName(), table.getName()); + Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol()); + tableColumn = tables.get(0).getColumns(); + Assertions.assertEquals(tableColumn.size(), columns.length); + + tableIdentity = "DEFAULT2.DUMMY"; + KylinException notExistException = null; + tables.clear(); + try { + tables = internalTableService.getTableList(PROJECT, isFuzzy, needDetails, tableIdentity); + } catch (KylinException e) { + notExistException = e; + } + Assertions.assertTrue(tables.isEmpty()); + Assertions.assertTrue( + null != notExistException && notExistException.getErrorCode().getCodeString().equals("KE-010007014")); + + //Illegal string + tableIdentity = "DEFAULT.1"; + notExistException = null; + try { + tables = internalTableService.getTableList(PROJECT, isFuzzy, needDetails, tableIdentity); + } catch (KylinException e) { + notExistException = e; + } + Assertions.assertTrue(tables.isEmpty()); + Assertions.assertTrue( + null != notExistException && notExistException.getErrorCode().getCodeString().equals("KE-010007014")); + } + + @Test + void testInternalTableShowDetails() throws Exception { + KylinConfig config = KylinConfig.getInstanceFromEnv(); + NTableMetadataManager tManager = NTableMetadataManager.getInstance(config, PROJECT); + InternalTableManager internalTableManager = InternalTableManager.getInstance(config, PROJECT); + TableDesc table = tManager.getTableDesc(TABLE_INDENTITY); + String[] partitionCols = new String[] { DATE_COL }; + Map<String, String> tblProperties = new HashMap<>(); + String tableIdentity = table.getDatabase() + "." + table.getName(); + boolean isFuzzy = false; + boolean needDetails = true; + when(tableService.getPartitionColumnFormat(any(), any(), any(), any())).thenReturn("yyyy-MM-dd"); + + internalTableService.createInternalTable(PROJECT, table.getName(), table.getDatabase(), partitionCols, + "yyyy-MM-dd", tblProperties, InternalTableDesc.StorageType.PARQUET.name()); + InternalTableDesc internalTable = internalTableManager.getInternalTableDesc(TABLE_INDENTITY); + Assertions.assertNotNull(internalTable); + String workingDir = config.getHdfsWorkingDirectory().replace("file://", ""); + File internalTableFolder = new File(workingDir, INTERNAL_DIR); + Assertions.assertTrue(internalTableFolder.exists() && internalTableFolder.isDirectory()); + + List<InternalTableDescResponse> tables = internalTableService.getTableList(PROJECT, isFuzzy, needDetails, + tableIdentity); + Assertions.assertEquals(tables.get(0).getTableName(), table.getName()); + Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol()); + List<ColumnDesc> tableColumn = tables.get(0).getColumns(); + ColumnDesc[] columns = internalTable.getColumns(); + Assertions.assertEquals(tableColumn.size(), columns.length); + for (int i = 0; i < columns.length; i++) { + ColumnDesc columninfo = tableColumn.get(i); + Assertions.assertEquals(columns[i].getName(), columninfo.getName()); + Assertions.assertEquals(columns[i].getId(), columninfo.getId()); + Assertions.assertEquals(columns[i].getDatatype(), columninfo.getDatatype()); + } + + tableIdentity = "DEFAULT.T"; + KylinException notExistException = null; + tables.clear(); + try { + tables = internalTableService.getTableList(PROJECT, isFuzzy, needDetails, tableIdentity); + } catch (KylinException e) { + notExistException = e; + } + Assertions.assertTrue(tables.isEmpty()); + Assertions.assertTrue( + null != notExistException && notExistException.getErrorCode().getCodeString().equals("KE-010007014")); } } diff --git a/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java b/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java index 354d186fdd..8d10c4b3a6 100644 --- a/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java +++ b/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java @@ -77,8 +77,8 @@ public class InternalTableLoadingService extends BasicService { if (isIncremental && (Objects.isNull(internalTable.getTablePartition()) || Objects.isNull(internalTable.getTablePartition().getPartitionColumns()) || internalTable.getTablePartition().getPartitionColumns().length == 0)) { - throw new KylinException(INTERNAL_TABLE_ERROR, - "Incremental build is not supported for unPartitioned table"); + String errorMsg = String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTableUnpartitioned()); + throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg); } // check refresh time exceed loaded range InternalTablePartition tablePartition = internalTable.getTablePartition(); diff --git a/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java b/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java index b4e9c4fe8b..e26bcab665 100644 --- a/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java +++ b/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java @@ -18,8 +18,14 @@ package org.apache.kylin.rest.response; +import java.util.Arrays; +import java.util.List; import java.util.Map; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.kylin.metadata.model.ColumnDesc; +import org.apache.kylin.metadata.table.InternalTableDesc; + import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @@ -57,4 +63,30 @@ public class InternalTableDescResponse { @JsonProperty("tbl_properties") private Map<String, String> tblProperties; + @JsonProperty("columns_info") + private List<ColumnDesc> columns; + + public static InternalTableDescResponse convertToResponse(InternalTableDesc internalTableDesc, + boolean needDetails) { + InternalTableDescResponse response = new InternalTableDescResponse(); + response.setTableName(internalTableDesc.getName()); + response.setUuid(internalTableDesc.getUuid()); + response.setDatabaseName(internalTableDesc.getDatabase()); + response.setRowCount(internalTableDesc.getRowCount()); + response.setStorageSize(internalTableDesc.getStorageSize()); + response.setHitCount(internalTableDesc.getHitCount()); + + String[] partitionColumns = internalTableDesc.getPartitionColumns(); + String partitionColumn = ArrayUtils.isNotEmpty(partitionColumns) ? partitionColumns[0] : null; + response.setTimePartitionCol(partitionColumn); + + response.setUpdateTime(internalTableDesc.getLastModified()); + response.setDatePartitionFormat(internalTableDesc.getDatePartitionFormat()); + response.setTblProperties(internalTableDesc.getTblProperties()); + + if (needDetails) { + response.setColumns(Arrays.asList(internalTableDesc.getColumns())); + } + return response; + } } diff --git a/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java b/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java index ea81cc175d..cc6913b8c3 100644 --- a/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java +++ b/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java @@ -116,7 +116,9 @@ public class InternalTableService extends BasicService { throw new KylinException(TABLE_NOT_EXIST, errorMsg); } if (originTable.isHasInternal()) { - throw new KylinException(INTERNAL_TABLE_ERROR, "Table is already an internal table"); + String errorMsg = String.format(Locale.ROOT, MsgPicker.getMsg().getSameInternalTableNameExist(), + originTable.getName()); + throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg); } checkParameters(partitionCols, originTable, datePartitionFormat); InternalTableDesc internalTable = new InternalTableDesc(originTable); @@ -155,11 +157,11 @@ public class InternalTableService extends BasicService { Optional<ColumnDesc> dateCol = partitionColList.stream().filter(col -> col.getTypeName().equals("date")) .findFirst(); if (StringUtils.isEmpty(datePartitionFormat) && dateCol.isPresent()) { - throw new KylinException(EMPTY_PARAMETER, "date_partition_format can not be null, please check again"); + throw new KylinException(EMPTY_PARAMETER, + String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTableNullPartitionFormat())); } if (!StringUtils.isEmpty(datePartitionFormat) && !dateCol.isPresent()) { - throw new KylinException(EMPTY_PARAMETER, - "couldn't find date_col present in partition_cols, please check again"); + throw new KylinException(EMPTY_PARAMETER, MsgPicker.getMsg().getInternalTableNoDataCol()); } checkIfFormatMatchCol(dateCol, originTable, datePartitionFormat); } @@ -229,7 +231,8 @@ public class InternalTableService extends BasicService { throw new KylinException(INTERNAL_TABLE_NOT_EXIST, errorMsg); } if (internalTable.getRowCount() > 0L) { - throw new KylinException(INTERNAL_TABLE_ERROR, "Non-empty internal table can not be updated"); + String errorMsg = String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTableEmpty(), dbTblName); + throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg); } checkParameters(partitionCols, originTable, datePartitionFormat); if (partitionCols != null && partitionCols.length != 0) { @@ -255,7 +258,8 @@ public class InternalTableService extends BasicService { Path location = new Path(path); fs.mkdirs(location); } catch (IOException e) { - throw new KylinException(INTERNAL_TABLE_ERROR, "Failed to create internal table location", e); + String errorMsg = String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTablePath()); + throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg); } } @@ -397,28 +401,27 @@ public class InternalTableService extends BasicService { startDate, endDate, yarnQueue); } - public List<InternalTableDescResponse> getTableList(String project) { + public List<InternalTableDescResponse> getTableList(String project, boolean isFuzzy, boolean needDetails, + String fuzzyKey) { InternalTableManager internalTableManager = getManager(InternalTableManager.class, project); List<InternalTableDesc> tableList = internalTableManager.listAllTables(); - List<InternalTableDescResponse> descList = Lists.newArrayList(); - tableList.forEach(internalTableDesc -> { - InternalTableDescResponse internalTableDescResponse = new InternalTableDescResponse(); - internalTableDescResponse.setTableName(internalTableDesc.getName()); - internalTableDescResponse.setUuid(internalTableDesc.getUuid()); - internalTableDescResponse.setDatabaseName(internalTableDesc.getDatabase()); - internalTableDescResponse.setRowCount(internalTableDesc.getRowCount()); - internalTableDescResponse.setStorageSize(internalTableDesc.getStorageSize()); - internalTableDescResponse.setHitCount(internalTableDesc.getHitCount()); - String[] partitionColumns = internalTableDesc.getPartitionColumns(); - String partitionColumn = (partitionColumns == null || partitionColumns.length == 0) ? null - : internalTableDesc.getPartitionColumns()[0]; - internalTableDescResponse.setTimePartitionCol(partitionColumn); - internalTableDescResponse.setUpdateTime(internalTableDesc.getLastModified()); - internalTableDescResponse.setDatePartitionFormat(internalTableDesc.getDatePartitionFormat()); - internalTableDescResponse.setTblProperties(internalTableDesc.getTblProperties()); - descList.add(internalTableDescResponse); - }); - return descList; + if (StringUtils.isNotBlank(fuzzyKey)) { + if (isFuzzy) { + String regex = fuzzyKey.replace(".", ".*"); + tableList = tableList.stream().filter(table -> table.getIdentity().matches("(?i).*" + regex + ".*")) + .collect(Collectors.toList()); + } else { + tableList = tableList.stream() + .filter(table -> StringUtils.equalsIgnoreCase(table.getIdentity(), fuzzyKey)) + .collect(Collectors.toList()); + } + if (tableList.isEmpty()) { + throw new KylinException(INTERNAL_TABLE_NOT_EXIST, + String.format(Locale.ROOT, MsgPicker.getMsg().getInternalTableNotFound(), fuzzyKey)); + } + } + return tableList.stream().map(table -> InternalTableDescResponse.convertToResponse(table, needDetails)) + .collect(Collectors.toList()); } public List<InternalTablePartitionDetail> getTableDetail(String project, String databaseName, String tableName) { diff --git a/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java b/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java index 402c4165fe..02c5dbdd2f 100644 --- a/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java +++ b/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Objects; import org.apache.calcite.rel.RelNode; import org.apache.kylin.common.KylinConfig; @@ -112,6 +113,8 @@ public class QueryGroupingSetsTest extends SemiAutoTestBase { @After public void teardown() throws Exception { queryHistoryDAO.deleteAllQueryHistory(); + ReflectionTestUtils.invokeMethod( + Objects.requireNonNull(ReflectionTestUtils.getField(queryService, "slowQueryDetector")), "interrupt"); super.tearDown(); QueryHistoryAccelerateScheduler.shutdown(); } diff --git a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java index 6f9bbd25e0..d514bfc6e9 100644 --- a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java +++ b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java @@ -67,8 +67,8 @@ public class InternalTableController extends NBasicController { public EnvelopeResponse<String> createInternalTable(@RequestParam(value = "project") String project, @PathVariable(value = "database") String database, // @PathVariable(value = "table") String table, @RequestBody InternalTableRequest request) throws Exception { - checkProjectName(project); - if (StringUtils.isEmpty(table) || StringUtils.isEmpty(database)) { + project = checkProjectName(project); + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(EMPTY_PARAMETER, "Table or database can not be null, please check again."); } internalTableService.createInternalTable(project, table, database, request.getPartitionCols(), @@ -82,7 +82,7 @@ public class InternalTableController extends NBasicController { public EnvelopeResponse<String> dropInternalTable(@RequestParam(value = "project") String project, @PathVariable(value = "database") String database, // @PathVariable(value = "table") String table) throws Exception { - checkProjectName(project); + project = checkProjectName(project); String dbTblName = database + "." + table; internalTableService.dropInternalTable(project, dbTblName); return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, "", ""); @@ -94,8 +94,8 @@ public class InternalTableController extends NBasicController { public EnvelopeResponse<String> truncateInternalTable(@RequestParam(value = "project") String project, @RequestParam(value = "database") String database, @RequestParam(value = "table") String table) throws Exception { - checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + project = checkProjectName(project); + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(INVALID_TABLE_NAME, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } String tableIdentity = database + "." + table; @@ -109,8 +109,8 @@ public class InternalTableController extends NBasicController { public EnvelopeResponse<String> dropPartitions(@RequestParam(value = "project") String project, @RequestParam(value = "database") String database, @RequestParam(value = "table") String table, @RequestParam(value = "partitions") String[] partitionValues) throws Exception { - checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + project = checkProjectName(project); + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(INVALID_TABLE_NAME, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } // If partitionValues is null, all files will be cleared @@ -127,8 +127,8 @@ public class InternalTableController extends NBasicController { @PathVariable(value = "project") String project, @PathVariable(value = "database") String database, // @PathVariable(value = "table") String table, @RequestBody InternalTableBuildRequest request) throws Exception { - checkProjectName(project); - if (StringUtils.isEmpty(table) || StringUtils.isEmpty(database)) { + project = checkProjectName(project); + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(INVALID_TABLE_NAME, MsgPicker.getMsg().getTableNameCannotEmpty()); } InternalTableLoadingJobResponse response = internalTableService.loadIntoInternalTable(project, table, database, @@ -143,8 +143,8 @@ public class InternalTableController extends NBasicController { public EnvelopeResponse<String> updateTable(@RequestParam(value = "project") String project, @PathVariable(value = "database") String database, // @PathVariable(value = "table") String table, @RequestBody InternalTableRequest request) throws Exception { - checkProjectName(project); - if (StringUtils.isEmpty(table) || StringUtils.isEmpty(database)) { + project = checkProjectName(project); + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(EMPTY_PARAMETER, "Table or database can not be null, please check again."); } if (table.isEmpty()) { @@ -160,10 +160,24 @@ public class InternalTableController extends NBasicController { @ResponseBody public EnvelopeResponse<DataResult<List<InternalTableDescResponse>>> getTableList( @RequestParam(value = "project") String project, + @RequestParam(value = "need_details", required = false, defaultValue = "false") boolean needDetails, + @RequestParam(value = "is_fuzzy", required = false, defaultValue = "false") boolean isFuzzy, + @RequestParam(value = "database", required = false) String database, + @RequestParam(value = "table", required = false) String table, @RequestParam(value = "page_offset", required = false, defaultValue = "0") Integer offset, @RequestParam(value = "page_size", required = false, defaultValue = "10") Integer limit) { - checkProjectName(project); - val rep = internalTableService.getTableList(project); + project = checkProjectName(project); + + String fuzzyKey = ""; + if (StringUtils.isNotBlank(database) && StringUtils.isNotBlank(table)) { + fuzzyKey = StringUtils.trim(database) + "." + StringUtils.trim(table); + } else if (StringUtils.isBlank(database)) { + fuzzyKey = StringUtils.trim(table); + } else if (StringUtils.isBlank(table)) { + fuzzyKey = StringUtils.trim(database); + } + + val rep = internalTableService.getTableList(project, isFuzzy, needDetails, fuzzyKey); return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, DataResult.get(rep, offset, limit), ""); } @@ -175,8 +189,9 @@ public class InternalTableController extends NBasicController { @PathVariable(value = "table") String table, @RequestParam(value = "page_offset", required = false, defaultValue = "0") Integer offset, @RequestParam(value = "page_size", required = false, defaultValue = "10") Integer limit) { - checkProjectName(project); + project = checkProjectName(project); val rep = internalTableService.getTableDetail(project, database, table); return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, DataResult.get(rep, offset, limit), ""); } + } diff --git a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java index 20c0927381..c54d7ed853 100644 --- a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java +++ b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java @@ -67,7 +67,7 @@ public class OpenInternalTableController extends NBasicController { @PathVariable(value = "database") String database, // @PathVariable(value = "table") String table, @RequestBody InternalTableRequest request) throws Exception { String projectName = checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(EMPTY_PARAMETER, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } return internalTableController.createInternalTable(projectName, database, table, request); @@ -78,6 +78,10 @@ public class OpenInternalTableController extends NBasicController { @ResponseBody public EnvelopeResponse<DataResult<List<InternalTableDescResponse>>> getTableList( @RequestParam(value = "project") String project, + @RequestParam(value = "need_details", required = false, defaultValue = "false") boolean needDetails, + @RequestParam(value = "is_fuzzy", required = false, defaultValue = "false") boolean isFuzzy, + @RequestParam(value = "database", required = false) String database, + @RequestParam(value = "table", required = false) String table, @RequestParam(value = "page_offset", required = false, defaultValue = "0") Integer offset, @RequestParam(value = "page_size", required = false, defaultValue = "10") Integer limit) { String projectName = checkProjectName(project); @@ -85,10 +89,12 @@ public class OpenInternalTableController extends NBasicController { checkNonNegativeIntegerArg("page_offset", offset); } if (null != limit) { - checkNonNegativeIntegerArg("page_offset", limit); + checkNonNegativeIntegerArg("page_size", limit); + } + if (StringUtils.isBlank(table) && StringUtils.isBlank(database) && isFuzzy) { + throw new KylinException(EMPTY_PARAMETER, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } - checkNonNegativeIntegerArg("page_size", limit); - return internalTableController.getTableList(projectName, offset, limit); + return internalTableController.getTableList(projectName, isFuzzy, needDetails, database, table, offset, limit); } @ApiOperation(value = "get_table_detail", tags = { "AI" }) @@ -100,7 +106,7 @@ public class OpenInternalTableController extends NBasicController { @RequestParam(value = "page_offset", required = false, defaultValue = "0") Integer offset, @RequestParam(value = "page_size", required = false, defaultValue = "10") Integer limit) { String projectName = checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(EMPTY_PARAMETER, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } if (null != offset) { @@ -119,7 +125,7 @@ public class OpenInternalTableController extends NBasicController { @PathVariable(value = "database") String database, // @PathVariable(value = "table") String table, @RequestBody InternalTableRequest request) throws Exception { String projectName = checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(EMPTY_PARAMETER, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } return internalTableController.updateTable(projectName, database, table, request); @@ -133,7 +139,7 @@ public class OpenInternalTableController extends NBasicController { @PathVariable(value = "table") String table, @RequestBody InternalTableBuildRequest request) throws Exception { String projectName = checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(EMPTY_PARAMETER, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } return internalTableController.loadIntoInternalTable(projectName, database, table, request); @@ -146,7 +152,7 @@ public class OpenInternalTableController extends NBasicController { @RequestParam(value = "project") String project, @RequestParam(value = "database") String database, @RequestParam(value = "table") String table) throws Exception { String projectName = checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(INVALID_TABLE_NAME, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } return internalTableController.truncateInternalTable(projectName, database, table); @@ -160,7 +166,7 @@ public class OpenInternalTableController extends NBasicController { @RequestParam(value = "table") String table, @RequestParam(value = "partitions") String[] partitionValues) throws Exception { String projectName = checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(INVALID_TABLE_NAME, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } if (null == partitionValues || partitionValues.length == 0) { @@ -177,7 +183,7 @@ public class OpenInternalTableController extends NBasicController { @PathVariable(value = "database") String database, // @PathVariable(value = "table") String table) throws Exception { String projectName = checkProjectName(project); - if (StringUtils.isEmpty(StringUtils.trim(table)) || StringUtils.isEmpty(StringUtils.trim(database))) { + if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) { throw new KylinException(INVALID_TABLE_NAME, MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty()); } return internalTableController.dropInternalTable(projectName, database, table);