| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.carbondata.core.scan.model; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.apache.carbondata.core.datastore.block.TableBlockInfo; |
| import org.apache.carbondata.core.index.IndexFilter; |
| import org.apache.carbondata.core.metadata.AbsoluteTableIdentifier; |
| import org.apache.carbondata.core.metadata.schema.table.CarbonTable; |
| import org.apache.carbondata.core.metadata.schema.table.column.CarbonColumn; |
| import org.apache.carbondata.core.metadata.schema.table.column.CarbonDimension; |
| import org.apache.carbondata.core.metadata.schema.table.column.CarbonMeasure; |
| import org.apache.carbondata.core.scan.expression.ColumnExpression; |
| import org.apache.carbondata.core.scan.expression.Expression; |
| import org.apache.carbondata.core.scan.expression.UnknownExpression; |
| import org.apache.carbondata.core.scan.expression.conditional.ConditionalExpression; |
| import org.apache.carbondata.core.stats.QueryStatisticsRecorder; |
| import org.apache.carbondata.core.util.CarbonProperties; |
| import org.apache.carbondata.core.util.CarbonUtil; |
| import org.apache.carbondata.core.util.DataTypeConverter; |
| |
| /** |
| * Query model which will have all the detail |
| * about the query, This will be sent from driver to executor ' |
| * This will be refereed to executing the query. |
| */ |
| public class QueryModel { |
| |
| /** |
| * list of projection columns in query |
| */ |
| private QueryProjection projection; |
| /** |
| * query id |
| */ |
| private String queryId; |
| |
| /** |
| * filter expression tree |
| */ |
| private IndexFilter indexFilter; |
| |
| /** |
| * table block information in which query will be executed |
| */ |
| private List<TableBlockInfo> tableBlockInfos; |
| /** |
| * To handle most of the computation in query engines like spark and hive, carbon should give |
| * raw detailed records to it. |
| */ |
| private boolean forcedDetailRawQuery; |
| /** |
| * table on which query will be executed |
| * TODO need to remove this ad pass only the path |
| * and carbon metadata will load the table from metadata file |
| */ |
| private CarbonTable table; |
| |
| private QueryStatisticsRecorder statisticsRecorder; |
| |
| private boolean vectorReader; |
| |
| private DataTypeConverter converter; |
| |
| private boolean[] isFilterDimensions; |
| private boolean[] isFilterMeasures; |
| |
| /** |
| * Read the data from carbondata file page by page instead of whole blocklet. |
| */ |
| private boolean readPageByPage; |
| |
| /** |
| * whether it require to output the row id |
| */ |
| private boolean requiredRowId; |
| |
| /** |
| * whether it is FG with search mode |
| */ |
| private boolean isFG; |
| |
| // whether to clear/free unsafe memory or not |
| private boolean freeUnsafeMemory = true; |
| |
| private boolean preFetchData; |
| |
| /** |
| * It fills the vector directly from decoded column page with out any staging and conversions. |
| * Execution engine can set this filed to true in case of vector flow. Note that execution engine |
| * should make sure that batch size vector should be greater than or equal to column page size. |
| * In this flow only pages will be pruned and decode the page and fill the complete page data to |
| * vector, so it is execution engine responsibility to filter the rows at row level. |
| */ |
| private boolean isDirectVectorFill; |
| |
| /** |
| * It is used to read only the deleted data of a particular version. It will be used to get the |
| * old updated/deleted data before update. |
| */ |
| private boolean readOnlyDelta; |
| |
| private QueryModel(CarbonTable carbonTable) { |
| tableBlockInfos = new ArrayList<TableBlockInfo>(); |
| this.table = carbonTable; |
| this.queryId = String.valueOf(System.nanoTime()); |
| this.preFetchData = CarbonProperties.getQueryPrefetchEnable(); |
| } |
| |
| public static QueryModel newInstance(CarbonTable carbonTable) { |
| return new QueryModel(carbonTable); |
| } |
| |
| public static void processFilterExpression(FilterProcessVO processVO, Expression filterExpression, |
| final boolean[] isFilterDimensions, final boolean[] isFilterMeasures, |
| CarbonTable carbonTable) { |
| if (null != filterExpression) { |
| if (null != filterExpression.getChildren() && filterExpression.getChildren().size() == 0) { |
| if (filterExpression instanceof ConditionalExpression) { |
| List<ColumnExpression> listOfCol = |
| ((ConditionalExpression) filterExpression).getColumnList(); |
| for (ColumnExpression expression : listOfCol) { |
| setDimAndMsrColumnNode(processVO, expression, isFilterDimensions, isFilterMeasures, |
| carbonTable); |
| } |
| } |
| } |
| for (Expression expression : filterExpression.getChildren()) { |
| if (expression instanceof ColumnExpression) { |
| setDimAndMsrColumnNode(processVO, (ColumnExpression) expression, isFilterDimensions, |
| isFilterMeasures, carbonTable); |
| } else if (expression instanceof UnknownExpression) { |
| UnknownExpression exp = ((UnknownExpression) expression); |
| List<ColumnExpression> listOfColExpression = exp.getAllColumnList(); |
| for (ColumnExpression col : listOfColExpression) { |
| setDimAndMsrColumnNode(processVO, col, isFilterDimensions, isFilterMeasures, |
| carbonTable); |
| } |
| } else { |
| processFilterExpression(processVO, expression, isFilterDimensions, isFilterMeasures, |
| carbonTable); |
| } |
| } |
| } |
| |
| } |
| |
| private static CarbonMeasure getCarbonMetadataMeasure(String name, List<CarbonMeasure> measures) { |
| for (CarbonMeasure measure : measures) { |
| if (measure.getColName().equalsIgnoreCase(name)) { |
| return measure; |
| } |
| } |
| return null; |
| } |
| |
| private static void setDimAndMsrColumnNode(FilterProcessVO processVO, ColumnExpression col, |
| boolean[] isFilterDimensions, boolean[] isFilterMeasures, CarbonTable table) { |
| CarbonDimension dim; |
| CarbonMeasure msr; |
| String columnName; |
| columnName = col.getColumnName(); |
| col.reset(); |
| dim = CarbonUtil |
| .findDimension(processVO.getCarbonDimensions(), columnName); |
| msr = getCarbonMetadataMeasure(columnName, processVO.getCarbonMeasures()); |
| |
| if (null != dim) { |
| // Dimension Column |
| col.setCarbonColumn(dim); |
| col.setDimension(dim); |
| col.setDimension(true); |
| if (null != isFilterDimensions) { |
| isFilterDimensions[dim.getOrdinal()] = true; |
| } |
| } else if (msr != null) { |
| col.setCarbonColumn(msr); |
| col.setMeasure(msr); |
| col.setMeasure(true); |
| if (null != isFilterMeasures) { |
| isFilterMeasures[msr.getOrdinal()] = true; |
| } |
| } else if (null != CarbonUtil.findDimension(processVO.getImplicitDimensions(), columnName)) { |
| // check if this is an implicit dimension |
| dim = CarbonUtil.findDimension(processVO.getImplicitDimensions(), columnName); |
| col.setCarbonColumn(dim); |
| col.setDimension(dim); |
| col.setDimension(true); |
| } else { |
| // in case of sdk or file format, there can be chance that each carbondata file may have |
| // different schema, so every segment properties will have dims and measures based on |
| // corresponding segment. So the filter column may not be present in it. so generate the |
| // dimension and measure from the carbon table |
| CarbonDimension dimension = |
| table.getDimensionByName(col.getColumnName()); |
| CarbonMeasure measure = table.getMeasureByName(col.getColumnName()); |
| col.setDimension(dimension); |
| col.setMeasure(measure); |
| col.setCarbonColumn(dimension == null ? measure : dimension); |
| col.setDimension(null != dimension); |
| col.setMeasure(null != measure); |
| } |
| } |
| |
| /** |
| * It gets the projection columns |
| */ |
| public CarbonColumn[] getProjectionColumns() { |
| CarbonColumn[] carbonColumns = |
| new CarbonColumn[getProjectionDimensions().size() + getProjectionMeasures().size()]; |
| for (ProjectionDimension dimension : getProjectionDimensions()) { |
| carbonColumns[dimension.getOrdinal()] = dimension.getDimension(); |
| } |
| for (ProjectionMeasure msr : getProjectionMeasures()) { |
| carbonColumns[msr.getOrdinal()] = msr.getMeasure(); |
| } |
| return carbonColumns; |
| } |
| |
| public void setProjection(QueryProjection projection) { |
| this.projection = projection; |
| } |
| |
| public List<ProjectionDimension> getProjectionDimensions() { |
| return projection.getDimensions(); |
| } |
| |
| public List<ProjectionMeasure> getProjectionMeasures() { |
| return projection.getMeasures(); |
| } |
| |
| /** |
| * @return the queryId |
| */ |
| public String getQueryId() { |
| return queryId; |
| } |
| |
| public void setQueryId(String queryId) { |
| this.queryId = queryId; |
| } |
| |
| /** |
| * @return the tableBlockInfos |
| */ |
| public List<TableBlockInfo> getTableBlockInfos() { |
| return tableBlockInfos; |
| } |
| |
| /** |
| * @param tableBlockInfos the tableBlockInfos to set |
| */ |
| public void setTableBlockInfos(List<TableBlockInfo> tableBlockInfos) { |
| this.tableBlockInfos = tableBlockInfos; |
| } |
| |
| public IndexFilter getIndexFilter() { |
| return indexFilter; |
| } |
| |
| public void setIndexFilter(IndexFilter indexFilter) { |
| this.indexFilter = indexFilter; |
| } |
| |
| /** |
| * @return the absoluteTableIdentifier |
| */ |
| public AbsoluteTableIdentifier getAbsoluteTableIdentifier() { |
| return table.getAbsoluteTableIdentifier(); |
| } |
| |
| /** |
| * @return the table |
| */ |
| public CarbonTable getTable() { |
| return table; |
| } |
| |
| public boolean isForcedDetailRawQuery() { |
| return forcedDetailRawQuery; |
| } |
| |
| public void setForcedDetailRawQuery(boolean forcedDetailRawQuery) { |
| this.forcedDetailRawQuery = forcedDetailRawQuery; |
| } |
| |
| public QueryStatisticsRecorder getStatisticsRecorder() { |
| return statisticsRecorder; |
| } |
| |
| public void setStatisticsRecorder(QueryStatisticsRecorder statisticsRecorder) { |
| this.statisticsRecorder = statisticsRecorder; |
| } |
| |
| public boolean isVectorReader() { |
| return vectorReader; |
| } |
| |
| public void setVectorReader(boolean vectorReader) { |
| this.vectorReader = vectorReader; |
| } |
| |
| public DataTypeConverter getConverter() { |
| return converter; |
| } |
| |
| public void setConverter(DataTypeConverter converter) { |
| this.converter = converter; |
| } |
| |
| public boolean[] getIsFilterDimensions() { |
| return isFilterDimensions; |
| } |
| |
| public void setIsFilterDimensions(boolean[] isFilterDimensions) { |
| this.isFilterDimensions = isFilterDimensions; |
| } |
| |
| public boolean[] getIsFilterMeasures() { |
| return isFilterMeasures; |
| } |
| |
| public void setIsFilterMeasures(boolean[] isFilterMeasures) { |
| this.isFilterMeasures = isFilterMeasures; |
| } |
| |
| public boolean isReadPageByPage() { |
| return readPageByPage; |
| } |
| |
| public void setReadPageByPage(boolean readPageByPage) { |
| this.readPageByPage = readPageByPage; |
| } |
| |
| public boolean isRequiredRowId() { |
| return requiredRowId; |
| } |
| |
| public void setRequiredRowId(boolean requiredRowId) { |
| this.requiredRowId = requiredRowId; |
| } |
| |
| public boolean isFG() { |
| return isFG; |
| } |
| |
| public void setFG(boolean FG) { |
| isFG = FG; |
| } |
| |
| public boolean isPreFetchData() { |
| return preFetchData; |
| } |
| |
| public void setPreFetchData(boolean preFetchData) { |
| this.preFetchData = preFetchData; |
| } |
| |
| public boolean isDirectVectorFill() { |
| return isDirectVectorFill; |
| } |
| |
| public void setDirectVectorFill(boolean directVectorFill) { |
| isDirectVectorFill = directVectorFill; |
| } |
| |
| public boolean isReadOnlyDelta() { |
| return readOnlyDelta; |
| } |
| |
| public void setReadOnlyDelta(boolean readOnlyDelta) { |
| this.readOnlyDelta = readOnlyDelta; |
| } |
| |
| @Override |
| public String toString() { |
| return String.format("scan on table %s.%s, %d projection columns with filter (%s)", |
| table.getDatabaseName(), table.getTableName(), |
| projection.getDimensions().size() + projection.getMeasures().size(), |
| indexFilter.getExpression().toString()); |
| } |
| |
| public boolean isFreeUnsafeMemory() { |
| return freeUnsafeMemory; |
| } |
| |
| public void setFreeUnsafeMemory(boolean freeUnsafeMemory) { |
| this.freeUnsafeMemory = freeUnsafeMemory; |
| } |
| |
| public static class FilterProcessVO { |
| |
| private List<CarbonDimension> carbonDimensions; |
| |
| private List<CarbonMeasure> carbonMeasures; |
| |
| private List<CarbonDimension> implicitDimensions; |
| |
| public FilterProcessVO(List<CarbonDimension> carbonDimensions, |
| List<CarbonMeasure> carbonMeasures, List<CarbonDimension> implicitDimensions) { |
| this.carbonDimensions = carbonDimensions; |
| this.carbonMeasures = carbonMeasures; |
| this.implicitDimensions = implicitDimensions; |
| } |
| |
| public List<CarbonDimension> getCarbonDimensions() { |
| return carbonDimensions; |
| } |
| |
| public List<CarbonMeasure> getCarbonMeasures() { |
| return carbonMeasures; |
| } |
| |
| public List<CarbonDimension> getImplicitDimensions() { |
| return implicitDimensions; |
| } |
| } |
| } |