com.baidu.rigel.biplatform.tesseract.qsservice.query.impl.QueryContextSplitServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.baidu.rigel.biplatform.tesseract.qsservice.query.impl.QueryContextSplitServiceImpl.java

Source

/**
 * Copyright (c) 2014 Baidu, Inc. All Rights Reserved.
 *
 * Licensed 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 com.baidu.rigel.biplatform.tesseract.qsservice.query.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.baidu.rigel.biplatform.ac.minicube.ExtendMinicubeMeasure;
import com.baidu.rigel.biplatform.ac.minicube.MiniCubeMeasure;
import com.baidu.rigel.biplatform.ac.model.Aggregator;
import com.baidu.rigel.biplatform.ac.model.Cube;
import com.baidu.rigel.biplatform.ac.model.MeasureType;
import com.baidu.rigel.biplatform.ac.query.data.DataModel;
import com.baidu.rigel.biplatform.ac.query.data.DataModel.FillDataType;
import com.baidu.rigel.biplatform.ac.query.data.DataSourceInfo;
import com.baidu.rigel.biplatform.ac.query.data.HeadField;
import com.baidu.rigel.biplatform.ac.query.model.QuestionModel;
import com.baidu.rigel.biplatform.ac.util.DataModelUtils;
import com.baidu.rigel.biplatform.ac.util.DeepcopyUtils;
import com.baidu.rigel.biplatform.ac.util.MetaNameUtil;
import com.baidu.rigel.biplatform.ac.util.PlaceHolderUtils;
import com.baidu.rigel.biplatform.parser.CompileExpression;
import com.baidu.rigel.biplatform.parser.context.CompileContext;
import com.baidu.rigel.biplatform.parser.context.Condition;
import com.baidu.rigel.biplatform.parser.context.EmptyCondition;
import com.baidu.rigel.biplatform.parser.result.ComputeResult;
import com.baidu.rigel.biplatform.parser.result.ListComputeResult;
import com.baidu.rigel.biplatform.parser.util.ConditionUtil;
import com.baidu.rigel.biplatform.tesseract.dataquery.udf.condition.CallbackCondition;
import com.baidu.rigel.biplatform.tesseract.dataquery.udf.condition.ParseCoditionUtils;
import com.baidu.rigel.biplatform.tesseract.exception.IllegalSplitResultException;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.QueryContextBuilder;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.QueryContextSplitService;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.vo.QueryContext;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.vo.QueryContextSplitResult;
import com.baidu.rigel.biplatform.tesseract.util.DataModelBuilder;

/**
 * 
 * 
 * @author xiaoming.chen
 *
 */
@Service
public class QueryContextSplitServiceImpl implements QueryContextSplitService {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    private static final String NONE = "NONE";

    @Resource
    private QueryContextBuilder queryContextBuilder;

    @Override
    public QueryContextSplitResult split(QuestionModel question, DataSourceInfo dsInfo, Cube cube,
            QueryContext queryContext, QueryContextSplitStrategy preSplitStrategy) {
        QueryContextSplitStrategy splitStrategy = QueryContextSplitStrategy.getNextStrategy(preSplitStrategy);
        // ??????
        if (splitStrategy != null) {
            if (splitStrategy.equals(QueryContextSplitStrategy.MeasureType)) {
                return splitByMeasureTypeStrategy(question, dsInfo, cube, queryContext);
                //            } else if (splitStrategy.equals(QueryContextSplitStrategy.Column)) {
                //                return splitByColumnStrategy(queryContext);
                //            } else {
                //                return splitByRowStrategy(queryContext);
            }
        }
        return null;
    }

    /**
     * @param cube
     * @param queryContext
     * @return
     */
    private QueryContextSplitResult splitByMeasureTypeStrategy(QuestionModel question, DataSourceInfo dsInfo,
            Cube cube, QueryContext queryContext) {
        QueryContextSplitResult result = new QueryContextSplitResult(QueryContextSplitStrategy.MeasureType,
                queryContext);
        // ?
        if (CollectionUtils.isNotEmpty(queryContext.getQueryMeasures())) {
            Set<String> callbackMeasureName = new HashSet<String>();
            CompileContext compileContext = null;
            for (Iterator<MiniCubeMeasure> it = queryContext.getQueryMeasures().iterator(); it.hasNext();) {
                MiniCubeMeasure measure = it.next();
                // ?
                if (measure.getAggregator().equals(Aggregator.CALCULATED)) {
                    if (measure.getType().equals(MeasureType.CALLBACK)) {
                        callbackMeasureName.add(measure.getUniqueName());
                    } else {
                        ExtendMinicubeMeasure extendMeasure = (ExtendMinicubeMeasure) measure;
                        compileContext = CompileExpression.compile(extendMeasure.getFormula());
                        result.getCompileContexts().put(measure.getUniqueName(), compileContext);
                    }
                    it.remove();
                }
            }
            // ?
            Map<Condition, Set<String>> conditions = ConditionUtil
                    .simpleMergeContexsCondition(result.getCompileContexts().values());
            if (CollectionUtils.isNotEmpty(callbackMeasureName)) {
                conditions.put(CallbackCondition.getInstance(), callbackMeasureName);
            }
            if (!queryContext.getQueryMeasures().isEmpty()) {
                if (!conditions.containsKey(EmptyCondition.getInstance())) {
                    conditions.put(EmptyCondition.getInstance(), new HashSet<>());
                }
                for (MiniCubeMeasure m : queryContext.getQueryMeasures()) {
                    if (!conditions.get(EmptyCondition.getInstance()).contains(m.getName())) {
                        conditions.get(EmptyCondition.getInstance()).add(m.getName());
                    }
                }

            }

            if (MapUtils.isNotEmpty(conditions)) {
                conditions.forEach((con, vars) -> {
                    QueryContext context = con.processCondition(ParseCoditionUtils.decorateQueryContext(
                            DeepcopyUtils.deepCopy(queryContext), question, cube, dsInfo, queryContextBuilder));
                    context.getQueryMeasures().clear();
                    for (String var : vars) {
                        MiniCubeMeasure measure = null;
                        if (MetaNameUtil.isUniqueName(var)) {
                            String name = MetaNameUtil.parseUnique2NameArray(var)[1];
                            measure = (MiniCubeMeasure) cube.getMeasures().get(name);
                        } else {
                            measure = (MiniCubeMeasure) cube.getMeasures()
                                    .get(PlaceHolderUtils.getKeyFromPlaceHolder(var));
                        }
                        if (measure == null) {
                            throw new IllegalSplitResultException(result,
                                    "can not get measure:" + var + " from cube", "SPILT_QUESTION");
                        }
                        if (!context.getQueryMeasures().contains(measure)) {
                            context.getQueryMeasures().add(measure);
                        }
                    }
                    result.getConditionQueryContext().put(con, context);

                });
            }
        }

        return result;
    }

    /**
     * @param queryContext
     * @return
     */
    //    private QueryContextSplitResult splitByColumnStrategy(QueryContext queryContext) {
    //        QueryContextSplitResult result = new QueryContextSplitResult(QueryContextSplitStrategy.Column, queryContext);
    //        
    //        if (CollectionUtils.isNotEmpty(queryContext.getColumnMemberTrees())) {
    //            for (int i = 0; i < queryContext.getColumnMemberTrees().size(); i++) {
    //                // TODO ?QueryContext
    //            }
    //        }
    //        return result;
    //    }
    //
    //    /**
    //     * @param queryContext
    //     * @return
    //     */
    //    private QueryContextSplitResult splitByRowStrategy(QueryContext queryContext) {
    //        QueryContextSplitResult result = new QueryContextSplitResult(QueryContextSplitStrategy.Row, queryContext);
    //
    //        if (CollectionUtils.isNotEmpty(queryContext.getRowMemberTrees())) {
    //            for (int i = 0; i < queryContext.getRowMemberTrees().size(); i++) {
    //                // TODO ?QueryContext
    //            }
    //        }
    //        return result;
    //    }

    /*
     * (non-Javadoc) 
     * @see com.baidu.rigel.biplatform.tesseract.qsservice.query.QueryContextSplitService#mergeDataModel(com.baidu.rigel.biplatform.tesseract.qsservice.query.vo.QueryContextSplitResult) 
     */
    @Override
    public DataModel mergeDataModel(QueryContextSplitResult splitResult) {
        long current = System.currentTimeMillis();
        if (splitResult == null
                || splitResult.getConditionQueryContext().size() != splitResult.getDataModels().size()) {
            throw new IllegalSplitResultException(splitResult, "splitResult is null or condition size not equal",
                    "MERGE_MODEL");
        }

        DataModel dataModel = new DataModel();
        dataModel.setColumnHeadFields(
                DataModelBuilder.buildAxisHeadFields(splitResult.getOriQueryContext().getColumnMemberTrees(),
                        splitResult.getOriQueryContext().getQueryMeasures()));
        dataModel.setRowHeadFields(
                DataModelBuilder.buildAxisHeadFields(splitResult.getOriQueryContext().getRowMemberTrees(), null));
        List<HeadField> rowLeafs = DataModelUtils.getLeafNodeList(dataModel.getRowHeadFields());

        // ?UniqueNameUniqueName?
        Map<Condition, Map<String, Map<String, List<BigDecimal>>>> dataModelDatas = new HashMap<Condition, Map<String, Map<String, List<BigDecimal>>>>(
                splitResult.getDataModels().size());
        if (!dataModelDatas.containsKey(EmptyCondition.getInstance())) {
            dataModelDatas.put(EmptyCondition.getInstance(), new HashMap<>());
        }
        splitResult.getDataModels().forEach((con, dm) -> {
            boolean isCallbackCondition = con.equals(CallbackCondition.getInstance());
            con = isCallbackCondition ? EmptyCondition.getInstance() : con;
            // ??
            DataModelUtils.fillFieldData(dm, FillDataType.COLUMN);
            List<HeadField> columnFields = DataModelUtils.getLeafNodeList(dm.getColumnHeadFields());
            Map<String, Map<String, List<BigDecimal>>> dataModelData = null;
            if (dataModelDatas.containsKey(con)) {
                dataModelData = dataModelDatas.get(con);
            } else {
                dataModelData = new HashMap<String, Map<String, List<BigDecimal>>>();
            }

            // ???
            for (HeadField field : columnFields) {
                if (!dataModelData.containsKey(field.getValue())) {
                    dataModelData.put(field.getValue(), new HashMap<>());
                }
                String parentKey = NONE;
                if (field.getParentLevelField() != null) {
                    parentKey = field.getParentLevelField().getNodeUniqueName();
                }
                dataModelData.get(field.getValue()).put(parentKey, field.getCompareDatas());
            }
            dataModelDatas.put(con, dataModelData);

        });

        // ???
        Map<String, List<BigDecimal>> constantResult = new HashMap<>(1);
        // TODO 
        splitResult.getCompileContexts().forEach((measureName, compileContext) -> {
            Map<String, List<BigDecimal>> calCulateDatas = new HashMap<>();
            Map<String, Map<Condition, Map<String, ComputeResult>>> categoryVariableVal = new HashMap<>();
            if (MapUtils.isNotEmpty(compileContext.getConditionVariables())) {
                for (Entry<Condition, Set<String>> entry : compileContext.getConditionVariables().entrySet()) {
                    Map<String, Map<String, List<BigDecimal>>> dataModelData = dataModelDatas.get(entry.getKey());
                    if (dataModelData == null) {
                        throw new IllegalSplitResultException(splitResult,
                                "dataModel is null by condition" + entry.getKey(), "MERGE_MODEL");
                    }
                    // parentNode uniqueName, varName, data
                    if (CollectionUtils.isNotEmpty(entry.getValue())) {
                        for (String var : entry.getValue()) {
                            String name = MetaNameUtil
                                    .generateMeasureUniqueName(PlaceHolderUtils.getKeyFromPlaceHolder(var));
                            if (!dataModelData.containsKey(name)) {
                                throw new IllegalSplitResultException(splitResult, "miss variable:" + var,
                                        "MERGE_MODEL");
                            }
                            for (String parentNodeUniqueName : dataModelData.get(name).keySet()) {
                                if (!categoryVariableVal.containsKey(parentNodeUniqueName)) {
                                    categoryVariableVal.put(parentNodeUniqueName, new HashMap<>());
                                }
                                if (!categoryVariableVal.get(parentNodeUniqueName).containsKey(entry.getKey())) {
                                    categoryVariableVal.get(parentNodeUniqueName).put(entry.getKey(),
                                            new HashMap<>());
                                }
                                categoryVariableVal.get(parentNodeUniqueName).get(entry.getKey()).put(var,
                                        new ListComputeResult(dataModelData.get(name).get(parentNodeUniqueName)));
                            }
                        }
                    } else {
                        constantResult.put(measureName, ListComputeResult
                                .transfer(compileContext.getNode().getResult(null), rowLeafs.size()).getData());
                    }
                }
                for (String parentName : categoryVariableVal.keySet()) {
                    // ??????
                    compileContext.getVariablesResult().clear();
                    compileContext.setVariablesResult(categoryVariableVal.get(parentName));
                    //                   compileContext.getVariablesResult().put(entry.getKey(), categoryVariableVal.get(parentName));
                    calCulateDatas.put(parentName,
                            ListComputeResult
                                    .transfer(compileContext.getNode().getResult(compileContext), rowLeafs.size())
                                    .getData());
                }
            }

            dataModelDatas.get(EmptyCondition.getInstance()).put(measureName, calCulateDatas);
        });
        mergeDataModelDatas(dataModel, dataModelDatas.get(EmptyCondition.getInstance()), constantResult);
        log.info("merge datamodel cost:{}ms", System.currentTimeMillis() - current);
        return dataModel;
    }

    /** 
     * mergeDataModelDatas
     * @param dataModel
     * @param datas
     * @param constantResult
     */
    private void mergeDataModelDatas(DataModel dataModel, Map<String, Map<String, List<BigDecimal>>> datas,
            Map<String, List<BigDecimal>> constantResult) {
        List<HeadField> rowLeafs = DataModelUtils.getLeafNodeList(dataModel.getRowHeadFields());

        List<HeadField> oriColumnFields = DataModelUtils.getLeafNodeList(dataModel.getColumnHeadFields());
        for (HeadField field : oriColumnFields) {
            if (constantResult.containsKey(field.getValue())) {
                field.setCompareDatas(constantResult.get(field.getValue()));
            } else {
                String pName = NONE;
                if (field.getParentLevelField() != null) {
                    pName = field.getParentLevelField().getNodeUniqueName();
                }
                field.setCompareDatas(datas == null ? null : datas.get(field.getValue()).get(pName));
            }
        }
        //        oriColumnFields.forEach(field -> {
        //            if(constantResult.containsKey(field.getValue())) {
        //                field.setCompareDatas(constantResult.get(field.getValue()));
        //            } else {
        //                String pName = NONE;
        //                if(field.getParentLevelField() != null) {
        //                    pName = field.getParentLevelField().getNodeUniqueName();
        //                }
        //                field.setCompareDatas(datas.get(field.getValue()).get(pName));
        //            }
        //        });

        List<HeadField> columnLeafs = DataModelUtils.getLeafNodeList(dataModel.getColumnHeadFields());
        dataModel.getColumnBaseData().clear();

        for (int i = 0; i < columnLeafs.size(); i++) {
            HeadField rowField = columnLeafs.get(i);
            dataModel.getColumnBaseData().add(rowField.getCompareDatas());
            while (dataModel.getColumnBaseData().get(i).size() < rowLeafs.size()) {
                dataModel.getColumnBaseData().get(i).add(null);
            }
        }

    }

}