shaofengshi closed pull request #167: Kylin 3186 URL: https://github.com/apache/kylin/pull/167
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/core-common/src/main/java/org/apache/kylin/common/util/DateFormat.java b/core-common/src/main/java/org/apache/kylin/common/util/DateFormat.java index 29858f1a34..5035e03f6d 100644 --- a/core-common/src/main/java/org/apache/kylin/common/util/DateFormat.java +++ b/core-common/src/main/java/org/apache/kylin/common/util/DateFormat.java @@ -32,6 +32,11 @@ public static final String DEFAULT_TIME_PATTERN = "HH:mm:ss"; public static final String DEFAULT_DATETIME_PATTERN_WITHOUT_MILLISECONDS = "yyyy-MM-dd HH:mm:ss"; public static final String DEFAULT_DATETIME_PATTERN_WITH_MILLISECONDS = "yyyy-MM-dd HH:mm:ss.SSS"; + public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm"; + public static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH"; + public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + public static final String YYYYMMDDHHMM = "yyyyMMddHHmm"; + public static final String YYYYMMDDHH = "yyyyMMddHH"; public static final String[] SUPPORTED_DATETIME_PATTERN = { // DEFAULT_DATE_PATTERN, // DEFAULT_DATETIME_PATTERN_WITHOUT_MILLISECONDS, // @@ -48,7 +53,7 @@ public static FastDateFormat getDateFormat(String datePattern) { } return r; } - + public static String formatToCompactDateStr(long millis) { return formatToDateStr(millis, COMPACT_DATE_PATTERN); } @@ -94,13 +99,23 @@ public static Date stringToDate(String str, String pattern) { public static long stringToMillis(String str) { // try to be smart and guess the date format if (isAllDigits(str)) { - if (str.length() == 8) + if (str.length() == 8 && isInputFormatDate(str, COMPACT_DATE_PATTERN)) //TODO: might be prolematic if an actual ts happends to be 8 digits, e.g. 1970-01-01 10:00:01.123 return stringToDate(str, COMPACT_DATE_PATTERN).getTime(); + else if (str.length() == 10 && isInputFormatDate(str, YYYYMMDDHH)) + return stringToDate(str, YYYYMMDDHH).getTime(); + else if (str.length() == 12 && isInputFormatDate(str, YYYYMMDDHHMM)) + return stringToDate(str, YYYYMMDDHHMM).getTime(); + else if (str.length() == 14 && isInputFormatDate(str, YYYYMMDDHHMMSS)) + return stringToDate(str, YYYYMMDDHHMMSS).getTime(); else return Long.parseLong(str); } else if (str.length() == 10) { return stringToDate(str, DEFAULT_DATE_PATTERN).getTime(); + } else if (str.length() == 13) { + return stringToDate(str, YYYY_MM_DD_HH).getTime(); + } else if (str.length() == 16) { + return stringToDate(str, YYYY_MM_DD_HH_MM).getTime(); } else if (str.length() == 19) { return stringToDate(str, DEFAULT_DATETIME_PATTERN_WITHOUT_MILLISECONDS).getTime(); } else if (str.length() > 19) { @@ -137,7 +152,16 @@ public static boolean isSupportedDateFormat(String dateStr) { return false; } + public static boolean isInputFormatDate(String dateStr, String formatStr) { + try { + return dateStr.equals(dateToString(stringToDate(dateStr, formatStr), formatStr)); + } catch (Exception ex) { + return false; + } + } + public static boolean isDatePattern(String ptn) { - return COMPACT_DATE_PATTERN.equals(ptn) || DEFAULT_DATE_PATTERN.equals(ptn); + return COMPACT_DATE_PATTERN.equals(ptn) || YYYYMMDDHH.equals(ptn) || YYYYMMDDHHMM.equals(ptn) + || YYYYMMDDHHMMSS.equals(ptn); } } diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/model/PartitionDesc.java b/core-metadata/src/main/java/org/apache/kylin/metadata/model/PartitionDesc.java index 2f23bdc9ee..b3bf6cc682 100644 --- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/PartitionDesc.java +++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/PartitionDesc.java @@ -199,7 +199,7 @@ public String buildDateRangeCondition(PartitionDesc partDesc, ISegment seg, Segm StringBuilder builder = new StringBuilder(); if (partDesc.partitionColumnIsYmdInt()) { - buildSingleColumnRangeCondAsYmdInt(builder, partitionDateColumn, startInclusive, endExclusive); + buildSingleColumnRangeCondAsYmdInt(builder, partitionDateColumn, startInclusive, endExclusive, partDesc.getPartitionDateFormat()); } else if (partDesc.partitionColumnIsTimeMillis()) { buildSingleColumnRangeCondAsTimeMillis(builder, partitionDateColumn, startInclusive, endExclusive); } else if (partitionDateColumn != null && partitionTimeColumn == null) { @@ -225,13 +225,13 @@ private static void buildSingleColumnRangeCondAsTimeMillis(StringBuilder builder } private static void buildSingleColumnRangeCondAsYmdInt(StringBuilder builder, TblColRef partitionColumn, - long startInclusive, long endExclusive) { + long startInclusive, long endExclusive, String partitionColumnDateFormat) { String partitionColumnName = partitionColumn.getIdentity(); builder.append(partitionColumnName + " >= " - + DateFormat.formatToDateStr(startInclusive, DateFormat.COMPACT_DATE_PATTERN)); + + DateFormat.formatToDateStr(startInclusive, partitionColumnDateFormat)); builder.append(" AND "); builder.append(partitionColumnName + " < " - + DateFormat.formatToDateStr(endExclusive, DateFormat.COMPACT_DATE_PATTERN)); + + DateFormat.formatToDateStr(endExclusive, partitionColumnDateFormat)); } private static void buildSingleColumnRangeCondition(StringBuilder builder, TblColRef partitionColumn, diff --git a/webapp/app/js/controllers/modelConditionsSettings.js b/webapp/app/js/controllers/modelConditionsSettings.js index 82abe0bf39..500db409c4 100644 --- a/webapp/app/js/controllers/modelConditionsSettings.js +++ b/webapp/app/js/controllers/modelConditionsSettings.js @@ -25,6 +25,12 @@ KylinApp.controller('ModelConditionsSettingsCtrl', function ($scope, $modal,MetaModel,modelsManager,VdmUtil) { $scope.modelsManager = modelsManager; $scope.availableFactTables = []; + // partition date temporary object. + // Because ng-chosen cannot watch string value, partition date should be object. + // firstValue: For fixing ng-chosen cannot watch first value change. + $scope.partition_date = { type: '', format: '', firstValue: '' }; + $scope.partition_time = { type: '', format: '', firstValue: '' }; + $scope.initSetting = function (){ $scope.selectedTables={fact:VdmUtil.getNameSpaceAliasName($scope.modelsManager.selectedModel.partition_desc.partition_date_column)} $scope.selectedTablesForPartitionTime={fact:VdmUtil.getNameSpaceAliasName($scope.modelsManager.selectedModel.partition_desc.partition_time_column)} @@ -35,31 +41,94 @@ KylinApp.controller('ModelConditionsSettingsCtrl', function ($scope, $modal,Meta $scope.availableFactTables.push(joinTable[j].alias); } } + + $scope.initialPartitionSetting('Date'); + $scope.initialPartitionSetting('Time'); } $scope.isFormatEdit = {editable:false}; + + /** + * initial date or time partition select + * + * @param {String: 'Date' | 'Time'} partitionFieldName + * @desc cubeConfigName: 'partitionDateFormatOpt' or 'partitionTimeFormatOpt' + * modelFormatKey: 'partition_date_format' or 'partition_time_format' + * scopeName: 'partition_date' or 'partition_time' + */ + $scope.initialPartitionSetting = function(partitionFieldName) { + var cubeConfigName = 'partition' + partitionFieldName + 'FormatOpt'; + + var lowerCaseName = partitionFieldName.toLowerCase(), + modelFormatKey = 'partition_' + lowerCaseName + '_format', + scopeName = 'partition_' + lowerCaseName, + scopePartitionTypeWatchName = 'partition_' + lowerCaseName + '.type', + scopePartitionFormatWatchName = 'partition_' + lowerCaseName + '.format'; + + var partitionFormatOpt = $scope.cubeConfig[cubeConfigName]; + var partition_format = $scope.modelsManager.selectedModel.partition_desc[modelFormatKey]; + + if(partitionFormatOpt.indexOf(partition_format) === -1) { + $scope[scopeName].type = 'other'; + $scope[scopeName].format = partition_format; + $scope[scopeName].firstValue = partition_format; + } else { + $scope[scopeName].type = partition_format; + $scope[scopeName].format = ''; + $scope[scopeName].firstValue = partition_format; + } + + // Add form change watcher. SetTimeout can escape the first render loop. + setTimeout(function() { + $scope.$watch(scopePartitionTypeWatchName, function (newValue, oldValue) { + // Ng-chosen will change the value of all selects on DOM when you select each first. + // So for fixing this bug, we should compare the newValue and oldValue. + // firstValue: For fixing ng-chosen cannot watch first value change. + if(newValue !== oldValue || ($scope[scopeName].firstValue && $scope[scopeName].firstValue !== newValue && newValue !== 'other')) { + if(newValue !== 'other') { + $scope.modelsManager.selectedModel.partition_desc[modelFormatKey] = $scope[scopeName].format = newValue; + } else { + $scope[scopeName].format = ''; + } + $scope[scopeName].firstValue = ''; + } + }); + + $scope.$watch(scopePartitionFormatWatchName, function (newValue, oldValue) { + if(newValue !== oldValue) { + $scope.modelsManager.selectedModel.partition_desc[modelFormatKey] = newValue; + } + }); + }); + }; + var judgeFormatEditable = function(dateColumn){ if(dateColumn == null){ $scope.isFormatEdit.editable = false; return; } - var column = _.filter($scope.getColumnsByAlias(VdmUtil.getNameSpaceAliasName(dateColumn)),function(_column){ - var columnName=VdmUtil.getNameSpaceAliasName(dateColumn)+"."+_column.name; - if(dateColumn == columnName){ - return _column; - } - }); - var data_type = column[0].datatype; - if(data_type ==="bigint" ||data_type ==="int" ||data_type ==="integer"){ - $scope.isFormatEdit.editable = false; - $scope.modelsManager.selectedModel.partition_desc.partition_date_format='yyyyMMdd'; - $scope.partitionColumn.hasSeparateTimeColumn=false; - $scope.modelsManager.selectedModel.partition_desc.partition_time_column=null; - $scope.modelsManager.selectedModel.partition_desc.partition_time_format=null; + /** + * enable the partition format editable of all data type + * Edit date: 2018/07/12 + * Author: Roger + */ + // var column = _.filter($scope.getColumnsByAlias(VdmUtil.getNameSpaceAliasName(dateColumn)),function(_column){ + // var columnName=VdmUtil.getNameSpaceAliasName(dateColumn)+"."+_column.name; + // if(dateColumn == columnName){ + // return _column; + // } + // }); + // var data_type = column[0].datatype; + // if(data_type ==="bigint" ||data_type ==="int" ||data_type ==="integer"){ + // $scope.isFormatEdit.editable = false; + // $scope.modelsManager.selectedModel.partition_desc.partition_date_format='yyyyMMdd'; + // $scope.partitionColumn.hasSeparateTimeColumn=false; + // $scope.modelsManager.selectedModel.partition_desc.partition_time_column=null; + // $scope.modelsManager.selectedModel.partition_desc.partition_time_format=null; - return; - } + // return; + // } $scope.isFormatEdit.editable = true; return; @@ -96,6 +165,20 @@ KylinApp.controller('ModelConditionsSettingsCtrl', function ($scope, $modal,Meta "hasSeparateTimeColumn" : false } + $scope.addFormValueWatcher = function() { + $scope.$watch('partition_date.type', function (newValue) { + if(newValue !== 'other') { + $scope.modelsManager.selectedModel.partition_desc.partition_date_format = $scope.partition_date.format = newValue; + } else { + $scope.partition_date.format = ''; + } + }); + + $scope.$watch('partition_date.format', function (newValue) { + $scope.modelsManager.selectedModel.partition_desc.partition_date_format = newValue; + }); + }; + if ($scope.state.mode=='edit'){ $scope.initSetting(); judgeFormatEditable($scope.modelsManager.selectedModel.partition_desc.partition_date_column); diff --git a/webapp/app/js/model/cubeConfig.js b/webapp/app/js/model/cubeConfig.js index eacb9154c5..a83d4c9a66 100644 --- a/webapp/app/js/model/cubeConfig.js +++ b/webapp/app/js/model/cubeConfig.js @@ -96,14 +96,22 @@ KylinApp.constant('cubeConfig', { {name:"minute_start",type:"timestamp"} ], partitionDateFormatOpt:[ + 'yyyy-MM-dd HH:mm:ss', + 'yyyy-MM-dd HH:mm', + 'yyyy-MM-dd HH', 'yyyy-MM-dd', + 'yyyyMMddHHMMSS', + 'yyyyMMddHHMM', + 'yyyyMMddHH', 'yyyyMMdd', - 'yyyy-MM-dd HH:mm:ss' + // 'timestamp', + // 'other' ], partitionTimeFormatOpt:[ 'HH:mm:ss', 'HH:mm', - 'HH' + 'HH', + // 'other' ], rowKeyShardOptions:[ true,false diff --git a/webapp/app/less/app.less b/webapp/app/less/app.less index 7aa7283560..cf9748e291 100644 --- a/webapp/app/less/app.less +++ b/webapp/app/less/app.less @@ -936,4 +936,18 @@ td.snapshot-usage .tooltip { } td.snapshot-usage .tooltip-inner { max-width: 1024px; +} + +div[ng-controller="ModelConditionsSettingsCtrl"] { + .format-input { + margin-top: 15px; + } + select.col-5 + .chosen-container { + width: 49% !important; + } + .format-input.col-5 { + display: inline-block; + width: 49%; + margin-top: 0; + } } \ No newline at end of file diff --git a/webapp/app/partials/modelDesigner/conditions_settings.html b/webapp/app/partials/modelDesigner/conditions_settings.html index cce5de2cf2..10aee8466c 100644 --- a/webapp/app/partials/modelDesigner/conditions_settings.html +++ b/webapp/app/partials/modelDesigner/conditions_settings.html @@ -27,7 +27,7 @@ <h3>Partition</h3> <div class="row middle-popover"> <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Partition Date Column</b> <i kylinpopover placement="right" title="Partition Date Column" template="partitionTip.html" class="fa fa-info-circle"></i></label> <div class="col-xs-12 col-sm-6" ng-if="state.mode=='edit'"> - <select style="width: 49%" chosen data-placeholder="e.g. DEFAULT.TEST_KYLIN_FACT.CAL_DT" + <select width="'49%'" chosen data-placeholder="e.g. DEFAULT.TEST_KYLIN_FACT.CAL_DT" ng-model="selectedTables.fact" ng-change="tableChange(selectedTables.fact)" data-placement="" @@ -35,7 +35,7 @@ <h3>Partition</h3> <option value="">--Select Partition Table--</option> </select> - <select style="width: 49%" chosen data-placeholder="e.g. DEFAULT.TEST_KYLIN_FACT.CAL_DT" + <select width="'49%'" chosen data-placeholder="e.g. DEFAULT.TEST_KYLIN_FACT.CAL_DT" ng-model="modelsManager.selectedModel.partition_desc.partition_date_column" ng-change="partitionChange(modelsManager.selectedModel.partition_desc.partition_date_column)" data-placement="" @@ -57,15 +57,24 @@ <h3>Partition</h3> <div class="row"> <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Date Format</b></label> <div class="col-xs-12 col-sm-6"> - <select style="width: 100%" chosen - ng-required="modelsManager.selectedModel.partition_desc.partition_date_format" - ng-model="modelsManager.selectedModel.partition_desc.partition_date_format" + <select chosen + width="'98.5%'" ng-if="state.mode=='edit'" + ng-model="partition_date.type" + ng-required="partition_date.type" ng-disabled="$parent.isFormatEdit.editable!==true" - data-placement="" - ng-options="ddt as ddt for ddt in cubeConfig.partitionDateFormatOpt"> + ng-class="{ 'col-5': partition_date.type === 'other' }" + ng-options="ddt as ddt for ddt in cubeConfig.partitionDateFormatOpt" + data-placement=""> <option value="">--Select Date Format--</option> </select> + <input + class="form-control format-input" + ng-if="partition_date.type === 'other'" + ng-model="partition_date.format" + ng-required="partition_date.format" + ng-class="{ 'col-5': partition_date.type === 'other' }" + placeholder="Please enter your custom date format."/> <span ng-if="state.mode=='view'&&modelsManager.selectedModel.partition_desc.partition_date_column">{{(modelsManager.selectedModel.partition_desc.partition_date_format)}}</span> </div> </div> @@ -85,14 +94,14 @@ <h3>Partition</h3> <div class="row middle-popover"> <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default align-right"><b>Partition Time Column </b> <i kylinpopover placement="right" ng-title="Partition Time Column" template="partitionTimeTip.html" class="fa fa-info-circle"></i> </label> <div class="col-xs-12 col-sm-6"> - <select style="width: 49%" chosen + <select width="'49%'" chosen ng-model="selectedTablesForPartitionTime.fact" ng-if="state.mode=='edit'" data-placement="" ng-options="alias as alias for alias in availableFactTables" > <option value="">--Select Partition Table--</option> </select> - <select style="width: 49%" chosen + <select width="'49%'" chosen ng-model="modelsManager.selectedModel.partition_desc.partition_time_column" ng-if="state.mode=='edit'" data-placement="" @@ -109,14 +118,23 @@ <h3>Partition</h3> <div class="row"> <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Time Format</b></label> <div class="col-xs-12 col-sm-6"> - <select style="width: 100%" chosen - ng-required="modelsManager.selectedModel.partition_desc.partition_time_format" - ng-model="modelsManager.selectedModel.partition_desc.partition_time_format" - ng-if="state.mode=='edit'" - data-placement="" - ng-options="ddt as ddt for ddt in cubeConfig.partitionTimeFormatOpt"> + <select chosen + width="'98.5%'" + ng-if="state.mode=='edit'" + ng-model="partition_time.type" + ng-required="partition_time.type" + ng-class="{ 'col-5': partition_time.type === 'other' }" + ng-options="ddt as ddt for ddt in cubeConfig.partitionTimeFormatOpt" + data-placement=""> <option value="">--Select Time Format--</option> </select> + <input + class="form-control format-input" + ng-if="partition_time.type === 'other'" + ng-model="partition_time.format" + ng-required="partition_time.format" + ng-class="{ 'col-5': partition_time.type === 'other' }" + placeholder="Please enter your custom time format."/> <span ng-if="state.mode=='view'&&modelsManager.selectedModel.partition_desc.partition_time_column">{{(modelsManager.selectedModel.partition_desc.partition_time_format)}}</span> </div> </div> ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services