This is an automated email from the ASF dual-hosted git repository. xxyu pushed a commit to branch kylin5_beta in repository https://gitbox.apache.org/repos/asf/kylin.git
commit 5f046ea4c73b7c792faaa1676598fd9ececd21be Author: Qian Xia <lauraxiaq...@gmail.com> AuthorDate: Thu Jul 20 16:40:12 2023 +0800 KYLIN-5660 base indexes issue --- .../studio/StudioModel/ModelEdit/index.vue | 4 +- .../StudioModel/ModelList/ModelAggregate/index.vue | 107 ++++----- .../ModelList/ModelAggregate/locales.js | 6 +- .../ModelList/ModelLayout/modelLayout.vue | 1 - .../ModelList/ModelSaveConfig/index.vue | 238 +++++++++++---------- .../ModelList/ModelSaveConfig/locales.js | 13 +- .../studio/StudioModel/TableIndexEdit/store.js | 1 - .../StudioModel/TableIndexEdit/tableindex_edit.vue | 3 +- 8 files changed, 178 insertions(+), 195 deletions(-) diff --git a/kystudio/src/components/studio/StudioModel/ModelEdit/index.vue b/kystudio/src/components/studio/StudioModel/ModelEdit/index.vue index 8382f1ebad..8b9a9a4919 100644 --- a/kystudio/src/components/studio/StudioModel/ModelEdit/index.vue +++ b/kystudio/src/components/studio/StudioModel/ModelEdit/index.vue @@ -2046,7 +2046,7 @@ export default class ModelEdit extends Vue { this.isPurgeSegment = res.isPurgeSegment // 修改分区列会清空所有segment,该字段引导用户去添加segment } if (res.isSubmit) { - this.handleSaveModel({data, modelSaveConfigData: res.data, createBaseIndex: this.modelInstance.has_base_table_index && this.modelInstance.has_base_agg_index ? false : res.with_base_index}) + this.handleSaveModel({data, modelSaveConfigData: res.data, createBaseIndex: res.base_index_type}) } else { this.saveBtnLoading = false } @@ -2326,7 +2326,7 @@ export default class ModelEdit extends Vue { } handleSaveModel ({data, modelSaveConfigData, createBaseIndex}) { this.saveModelType = 'saveModel' - let para = {...data, with_base_index: createBaseIndex} + let para = {...data, base_index_type: createBaseIndex} if (data.uuid) { this.saveModelType = 'updataModel' } diff --git a/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/index.vue b/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/index.vue index bcc4f70f4a..98f3faa97c 100644 --- a/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/index.vue +++ b/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/index.vue @@ -1,12 +1,6 @@ <template> <div class="model-aggregate ksd-mb-15" v-if="model" v-loading="isLoading"> <div class="aggregate-view"> - <div class="btn-groups" v-if="showModelTypeSwitch"> - <el-tabs class="btn-group-tabs" v-model="switchModelType" type="button" @tab-click="changeModelTab"> - <el-tab-pane :label="$t('kylinLang.common.BATCH')" name="BATCH" /> - <el-tab-pane :label="$t('kylinLang.common.STREAMING')" name="STREAMING" /> - </el-tabs> - </div> <div class="index-group"> <el-card class="agg-detail-card agg-detail"> <div class="detail-content" v-loading="indexLoading"> @@ -24,9 +18,9 @@ </div> </el-popover> <div class="date-range ksd-mb-16 ksd-fs-12 ksd-fleft"> - {{$t('dataRange')}}: {{getDataRange}}<span class="data-range-tips"><i v-if="!isRealTimeMode" v-popover:indexPopover class="el-icon-ksd-info ksd-fs-12 ksd-ml-8"></i></span> + {{$t('dataRange')}}: {{getDataRange}}<span class="data-range-tips"><i v-popover:indexPopover class="el-icon-ksd-info ksd-fs-12 ksd-ml-8"></i></span> </div> - <div v-if="isShowAggregateAction && isHaveComplementSegs && !isRealTimeMode" @click="complementedIndexes('allIndexes')" class="text-btn-like ksd-fleft ksd-ml-6"> + <div v-if="isShowAggregateAction && isHaveComplementSegs" @click="complementedIndexes('allIndexes')" class="text-btn-like ksd-fleft ksd-ml-6"> <el-tooltip :content="$t('viewIncomplete')" effect="dark" placement="top"> <i class="el-ksd-icon-view_range_22"></i> </el-tooltip> @@ -39,10 +33,21 @@ </div> </div> <div class="clearfix" v-if="isShowAggregateAction"> - <el-alert class="ksd-mb-8" :title="$t('realTimeModelActionTips')" type="tip" show-icon v-if="isRealTimeMode&&isShowRealTimeModelActionTips" @close="isShowRealTimeModelActionTips = false" /> <el-dropdown style="margin-left:-14px !important;" class="ksd-ml-5 ksd-fleft" v-if="isShowAggregateAction && isShowIndexActions && !indexLoading"> <el-button icon="el-ksd-icon-add_22" type="primary" text>{{$t('index')}}</el-button> <el-dropdown-menu slot="dropdown"> + <el-dropdown-item class="dropdown-group-title" v-if="model.model_type === 'HYBRID' ? switchModelType !== 'STREAMING' : model.model_type !== 'STREAMING'"> + <span>{{$t('base')}}</span> + </el-dropdown-item> + <el-dropdown-item :class="{'action-disabled': Object.keys(indexStat).length && !indexStat.need_create_base_agg_index}" v-if="model.model_type === 'HYBRID' ? switchModelType !== 'STREAMING' : model.model_type !== 'STREAMING'"> + <span :title="Object.keys(indexStat).length && !indexStat.need_create_base_agg_index ? $t('unCreateBaseAggIndexTip') : ''" @click="createBaseIndex('BASE_AGG_INDEX')">{{$t('BASE_AGG_INDEX')}}</span> + </el-dropdown-item> + <el-dropdown-item :class="{'action-disabled': Object.keys(indexStat).length && !indexStat.need_create_base_table_index}" v-if="model.model_type === 'HYBRID' ? switchModelType !== 'STREAMING' : model.model_type !== 'STREAMING'"> + <span :title="Object.keys(indexStat).length && !indexStat.need_create_base_table_index ? $t('unCreateBaseTableIndexTip') : ''" @click="createBaseIndex('BASE_TABLE_INDEX')">{{$t('BASE_TABLE_INDEX')}}</span> + </el-dropdown-item> + <el-dropdown-item class="dropdown-group-title" divided v-if="isShowEditAgg || (isShowTableIndexActions&&!isHideEdit)"> + <span>{{$t('custom')}}</span> + </el-dropdown-item> <el-dropdown-item :class="{'action-disabled': !indexUpdateEnabled && model.model_type === 'STREAMING'}" @click.native="handleAggregateGroup" v-if="isShowEditAgg"> <el-tooltip :content="$t('refuseAddIndexTip')" effect="dark" placement="top" :disabled="indexUpdateEnabled || model.model_type !== 'STREAMING'"> <span>{{$t('aggregateGroup')}}</span> @@ -53,21 +58,10 @@ <span>{{$t('tableIndex')}}</span> </el-tooltip> </el-dropdown-item> - <el-dropdown-item :class="{'action-disabled': Object.keys(indexStat).length && !indexStat.need_create_base_agg_index && !indexStat.need_create_base_table_index}" v-if="model.model_type === 'HYBRID' ? switchModelType !== 'STREAMING' : model.model_type !== 'STREAMING'"> - <span :title="Object.keys(indexStat).length && !indexStat.need_create_base_agg_index && !indexStat.need_create_base_table_index ? $t('unCreateBaseIndexTip') : ''" @click="createBaseIndex">{{$t('baseIndex')}}</span> - </el-dropdown-item> </el-dropdown-menu> </el-dropdown> - <el-button icon="el-ksd-icon-build_index_22" :disabled="!checkedList.length || isHaveLockedIndex" text type="primary" class="ksd-ml-2 ksd-fleft" v-if="datasourceActions.includes('buildIndex') && !isRealTimeMode" @click="complementedIndexes('batchIndexes')">{{$t('buildIndex')}}</el-button> - <template v-if="isRealTimeMode"> - <el-tooltip placement="top" :content="!indexUpdateEnabled ? $t('refuseRemoveIndexTip') : $t('disabledDelBaseIndexTips')" v-if="datasourceActions.includes('delAggIdx') && (isDisableDelBaseIndex || !indexUpdateEnabled)"> - <div class="ksd-fleft"> - <el-button v-if="datasourceActions.includes('delAggIdx') && (isDisableDelBaseIndex || !indexUpdateEnabled)" :disabled="isDisableDelBaseIndex || !indexUpdateEnabled" type="primary" icon="el-ksd-icon-table_delete_22" @click="removeIndexes" text>{{$t('kylinLang.common.delete')}}</el-button> - </div> - </el-tooltip> - <el-button v-if="datasourceActions.includes('delAggIdx') && !isDisableDelBaseIndex && indexUpdateEnabled" :disabled="!checkedList.length" type="primary" icon="el-ksd-icon-table_delete_22" class="ksd-fleft" @click="removeIndexes" text>{{$t('kylinLang.common.delete')}}</el-button> - </template> - <template v-else> + <el-button icon="el-ksd-icon-build_index_22" :disabled="!checkedList.length || isHaveLockedIndex" text type="primary" class="ksd-ml-2 ksd-fleft" v-if="datasourceActions.includes('buildIndex')" @click="complementedIndexes('batchIndexes')">{{$t('buildIndex')}}</el-button> + <template> <el-tooltip placement="top" :content="$t('disabledDelBaseIndexTips')" v-if="datasourceActions.includes('delAggIdx')&&isDisableDelBaseIndex"> <div class="ksd-fleft"> <el-dropdown @@ -117,7 +111,7 @@ <div class="filter-tags-layout"><el-tag size="mini" closable v-for="(item, index) in filterTags" :key="index" @close="handleClose(item)">{{`${$t(item.source)}:${$t(item.label)}`}}</el-tag></div> <span class="clear-all-filters" @click="clearAllTags">{{$t('clearAll')}}</span> </div> - <div class="index-table-list" :class="{'is-show-filter': filterTags.length, 'is-show-tips' :isRealTimeMode&&isShowRealTimeModelActionTips, 'is-show-tab-button': showModelTypeSwitch, 'is-show-tips--tab-button': isRealTimeMode&&isShowRealTimeModelActionTips&&showModelTypeSwitch}"> + <div class="index-table-list" :class="{'is-show-filter': filterTags.length}"> <el-table ref="indexesTable" :data="indexDatas" @@ -176,7 +170,7 @@ </el-table-column> <el-table-column :label="$t('kylinLang.common.action')" fixed="right" width="83" v-if="isShowAggregateAction"> <template slot-scope="scope"> - <common-tip :content="$t('buildIndex')" :disabled="scope.row.status === 'LOCKED'" v-if="isShowAggregateAction&&datasourceActions.includes('buildIndex')&&!isRealTimeMode"> + <common-tip :content="$t('buildIndex')" :disabled="scope.row.status === 'LOCKED'" v-if="isShowAggregateAction&&datasourceActions.includes('buildIndex')"> <i class="el-ksd-icon-build_index_22 ksd-ml-5" :class="{'is-disabled': scope.row.status === 'LOCKED'}" @click="complementedIndexes('', scope.row.id)"></i> </common-tip> <common-tip :content="$t('editIndex')" v-if="isShowAggregateAction&&datasourceActions.includes('editAggGroup')"> @@ -322,27 +316,12 @@ export default class ModelAggregate extends Vue { filterTags = [] checkedList = [] removeLoading = false - indexRangeMap = { - BATCH: ['HYBRID', 'BATCH'], - STREAMING: ['HYBRID', 'STREAMING'] - } switchIndexValue = 'index' switchModelType = 'BATCH' // 默认批数据 - BATCH, 流数据 - STREAMING isHaveComplementSegs = false indexesByQueryHistory = true // 是否获取查询相关的索引 - isShowRealTimeModelActionTips = true indexStat = {} - // 控制显示流数据,批数据选项 - get showModelTypeSwitch () { - return this.model && this.model.model_type === 'HYBRID' - } - - // 判断是否时流数据模式 - get isRealTimeMode () { - return (this.showModelTypeSwitch && this.switchModelType === 'STREAMING') || (this.model.model_type === 'STREAMING') - } - get modelId () { if (this.model.model_type !== 'HYBRID') { return this.model.uuid @@ -351,23 +330,6 @@ export default class ModelAggregate extends Vue { } } - // 标识是融合数据模型下的批数据模式 - get isHybridBatch () { - return this.model.model_type === 'HYBRID' && this.switchModelType === 'BATCH' - } - - async changeModelTab (name) { - // 切换tab 时需要重刷列表 - this.filterArgs.page_offset = 0 - this.filterArgs.page_size = +localStorage.getItem(this.pageRefTags.indexPager) || pageCount - this.filterArgs.key = '' - this.indexLoading = true - await this.freshIndexGraph() - await this.loadAggIndices() - this.getIndexInfo() - this.indexLoading = false - } - formatDataSize (dataSize) { const [size = +size, ext] = this.$root.$options.filters.dataSize(dataSize).split(' ') const intType = ['B', 'KB'] @@ -425,7 +387,6 @@ export default class ModelAggregate extends Vue { indexes: indexes, submitText: submitText, isRemoveIndex: isRemoveIndex, - isHybridBatch: this.isHybridBatch, model: this.model }) this.refreshIndexGraphAfterSubmitSetting() @@ -531,11 +492,10 @@ export default class ModelAggregate extends Vue { editTableIndex (indexDesc) { const { projectName, model } = this this.showTableIndexEditModal({ - isHybridBatch: this.isHybridBatch, modelInstance: this.modelInstance, tableIndexDesc: indexDesc || {name: 'TableIndex_1'}, indexUpdateEnabled: this.indexUpdateEnabled, - indexType: this.showModelTypeSwitch ? this.switchModelType : '', + indexType: '', projectName, model }).then((res) => { @@ -735,11 +695,7 @@ export default class ModelAggregate extends Vue { } async loadAggIndices (ids) { try { - // this.indexLoading = true const params = {} - if (this.showModelTypeSwitch) { - params.range = this.indexRangeMap[this.switchModelType] - } if (this.indexesByQueryHistory && !this.layoutId && !this.isShowAggregateAction) { this.indexDatas = [] this.totalSize = 0 @@ -755,10 +711,8 @@ export default class ModelAggregate extends Vue { this.indexDatas = data.value this.totalSize = data.total_size this.indexUpdateEnabled = data.index_update_enabled - // this.indexLoading = false } catch (e) { handleError(e) - // this.indexLoading = false } } created () { @@ -780,7 +734,7 @@ export default class ModelAggregate extends Vue { async handleAggregateGroup () { if (!this.indexUpdateEnabled && this.model.model_type === 'STREAMING') return const { projectName, model } = this - const { isSubmit } = await this.callAggregateModal({ editType: 'new', model, projectName, indexUpdateEnabled: this.indexUpdateEnabled, indexType: this.showModelTypeSwitch ? this.switchModelType : '' }) + const { isSubmit } = await this.callAggregateModal({ editType: 'new', model, projectName, indexUpdateEnabled: this.indexUpdateEnabled, indexType: '' }) isSubmit && await this.refreshIndexGraphAfterSubmitSetting() isSubmit && await this.$emit('refreshModel') } @@ -844,18 +798,16 @@ export default class ModelAggregate extends Vue { } // 创建 base index - createBaseIndex () { - if (Object.keys(this.indexStat).length && !this.indexStat.need_create_base_agg_index && !this.indexStat.need_create_base_table_index) return + createBaseIndex (type) { + if (Object.keys(this.indexStat).length && (!this.indexStat.need_create_base_agg_index && type === 'BASE_AGG_INDEX' || !this.indexStat.need_create_base_table_index && type === 'BASE_TABLE_INDEX')) return this.loadBaseIndex({ model_id: this.modelId, project: this.projectName, load_data: false, - source_type: ['BASE_TABLE_INDEX', 'BASE_AGG_INDEX'] + source_types: [type] }).then(async (res) => { const result = await handleSuccessAsync(res) const layoutIds = [] - // const baseAggIndexNum = result.agg_index ? result.agg_index.dimension_count + result.agg_index.measure_count : 0 - // const baseTableIndexNum = result.table_index ? result.table_index.dimension_count + result.table_index.measure_count : 0 result.base_agg_index && layoutIds.push(result.base_agg_index.layout_id) result.base_table_index && layoutIds.push(result.base_table_index.layout_id) this.$message({ @@ -1258,6 +1210,19 @@ export default class ModelAggregate extends Vue { &.action-disabled { color: @text-disabled-color; cursor: not-allowed; + &:focus { + color: @text-disabled-color; + cursor: not-allowed; + } + } + &.dropdown-group-title { + font-size: 12px; + color: @text-disabled-color; + line-height: 30px; + cursor: default; + &:hover { + background-color: @fff !important; + } } } diff --git a/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/locales.js b/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/locales.js index 078b753175..545f76e14b 100644 --- a/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/locales.js +++ b/kystudio/src/components/studio/StudioModel/ModelList/ModelAggregate/locales.js @@ -28,6 +28,8 @@ export default { RECOMMENDED_TABLE_INDEX: 'Recommended Table Index', BASE_AGG_INDEX: 'Base Aggregate Index', BASE_TABLE_INDEX: 'Base Table Index', + custom: 'Customize', + base: 'Base', customAggIndex: 'Custom Aggregate Group: ', customTableIndex: 'Custom Table Index: ', indexContentTips: '{dimensionNum} dimension(s), {measureNum} measure(s)', @@ -76,11 +78,11 @@ export default { cardinality: 'Cardinality', cardinalityColumnTips: 'Total amount of unique data in this column. Could be gathered from sampling.', baseIndex: 'Base Index', - unCreateBaseIndexTip: 'Base Indexes have already been added', + unCreateBaseAggIndexTip: 'Base Aggregate Index have already been added', + unCreateBaseTableIndexTip: 'Base Table Index have already been added', buildBaseIndexTip: 'Successfully added {baseIndexNum} base index(es). ', updateBaseIndexTips: 'A base index would be added. The previous base index might be in "locked" state while still could answer queries. Are you sure you wan to update?', disabledDelBaseIndexTips: 'To delete the base table index, please turn off tiered storage for the model.', - realTimeModelActionTips: 'To build streaming index needs to start the streaming job on the Job page. To add/delete streaming indexes, follow the steps: stop the streaming job, delete all the streaming segments, add/delete streaming indexes, start the streaming job.', refuseAddIndexTip: 'Can\'t add streaming indexes. Please stop the streaming job and then delete all the streaming segments.', refuseRemoveIndexTip: 'Can\'t delete streaming indexes. Please stop the streaming job and then delete all the streaming segments.', disabledBuildIndexTips: 'disabledBuildIndexTips' diff --git a/kystudio/src/components/studio/StudioModel/ModelList/ModelLayout/modelLayout.vue b/kystudio/src/components/studio/StudioModel/ModelList/ModelLayout/modelLayout.vue index 4bb9f838ed..a84af715b4 100644 --- a/kystudio/src/components/studio/StudioModel/ModelList/ModelLayout/modelLayout.vue +++ b/kystudio/src/components/studio/StudioModel/ModelList/ModelLayout/modelLayout.vue @@ -416,7 +416,6 @@ export default class ModelLayout extends Vue { refrashWarningSegment: refrashWarningSegment, indexes: [], submitText: submitText, - isHybridBatch: this.currentModelRow.model_type === 'HYBRID', model: model }) } diff --git a/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/index.vue b/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/index.vue index efc76eb115..6578697518 100644 --- a/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/index.vue +++ b/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/index.vue @@ -9,8 +9,7 @@ @close="isShow && handleClose(false)" :close-on-press-escape="false" :close-on-click-modal="false"> - <!-- <div class="ky-list-title" v-if="!(modelInstance && modelInstance.uuid) && partitionMeta.table && partitionMeta.column">{{$t('partitionSet')}}</div> --> - <div class="partition-set ksd-mb-10" v-if="mode === 'saveModel'"> + <div class="partition-set" v-if="mode === 'saveModel'"> <el-alert :title="cannotSaveModelTips" type="error" @@ -27,22 +26,24 @@ v-if="isShowWarning" show-icon> </el-alert> - <div class="ksd-title-label-mini">{{$t('chooseBuildType')}}</div> - <el-select v-model="buildType" class="ksd-mtb-10" @change="handChangeBuildType" :disabled="!datasourceActions.includes('changeBuildType')" style="width:100%"> - <el-option :label="$t('incremental')" value="incremental"></el-option> - <el-option v-if="!isNotBatchModel" :label="$t('fullLoad')" value="fullLoad"></el-option> - </el-select> - <el-alert - class="ksd-pt-0" - :title="buildTips" - type="info" - :show-background="false" - :closable="false" - show-icon> - </el-alert> + <el-tabs v-model="buildType" class="buildType-switch" type="button" @tab-click="handChangeBuildType"> + <el-tab-pane name="incremental" :disabled="!datasourceActions.includes('changeBuildType')"> + <span slot="label"> + <el-tooltip :content="$t('incrementalTips')" placement="top"> + <span>{{$t('incremental')}}<el-tag class="ksd-ml-5" size="mini" type="success">{{$t('recommend')}}</el-tag></span> + </el-tooltip> + </span> + </el-tab-pane> + <el-tab-pane :disabled="isNotBatchModel || !datasourceActions.includes('changeBuildType')" name="fullLoad"> + <span slot="label"> + <el-tooltip :content="!isNotBatchModel&&datasourceActions.includes('changeBuildType') ? $t('fullLoadTips', {storageSize: dataSize(modelDesc.storage)}) : this.$t('isNotBatchModel')" placement="top"> + <span>{{$t('fullLoad')}}</span> + </el-tooltip> + </span> + </el-tab-pane> + </el-tabs> </div> <el-form v-if="mode === 'saveModel'&&buildType=== 'incremental'" :model="partitionMeta" ref="partitionForm" :rules="partitionRules" label-width="85px" label-position="top"> - <div class="ksd-title-label-mini ksd-mb-10">{{$t('partitionSet')}}</div> <!-- 新建流数据、融合数据模型时提示 --> <el-alert class="ksd-mb-8" @@ -57,7 +58,6 @@ <el-col :span="24"> <el-tooltip effect="dark" :content="$t('disableChangePartitionTips')" :disabled="!(isNotBatchModel&&!!modelDesc.uuid&&isAlreadyHavePartition)" placement="bottom"> <el-select :disabled="isLoadingNewRange||(isNotBatchModel&&!!modelDesc.uuid&&isAlreadyHavePartition)" v-model="partitionMeta.table" @change="partitionTableChange" :placeholder="$t('kylinLang.common.pleaseSelectOrSearch')" style="width:100%"> - <!-- <el-option :label="$t('noPartition')" value=""></el-option> --> <el-option :label="t.alias" :value="t.alias" v-for="t in partitionTables" :key="t.alias">{{t.alias}}</el-option> </el-select> </el-tooltip> @@ -108,11 +108,7 @@ <el-option-group> <el-option v-if="dateFormatsOptions.map(it => it.value).indexOf(prevPartitionMeta.format) === -1 && prevPartitionMeta.format" :label="prevPartitionMeta.format" :value="prevPartitionMeta.format"></el-option> <el-option :label="f.label" :value="f.value" v-for="f in dateFormatsOptions" :key="f.label"></el-option> - <!-- <el-option label="" value="" v-if="partitionMeta.column && timeDataType.indexOf(getColumnInfo(partitionMeta.column).datatype)===-1"></el-option> --> </el-option-group> - <!-- <el-option-group> - <el-option :label="f.label" :value="f.value" v-for="f in dateTimestampFormats" :key="f.label"></el-option> - </el-option-group> --> </el-select> </el-tooltip> </el-col> @@ -132,8 +128,8 @@ <div class="error-format" v-if="errorFormat">{{errorFormat}}</div> <div class="pre-format" v-if="formatedDate">{{$t('previewFormat')}}{{formatedDate}}</div> <div class="format">{{$t('formatRule')}} - <span v-if="isExpandFormatRule" @click="isExpandFormatRule = false">{{$t('viewDetail')}}<i class="el-icon-ksd-more_01-copy arrow"></i></span> - <span v-else @click="isExpandFormatRule = true">{{$t('viewDetail')}}<i class="el-icon-ksd-more_02 arrow"></i></span> + <span v-if="isExpandFormatRule" @click="isExpandFormatRule = false">{{$t('viewDetail')}}<i class="el-ksd-icon-arrow_up_16 arrow ksd-fs-16"></i></span> + <span v-else @click="isExpandFormatRule = true">{{$t('viewDetail')}}<i class="el-ksd-icon-arrow_down_16 arrow ksd-fs-16"></i></span> </div> <div class="detail-content" v-if="isExpandFormatRule"> <p><span class="ksd-mr-2">1. </span><span>{{$t('rule1')}}</span></p> @@ -146,7 +142,7 @@ <span slot="label"> <span>{{$t('multilevelPartition')}}</span> <el-tooltip effect="dark" :content="$t('multilevelPartitionDesc')" placement="right"> - <i class="el-icon-ksd-what"></i> + <i class="el-icon-ksd-what ksd-fs-14"></i> </el-tooltip> </span> <el-row> @@ -173,13 +169,37 @@ </el-form-item> </el-form> <template v-if="mode === 'saveModel'"> - <div class="divide-block"> - <div class="divider"></div> - <span v-if="isExpand" @click="toggleShowPartition">{{$t('advanceSetting')}}<i class="el-ksd-icon-arrow_up_16 arrow ksd-fs-16"></i></span> - <span v-else @click="toggleShowPartition">{{$t('advanceSetting')}}<i class="el-ksd-icon-arrow_down_16 arrow ksd-fs-16"></i></span> + <div v-if="modelInstance && modelInstance.status !== 'BROKEN' && !isStreamModel && !this.isHaveNoDimMeas && !modelDesc.with_second_storage && !(modelInstance.has_base_table_index && modelInstance.has_base_agg_index)"> + <div class="divide-block"> + <div class="divider"> + <span>{{$t('indexSetting')}}</span> + </div> + </div> + <div class="base-index-block ksd-ptb-16"> + <el-checkbox-group v-model="source_types"> + <el-checkbox label="BASE_AGG_INDEX" size="small" v-if="!modelInstance.has_base_agg_index"> + <span>{{$t('addBaseAggIndexCheckBox')}}</span> + <el-tooltip effect="dark" :content="$t('baseAggIndexTips')" placement="top"> + <i class="el-icon-ksd-what ksd-fs-14"></i> + </el-tooltip> + </el-checkbox> + <el-checkbox size="small" label="BASE_TABLE_INDEX" :disabled="modelDesc.with_second_storage" v-if="!modelInstance.has_base_table_index"> + <span>{{$t('addBaseTableIndexCheckBox')}}</span> + <el-tooltip effect="dark" :content="$t('baseTableIndexTips')" placement="top"> + <i class="el-icon-ksd-what ksd-fs-14"></i> + </el-tooltip> + </el-checkbox> + </el-checkbox-group> + </div> + </div> + <div class="divide-block advance-setting"> + <div class="divider"> + <span v-if="isExpand" @click="toggleShowPartition">{{$t('advanceSetting')}}<i class="el-ksd-icon-arrow_up_16 arrow ksd-fs-16"></i></span> + <span v-else @click="toggleShowPartition">{{$t('advanceSetting')}}<i class="el-ksd-icon-arrow_down_16 arrow ksd-fs-16"></i></span> + </div> </div> <div v-show="isExpand"> - <div class="ksd-mb-24" v-if="$store.state.project.second_storage_enabled"> + <div class="second-setting ksd-mb-16" v-if="$store.state.project.second_storage_enabled"> <el-alert v-if="modelDesc.with_second_storage" show-icon type="warning" class="ksd-mb-8" :closable="false"> <span v-html="$t('forbidenComputedColumnTips')" class="ksd-fs-12"></span> </el-alert> @@ -209,7 +229,13 @@ v-if="isShowSecStorageTips" show-icon> </el-alert> - <span class="ksd-title-label-mini">{{$t('secStorage')}}</span> + <span class="ksd-title-label-mini"> + <span>{{$t('secStorage')}}</span> + <el-tooltip effect="dark" placement="right"> + <span slot="content" v-html="$t('secStorageDesc')"></span> + <i class="el-icon-ksd-what ksd-fs-14"></i> + </el-tooltip> + </span> <span class="sec-switch"> <common-tip :content="disableSecStorageTips" :disabled="!isNotBatchModel && !isHaveNoDimMeas"> <el-switch @@ -221,13 +247,11 @@ </el-switch> </common-tip> </span> - <div class="secStorage-desc ksd-mt-8" v-html="$t('secStorageDesc')"></div> </div> - <!-- <div class="divider"></div> --> - <div class="ksd-title-label-mini ksd-mb-8"> + <div class="data-filter ksd-title-label-mini ksd-mb-8"> {{$t('dataFilterCond')}} <el-tooltip effect="dark" :content="$t('dataFilterCondTips')" placement="right"> - <i class="el-ksd-icon-more_info_16 ksd-fs-16 ksd-mb-2"></i> + <i class="el-icon-ksd-what ksd-fs-14"></i> </el-tooltip> </div> <el-alert @@ -245,16 +269,8 @@ </div> </template> <div slot="footer" class="dialog-footer ky-no-br-space"> - <div class="ksd-fleft" style="display: flex;" v-if="modelInstance && modelInstance.status !== 'BROKEN' && !isStreamModel && !modelDesc.with_second_storage && !this.isHaveNoDimMeas && !(modelInstance.has_base_table_index && modelInstance.has_base_agg_index)"> - <el-checkbox v-model="addBaseIndex"> - <span>{{$t('addBaseIndexCheckBox')}}</span> - </el-checkbox> - <el-tooltip effect="dark" :content="$t('baseIndexTips')" placement="top"> - <i class="el-ksd-icon-more_info_22 ksd-fs-22"></i> - </el-tooltip> - </div> <el-button size="medium" @click="isShow && handleClose(false)">{{$t('kylinLang.common.cancel')}}</el-button> - <el-button type="primary" v-if="isShow" :disabled="isLoadingNewRange||disabledSave" :loading="isLoadingSave" @click="savePartitionConfirm" size="medium">{{$t('kylinLang.common.submit')}}</el-button> + <el-button type="primary" v-if="isShow" :disabled="isLoadingNewRange||disabledSave" :loading="isLoadingSave" @click="savePartitionConfirm" size="medium">{{mode === 'saveModel' ? $t('modelSaveSet') : $t('kylinLang.common.submit')}}</el-button> </div> </el-dialog> </template> @@ -269,7 +285,6 @@ import locales from './locales' import store, { types } from './store' import { timeDataType, dateFormats, timestampFormats, dateTimestampFormats } from '../../../../../config' import NModel from '../../ModelEdit/model.js' -// import { titleMaps, cancelMaps, confirmMaps, getSubmitData } from './handler' import { objectClone, isSubPartitionType, indexOfObjWithSomeKey, isStreamingPartitionType } from '../../../../../util' import { handleSuccess, transToUTCMs } from 'util/business' import { handleSuccessAsync, handleError } from 'util/index' @@ -292,12 +307,6 @@ vuex.registerModule(['modals', 'ModelSaveConfig'], store) exchangeJoinTableList: state => state.form.exchangeJoinTableList, callback: state => state.callback }), - // ...mapState('DimensionsModal', { - // otherColumns: state => state.otherColumns - // }), - // ...mapState('BatchMeasureModal', { - // otherMeasureColumns: state => state.otherColumns - // }), ...mapState({ otherColumns: state => state.model.otherColumns }) @@ -366,7 +375,7 @@ export default class ModelPartitionModal extends Vue { importantChange = false isExpand = false defaultBuildType = 'incremental' - addBaseIndex = false + source_types = [] isShowSecStorageTips = false isShowSecStorageTips2 = false isShowSecondStoragePartitionTips = false @@ -399,19 +408,16 @@ export default class ModelPartitionModal extends Vue { return true } } - get buildTips () { - if (this.buildType === 'incremental') { - return this.$t('incrementalTips') - } else if (this.buildType === 'fullLoad') { - return this.$t('fullLoadTips', {storageSize: Vue.filter('dataSize')(this.modelDesc.storage)}) - } - } get factTableType () { const obj = this.modelInstance.getFactTable() return obj.source_type } + dataSize (storage) { + return Vue.filter('dataSize')(storage) + } + handChangeBuildType (val) { this.isShowWarning = typeof this.modelDesc.available_indexes_count === 'number' && this.modelDesc.available_indexes_count > 0 && (this.defaultBuildType !== this.buildType || this.isChangePartition) if (val === 'incremental' && !this.partitionMeta.table) { @@ -489,7 +495,7 @@ export default class ModelPartitionModal extends Vue { } get partitionTitle () { if (this.mode === 'saveModel') { - return this.$t('modelSaveSet') + return this.$t('saveModel') } else { return this.$t('modelPartitionSet') } @@ -505,13 +511,7 @@ export default class ModelPartitionModal extends Vue { } return result } - // get showDataRange () { - // // 分区列有空值或者和历史值一样 - // if (!this.partitionMeta.table || !this.partitionMeta.column || this.partitionMeta.table + '.' + this.partitionMeta.column === this.modelInstance.his_partition_desc.partition_date_column) { - // return false - // } - // return true - // } + // 获取破损的partition keys get brokenPartitionColumns () { if (this.partitionMeta.table) { @@ -606,7 +606,10 @@ export default class ModelPartitionModal extends Vue { // }) const partition_desc = this.modelDesc.partition_desc this.isExpand = !this.modelDesc.uuid && !this.isNotBatchModel - this.addBaseIndex = this.modelInstance && !(this.isStreamModel || this.modelDesc.with_second_storage || this.isHaveNoDimMeas || (this.modelInstance.has_base_table_index && this.modelInstance.has_base_agg_index)) + // 新建模型是,默认添加基础索引。编辑时已添加基础索引不显示,未添加索引是未勾选状态,用户可选择勾选 + if (!this.modelDesc.uuid) { + this.source_types = ['BASE_TABLE_INDEX', 'BASE_AGG_INDEX'] + } if (this.modelDesc.uuid && !(partition_desc && partition_desc.partition_date_column) && !this.isNotBatchModel) { this.buildType = 'fullLoad' this.defaultBuildType = 'fullLoad' @@ -643,12 +646,7 @@ export default class ModelPartitionModal extends Vue { this.partitionMeta.column = '' this.partitionMeta.format = '' this.partitionMeta.multiPartition = '' - // this.$refs.partitionForm.validate() } - // partitionColumnChange () { - // this.partitionMeta.format = 'yyyy-MM-dd' - // this.$refs.partitionForm.validate() - // } resetForm () { this.partitionMeta = { table: '', @@ -698,14 +696,8 @@ export default class ModelPartitionModal extends Vue { } let isOnlySave = true if (typeof this.modelDesc.available_indexes_count === 'number' && this.modelDesc.available_indexes_count > 0) { - // if (this.prevPartitionMeta.table && this.buildType === 'fullLoad') { - // await kylinConfirm(this.$t('changeSegmentTip2', {modelName: this.modelDesc.name}), '', this.$t('kylinLang.common.tip')) - // } else if ((this.prevPartitionMeta.table !== this.partitionMeta.table || this.prevPartitionMeta.column !== this.partitionMeta.column || this.prevPartitionMeta.format !== this.partitionMeta.format) && this.buildType === 'incremental') { - // await kylinConfirm(this.$t('changeSegmentTip1', {tableColumn: `${this.partitionMeta.table}.${this.partitionMeta.column}`, dateType: this.partitionMeta.format, modelName: this.modelDesc.name}), '', this.$t('kylinLang.common.tip')) - // } if (this.isChangeToFullLoad || this.isChangePartition) { this.importantChange = true - // await kylinConfirm(this.$t('changeSegmentTips'), {confirmButtonText: this.$t('kylinLang.common.save'), type: 'warning', dangerouslyUseHTMLString: true}, this.$t('kylinLang.common.tip')) const res = await this.callGlobalDetailDialog({ msg: this.$t('changeSegmentTips'), title: this.$t('kylinLang.common.tip'), @@ -786,13 +778,9 @@ export default class ModelPartitionModal extends Vue { if (!(checkData && checkData.partition_desc && checkData.partition_desc.partition_date_column) || this.buildType === 'fullLoad') { checkData.partition_desc = null } - // if (this.isHybridModel) { - // checkData.batch_partition_desc = checkData.partition_desc - // } this.checkFilterConditon(checkData).then((res) => { handleSuccess(res, async (data) => { // TODO HA 模式时 post 等接口需要等待同步完去刷新列表 - // await handleWaiting() if (!this.importantChange && 'rebuild_index' in data && data.rebuild_index) { try { const res = await this.callGlobalDetailDialog({ @@ -833,15 +821,12 @@ export default class ModelPartitionModal extends Vue { this.filterErrorMsg = '' // 不把这个信息记录下来的话,300 延迟后,modelDesc 就 undefined 了 let temp = objectClone(this.modelDesc) - // if (this.isHybridModel) { - // temp.batch_partition_desc = temp.partition_desc - // } setTimeout(() => { this.callback && this.callback({ isSubmit: isSubmit, isPurgeSegment: this.isChangePartition, data: temp, - with_base_index: this.modelDesc.with_second_storage ? false : this.addBaseIndex + base_index_type: this.source_types }) this.hideModal() this.resetModalForm() @@ -894,9 +879,34 @@ export default class ModelPartitionModal extends Vue { } </script> -<style lang="less" scoped> +<style lang="less"> @import '../../../../../assets/styles/variables.less'; .model-partition-dialog { + .buildType-switch { + .el-tabs__header { + width: 100%; + .el-tabs__nav { + width: 97.8%; + .el-tabs__item { + width: 50%; + .el-tag { + position: relative; + bottom: 1px; + } + } + } + } + } + .el-tabs__item.is-disabled { + cursor: not-allowed; + } + .second-setting, + .data-filter { + .el-icon-ksd-what { + position: relative; + top: 1px; + } + } .error-format { color: @error-color-1; font-size: 12px; @@ -906,7 +916,9 @@ export default class ModelPartitionModal extends Vue { color: @text-normal-color; font-size: 14px; margin-top: 4px; - background-color: @base-background-color; + background-color: @ke-background-color-secondary; + border: 1px solid @ke-border-divider-color; + border-radius: 6px; height: 26px; line-height: 26px; border-radius: 4px; @@ -922,13 +934,14 @@ export default class ModelPartitionModal extends Vue { color: @base-color; cursor: pointer; .arrow { - transform: rotate( 90deg ); margin-left: 3px; } } } .detail-content { - background-color: @base-background-color-1; + background-color: @ke-background-color-secondary; + border: 1px solid @ke-border-divider-color; + border-radius: 6px; padding: 8px 16px; box-sizing: border-box; font-size: 12px; @@ -954,26 +967,37 @@ export default class ModelPartitionModal extends Vue { color: @error-color-1; } } + .base-index-block { + .el-icon-ksd-what { + position: relative; + top: 1px; + } + } .divide-block { - color: @text-title-color; + color: @text-placeholder-color; position: relative; text-align: center; - margin-top: 5px; + margin-top: 16px; font-size: 12px; span { - cursor: pointer; + cursor: default; + position: absolute; + display: inline-block; + top: -8px; + background-color: #fff; + padding: 0 10px; + left: 44%; } - // .arrow { - // transform: rotate(90deg); - // margin-left: 3px; - // font-size: 5px; - // color: @base-color; - // position: absolute; - // top: 15px; - // } .divider { margin: 10px 0; - border-bottom: 1px solid @ke-color-secondary; + border-bottom: 1px solid @ke-border-secondary; + position: relative; + } + &.advance-setting { + color: @ke-color-primary; + span { + cursor: pointer; + } } } .item-desc { @@ -983,16 +1007,6 @@ export default class ModelPartitionModal extends Vue { .where-area { margin-top:20px; } - // .error-msg {display:none} - // .is-broken { - // .el-input__inner{ - // border:solid 1px @color-danger; - // } - // .error-msg { - // color:@color-danger; - // display:block; - // } - // } .up-performance{ i { color:@normal-color-1; diff --git a/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/locales.js b/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/locales.js index 2f99512b21..9b735733f8 100644 --- a/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/locales.js +++ b/kystudio/src/components/studio/StudioModel/ModelList/ModelSaveConfig/locales.js @@ -33,7 +33,9 @@ export default { chooseBuildType: 'Please select a load method', incremental: 'Incremental Load', fullLoad: 'Full Load', - incrementalTips: 'The system could incrementally load data based on the selected partition column.', + recommend: 'Recommend', + isNotBatchModel: 'Can’t load the stream model in full.', + incrementalTips: 'It will load data incrementally based on the selected partition column, which is more resource-efficient.', fullLoadTips: 'The system will load all data.', changeBuildTypeTips: 'With partition setting changed, all segments and data would be deleted. The model couldn\'t serve queries. Meanwhile, the related ongoing jobs for building index would be discarded.', editCCBuildTip: 'The modified expression of computed column would be effective until all the related indexes have been built. Do you want to save and build index now? ', @@ -45,10 +47,12 @@ export default { partitionDateTable: 'Partition Table', multilevelPartition: 'Subpartition Column', multilevelPartitionDesc: 'A column from the selected table could be chosen. The models under this project could be partitioned by this column in addition to time partitioning. ', + indexSetting: 'Index Setting', advanceSetting: 'Advanced Setting', - addBaseIndexCheckBox: 'Add Base Indexes', + addBaseAggIndexCheckBox: 'Base Aggregate Index', + addBaseTableIndexCheckBox: 'Base Table Index', secStorage: 'Tiered Storage', - secStorageDesc: 'With this switch ON, the system will create a base table index, which will be sync to the tiered storage. It will improve the performance of ad-hoc query and detail query analysis scenarios.<br/>The index can\'t be deleted when the tiered storage is ON.', + secStorageDesc: 'Tiered storage can significantly improve the performance of flexible ultra-multidimensional analysis and detailed queries. It will add base table index by default and cannot be deleted for synchronizing data when open.', secStorageTips: 'With this switch OFF, the model\'s tiered storage data will be cleared。', openSecStorageTips: 'It\'s recommended to turn on the tiered storage, as too many dimensions are included.', openSecStorageTips2: 'With the tiered storage ON, the existing data needs to be loaded to tiered storage to take effect.', @@ -57,7 +61,8 @@ export default { forbidenComputedColumnTips: 'The parquet files containing data prior to 1970 cannot be loaded. <a class="ky-a-like" href="https://docs.kyligence.io/books/v4.5/en/Designers-Guide/tiered_storage/" target="_blank">View the manual <i class="el-ksd-icon-spark_link_16"></i></a>', secondStoragePartitionTips: 'Can\'t save the model. When the model uses incremental load method and the tiered storage is ON, the time partition column must be added as a dimension.', streamSecStoragePartitionTips: 'Can\'t save the model. For fusion model, the time partition column must be added as a dimension.', - baseIndexTips: 'Base indexes include all dimensions and measures of the model and automatically update as the model changes by default.', + baseAggIndexTips: 'The base aggregate index contains all dimensions and metrics of the model, and can override answering aggregated queries to avoid pushdown. It will automatically update as the model changes by default.', + baseTableIndexTips: 'The base table index contains all the columns used in the dimensions and metrics of the model, and can override answering detailed queries to avoid pushdown. It will automatically update as the model changes by default.', notBatchModelPartitionTips: 'The time partition settings can\'t be modified after the fusion model or streaming model is saved.', disableChangePartitionTips: 'The time partition settings can\'t be modified for fusion model and streaming model.', previewFormat: 'Format preview: ', diff --git a/kystudio/src/components/studio/StudioModel/TableIndexEdit/store.js b/kystudio/src/components/studio/StudioModel/TableIndexEdit/store.js index bedfe56a6f..82e955b2d0 100644 --- a/kystudio/src/components/studio/StudioModel/TableIndexEdit/store.js +++ b/kystudio/src/components/studio/StudioModel/TableIndexEdit/store.js @@ -12,7 +12,6 @@ const initialState = JSON.stringify({ isShow: false, form: { data: { - isHybridBatch: false, modelInstance: null, tableIndexDesc: null, indexUpdateEnabled: true diff --git a/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue b/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue index e035e29a77..fa222db8f1 100644 --- a/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue +++ b/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue @@ -104,7 +104,6 @@ ]), ...mapState('TableIndexEditModal', { isShow: state => state.isShow, - isHybridBatch: state => state.isHybridBatch, modelInstance: state => state.form.data.modelInstance, tableIndexDesc: state => objectClone(state.form.data.tableIndexDesc), indexUpdateEnabled: state => state.form.data.indexUpdateEnabled, @@ -403,7 +402,7 @@ } }) this.tableIndexMeta.project = this.currentSelectedProject - this.tableIndexMeta.model_id = this.isHybridBatch ? this.modelInstance.batch_id : this.modelInstance.uuid + this.tableIndexMeta.model_id = this.modelInstance.uuid 'name' in this.tableIndexMeta && delete this.tableIndexMeta.name if (this.tableIndexMeta.id) { this.editTableIndex({...this.tableIndexMeta, index_range: this.tableIndexMeta.index_range || 'EMPTY'}).then(successCb, errorCb)