This is an automated email from the ASF dual-hosted git repository. xxyu pushed a commit to branch kylin5 in repository https://gitbox.apache.org/repos/asf/kylin.git
commit 334b8b2ca4b588bbc820b1a3cefb19cd286a4bf5 Author: Qian Xia <lauraxiaq...@gmail.com> AuthorDate: Thu Jul 13 15:15:13 2023 +0800 KYLIN-5624 agg index / table index text recognize --- .../RecognizeAggregateModal.vue | 29 ++++++++---- .../common/RecognizeAggregateModal/handler.js | 13 +++++- .../StudioModel/ModelList/AggregateModal/index.vue | 54 +++++++++++++++++++--- .../studio/StudioModel/TableIndexEdit/locales.js | 1 + .../StudioModel/TableIndexEdit/tableindex_edit.vue | 19 ++++++++ 5 files changed, 97 insertions(+), 19 deletions(-) diff --git a/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue b/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue index 554e73a2cf..43b6dddd6b 100644 --- a/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue +++ b/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue @@ -90,6 +90,9 @@ import { collectErrorsInEditor, refreshEditor, scrollToLineAndHighlight, updatePlaceHolder, ERROR_TYPE } from './handler' import { AGGREGATE_TYPE } from '../../../config' vuex.registerModule(['modals', 'RecognizeAggregateModal'], store) + + const TABLE_INDEX = 'TABLE_INDEX' + @Component({ components: { AceEditor, @@ -115,7 +118,8 @@ 'hierarchies', 'hierarchyItems', 'joints', - 'jointItems' + 'jointItems', + 'tableIndexCols' ]) }, methods: { @@ -149,7 +153,11 @@ } get errorCount () { const { errorInEditor } = this - return errorInEditor.filter(line => [ERROR_TYPE.COLUMN_NOT_IN_MODEL, ERROR_TYPE.COLUMN_NOT_IN_INCLUDES].includes(line.type)).length + return errorInEditor.filter(line => [ + ERROR_TYPE.COLUMN_NOT_IN_MODEL, + ERROR_TYPE.COLUMN_NOT_IN_INCLUDES, + ERROR_TYPE.COLUMN_USED_IN_OTHER + ].includes(line.type)).length } get repeatCount () { const { errorInEditor } = this @@ -176,12 +184,13 @@ return selectedDimensionCount && !isSelectAll } isColumnUsedInCurrent (column) { - const { type, includes, mandatories, hierarchyItems, jointItems } = this + const { type, includes, mandatories, hierarchyItems, jointItems, tableIndexCols } = this switch (type) { case AGGREGATE_TYPE.INCLUDE: return includes.includes(column) case AGGREGATE_TYPE.MANDATORY: return mandatories.includes(column) case AGGREGATE_TYPE.HIERARCHY: return hierarchyItems.includes(column) case AGGREGATE_TYPE.JOINT: return jointItems.includes(column) + case TABLE_INDEX: return tableIndexCols.includes(column) default: return false } } @@ -223,6 +232,8 @@ return this.$t('columnNotInIncludes', { column }) case ERROR_TYPE.COLUMN_DUPLICATE: return this.$t('columnDuplicate', { column }) + case ERROR_TYPE.COLUMN_USED_IN_OTHER: + return this.$t('columnUsedInOther', { column }) default: return 'Unknow Error' } } @@ -262,14 +273,12 @@ {this.$t('inputPlaceholder1')} <el-tooltip popperClass="recognize-aggregate-placeholder-tooltip" - content={( - <ul> - <li>{this.$t('inputPlaceholderTooltip1')}</li> - <li>{this.$t('inputPlaceholderTooltip2')}</li> - </ul> - )} placement="top" > + <ul slot="content"> + <li>{this.$t('inputPlaceholderTooltip1')}</li> + <li>{this.$t('inputPlaceholderTooltip2')}</li> + </ul> <span class="how-to-use">{this.$t('inputPlaceholderTooltipTrigger')}</span> </el-tooltip> </div> @@ -323,7 +332,7 @@ if (columnText) { const dimension = modelDimensions.find(d => d.column === columnText) if (dimension) { - if (type !== AGGREGATE_TYPE.INCLUDE && !this.isColumnInIncludes(dimension.column)) { + if (![AGGREGATE_TYPE.INCLUDE, TABLE_INDEX].includes(type) && !this.isColumnInIncludes(dimension.column)) { this.setNotInIncludesError(dimension.column) } else if (!this.isColumnUsedInOther(dimension.column)) { const duplicate = dimensions.some(d => d.value === dimension.column) diff --git a/kystudio/src/components/common/RecognizeAggregateModal/handler.js b/kystudio/src/components/common/RecognizeAggregateModal/handler.js index f8cdc0d6e8..db4eb83cf2 100644 --- a/kystudio/src/components/common/RecognizeAggregateModal/handler.js +++ b/kystudio/src/components/common/RecognizeAggregateModal/handler.js @@ -8,7 +8,8 @@ const dom = acequire('ace/lib/dom') export const ERROR_TYPE = { COLUMN_NOT_IN_MODEL: 'columnNotInModel', COLUMN_NOT_IN_INCLUDES: 'columnNotInIncludes', - COLUMN_DUPLICATE: 'columnDuplicate' + COLUMN_DUPLICATE: 'columnDuplicate', + COLUMN_USED_IN_OTHER: 'columnUsedInOther' } export function $updatePlaceholder (editor, renderPlaceholder) { @@ -83,7 +84,7 @@ export function searchColumnInEditor (editor, column) { } export function collectErrorsInEditor (errors, editor) { - const { notInModel, duplicate, notInIncludes } = errors + const { notInModel, duplicate, notInIncludes, usedInOthers } = errors let errorInEditor = [] let errorLines = [] @@ -112,6 +113,14 @@ export function collectErrorsInEditor (errors, editor) { })] } + for (const column of usedInOthers) { + const usedInOtherRanges = searchColumnInEditor(editor, column) + errorInEditor = [...errorInEditor, ...usedInOtherRanges.map(r => { + errorLines.push(r.start.row) + return { row: r.start.row, column, type: ERROR_TYPE.COLUMN_USED_IN_OTHER } + })] + } + errorLines = errorLines.sort() return { errorInEditor, errorLines } diff --git a/kystudio/src/components/studio/StudioModel/ModelList/AggregateModal/index.vue b/kystudio/src/components/studio/StudioModel/ModelList/AggregateModal/index.vue index 7ad21f77b9..a53beaa4f0 100644 --- a/kystudio/src/components/studio/StudioModel/ModelList/AggregateModal/index.vue +++ b/kystudio/src/components/studio/StudioModel/ModelList/AggregateModal/index.vue @@ -191,6 +191,14 @@ <common-tip placement="right" :content="$t('hierarchyDesc')"> <i class="el-ksd-icon-more_info_16"></i> </common-tip> + <span class="row ksd-fright ky-no-br-space"> + <el-button + plain class="ksd-ml-10" size="mini" + @click="handleHierarchyRecognize(AGGREGATE_TYPE.HIERARCHY, aggregateIdx)" + > + {{$t('textRecognition')}} + </el-button> + </span> </h2> <div class="list" v-for="(hierarchy, hierarchyRowIdx) in aggregate.hierarchyArray" @@ -229,6 +237,14 @@ <common-tip placement="right" :content="$t('jointDesc')"> <i class="el-ksd-icon-more_info_16"></i> </common-tip> + <span class="row ksd-fright ky-no-br-space"> + <el-button + plain class="ksd-ml-10" size="mini" + @click="handleJointRecognize(AGGREGATE_TYPE.JOINT, aggregateIdx)" + > + {{$t('textRecognition')}} + </el-button> + </span> </h2> <div class="list" v-for="(joint, jointRowIdx) in aggregate.jointArray" @@ -1033,11 +1049,11 @@ export default class AggregateModal extends Vue { this.aggregateStyle = [] }) } - handleAddDimensionRow (path, id) { + handleAddDimensionRow (path, id, items = []) { const rootKey = path.split('.')[0] const dimensionRows = get(this.form, path) const newId = dimensionRows.length - const newDimensionRow = { id: newId, items: [] } + const newDimensionRow = { id: newId, items } this.setModalForm({[rootKey]: push(this.form, path, newDimensionRow)[rootKey]}) this.isWaitingCheckCuboids[id] = true this.isWaitingCheckAllCuboids = true @@ -1126,22 +1142,46 @@ export default class AggregateModal extends Vue { } }) } - async handleIncludesRecognize (type, aggregateIdx, groupIdx = 0) { + async handleIncludesRecognize (type, aggregateIdx) { const { model, form } = this const { aggregateArray = [] } = form const aggregate = aggregateArray[aggregateIdx] - const selectedColumns = await this.callRecognizeAggregateModal({ type, model, aggregate, groupIdx }) + const selectedColumns = await this.callRecognizeAggregateModal({ type, model, aggregate }) const value = [...aggregate.includes, ...selectedColumns] this.handleInput(`aggregateArray.${aggregateIdx}.includes`, value, aggregate.id) } - async handleMandatoryRecognize (type, aggregateIdx, groupIdx = 0) { + async handleMandatoryRecognize (type, aggregateIdx) { const { model, form } = this const { aggregateArray = [] } = form const aggregate = aggregateArray[aggregateIdx] - const selectedColumns = await this.callRecognizeAggregateModal({ type, model, aggregate, groupIdx }) + const selectedColumns = await this.callRecognizeAggregateModal({ type, model, aggregate }) const value = [...aggregate.mandatory, ...selectedColumns] this.handleInput(`aggregateArray.${aggregateIdx}.mandatory`, value, aggregate.id) } + async handleHierarchyRecognize (type, aggregateIdx) { + const { model, form } = this + const { aggregateArray = [] } = form + const aggregate = aggregateArray[aggregateIdx] + const value = await this.callRecognizeAggregateModal({ type, model, aggregate }) + const emptyArrayIdx = aggregate.hierarchyArray.findIndex(array => array.items.length === 0) + if (emptyArrayIdx !== -1) { + this.handleInput(`aggregateArray.${aggregateIdx}.hierarchyArray.${emptyArrayIdx}.items`, value, aggregate.id) + } else { + this.handleAddDimensionRow(`aggregateArray.${aggregateIdx}.hierarchyArray`, aggregate.id, value) + } + } + async handleJointRecognize (type, aggregateIdx) { + const { model, form } = this + const { aggregateArray = [] } = form + const aggregate = aggregateArray[aggregateIdx] + const value = await this.callRecognizeAggregateModal({ type, model, aggregate }) + const emptyArrayIdx = aggregate.jointArray.findIndex(array => array.items.length === 0) + if (emptyArrayIdx !== -1) { + this.handleInput(`aggregateArray.${aggregateIdx}.jointArray.${emptyArrayIdx}.items`, value, aggregate.id) + } else { + this.handleAddDimensionRow(`aggregateArray.${aggregateIdx}.jointArray`, aggregate.id, value) + } + } handleRemoveAllIncludes (aggregateIdx, titleId, id) { kylinConfirm(this.$t('clearAllAggregateTip', {aggId: titleId}), {type: 'warning'}, this.$t('clearAggregateTitle')).then(() => { const { aggregateArray = [] } = this.form @@ -2210,7 +2250,7 @@ export default class AggregateModal extends Vue { position: absolute; right: 6px; top: 0; - transform: translateY(2px); + transform: translateY(12px); .is-text { font-size: 24px; border: 0; diff --git a/kystudio/src/components/studio/StudioModel/TableIndexEdit/locales.js b/kystudio/src/components/studio/StudioModel/TableIndexEdit/locales.js index 031267a13a..45109240d4 100644 --- a/kystudio/src/components/studio/StudioModel/TableIndexEdit/locales.js +++ b/kystudio/src/components/studio/StudioModel/TableIndexEdit/locales.js @@ -29,6 +29,7 @@ export default { indexTimeRange: 'Index’s Time Range', indexTimeRangeTips: 'The data range that the indexes will be built in. With "Batch and Streaming" selected, there will be generated batch indexes and streaming indexes with same content respectively. ', noIndexRangeByHybrid: 'Select index’s data range to display available columns.', + textRecognition: 'Text Recognition', refuseAddIndexTip: 'Can\'t add streaming indexes. Please stop the streaming job and then delete all the streaming segments.' } } diff --git a/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue b/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue index c34a90dcc0..946ac5ee48 100644 --- a/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue +++ b/kystudio/src/components/studio/StudioModel/TableIndexEdit/tableindex_edit.vue @@ -29,6 +29,9 @@ </el-alert> <template v-if="modelInstance.model_type !== 'HYBRID' || modelInstance.model_type === 'HYBRID' && tableIndexMeta.index_range"> <p class="anit-table-tips" v-if="hasManyToManyAndAntiTable">{{$t('manyToManyAntiTableTip')}}</p> + <el-button plain class="ksd-ml-10" size="mini" @click="handleTableIndexRecognize"> + {{$t('textRecognition')}} + </el-button> <el-input v-model="searchColumn" size="medium" prefix-icon="el-ksd-icon-search_22" style="width:200px" :placeholder="$t('filterByColumns')"></el-input> </template> </div> @@ -118,6 +121,9 @@ hideModal: types.HIDE_MODAL, setModalForm: types.SET_MODAL_FORM, resetModalForm: types.RESET_MODAL_FORM + }), + ...mapActions('RecognizeAggregateModal', { + callRecognizeAggregateModal: types.CALL_MODAL }) }, locales @@ -349,6 +355,19 @@ this.$message({message: tipMsg, type: 'success'}) } } + async handleTableIndexRecognize () { + const selectedColumns = await this.callRecognizeAggregateModal({ + type: 'TABLE_INDEX', + allColumns: this.allColumns, + model: this.modelInstance + }) + this.allColumns.forEach((col) => { + if (selectedColumns.includes(col.fullName)) { + col.isUsed = true + } + }) + this.selectTableIndex() + } confirmSubmit (isLoadData) { this.isLoadDataLoading = isLoadData this.btnLoading = true