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

Java tutorial

Introduction

Here is the source code for com.baidu.rigel.biplatform.tesseract.qsservice.query.impl.QueryServiceImpl.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.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baidu.rigel.biplatform.ac.exception.MiniCubeQueryException;
import com.baidu.rigel.biplatform.ac.minicube.MiniCubeMember;
import com.baidu.rigel.biplatform.ac.model.Cube;
import com.baidu.rigel.biplatform.ac.query.data.DataModel;
import com.baidu.rigel.biplatform.ac.query.data.DataSourceInfo;
import com.baidu.rigel.biplatform.ac.query.model.ConfigQuestionModel;
import com.baidu.rigel.biplatform.ac.query.model.PageInfo;
import com.baidu.rigel.biplatform.ac.query.model.QuestionModel;
import com.baidu.rigel.biplatform.ac.util.MetaNameUtil;
import com.baidu.rigel.biplatform.tesseract.dataquery.udf.condition.CallbackCondition;
import com.baidu.rigel.biplatform.tesseract.datasource.DataSourcePoolService;
import com.baidu.rigel.biplatform.tesseract.exception.MetaException;
import com.baidu.rigel.biplatform.tesseract.exception.OverflowQueryConditionException;
import com.baidu.rigel.biplatform.tesseract.isservice.exception.IndexAndSearchException;
import com.baidu.rigel.biplatform.tesseract.isservice.exception.IndexAndSearchExceptionType;
import com.baidu.rigel.biplatform.tesseract.isservice.search.service.SearchService;
import com.baidu.rigel.biplatform.tesseract.isservice.search.service.impl.CallbackSearchServiceImpl;
import com.baidu.rigel.biplatform.tesseract.meta.MetaDataService;
import com.baidu.rigel.biplatform.tesseract.model.MemberNodeTree;
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.QueryContextSplitService.QueryContextSplitStrategy;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.QueryRequestBuilder;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.QueryService;
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.qsservice.query.vo.QueryRequest;
import com.baidu.rigel.biplatform.tesseract.resultset.isservice.SearchIndexResultSet;
import com.baidu.rigel.biplatform.tesseract.util.DataModelBuilder;
import com.baidu.rigel.biplatform.tesseract.util.QueryRequestUtil;
import com.baidu.rigel.biplatform.tesseract.util.TesseractExceptionUtils;
import com.baidu.rigel.biplatform.tesseract.util.isservice.LogInfoConstants;

/**
 * ?
 * 
 * @author xiaoming.chen
 *
 */
@Service
public class QueryServiceImpl implements QueryService {

    /**
     * Logger
     */
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * searchService
     */
    @Resource
    private SearchService searchService;

    /**
     * metaDataService
     */
    @Resource
    private MetaDataService metaDataService;

    /**
     * dataSourcePoolService
     */
    @Resource
    private DataSourcePoolService dataSourcePoolService;

    /**
     * queryContextSplitService
     */
    @Resource
    private QueryContextSplitService queryContextSplitService;

    @Resource
    private QueryContextBuilder queryContextBuilder;

    @Autowired
    private CallbackSearchServiceImpl callbackSearchService;

    @Override
    public DataModel query(QuestionModel questionModel, QueryContext queryContext,
            QueryContextSplitStrategy preSplitStrategy) throws MiniCubeQueryException {
        long current = System.currentTimeMillis();
        if (questionModel == null) {
            throw new IllegalArgumentException("questionModel is null");
        }
        DataSourceInfo dataSourceInfo = null;
        Cube cube = null;
        // 
        if (questionModel instanceof ConfigQuestionModel) {
            ConfigQuestionModel configQuestionModel = (ConfigQuestionModel) questionModel;
            dataSourceInfo = configQuestionModel.getDataSourceInfo();
            cube = configQuestionModel.getCube();
            // ???cache
            //            questionModel.setUseIndex(false);
        }
        if (cube == null) {
            cube = metaDataService.getCube(questionModel.getCubeId());
        }
        if (dataSourceInfo == null) {
            dataSourceInfo = dataSourcePoolService.getDataSourceInfo(questionModel.getDataSourceInfoKey());
        }
        logger.info("cost :" + (System.currentTimeMillis() - current) + " to get datasource and other data");
        current = System.currentTimeMillis();
        try {
            queryContext = queryContextBuilder.buildQueryContext(questionModel, dataSourceInfo, cube, queryContext);
        } catch (MetaException e1) {
            e1.printStackTrace();
            throw new MiniCubeQueryException(e1);
        }
        logger.info("cost :" + (System.currentTimeMillis() - current) + " to build query context.");
        // ??????
        int conditionDescartes = stateQueryContextConditionCount(queryContext, questionModel.isNeedSummary());
        logger.info("query condition descarte:" + conditionDescartes);
        logger.debug("question model:{}", questionModel);
        if (questionModel.getQueryConditionLimit().isWarningAtOverFlow()
                && conditionDescartes > questionModel.getQueryConditionLimit().getWarnningConditionSize()) {
            StringBuilder sb = new StringBuilder();
            sb.append("condition descartes :").append(conditionDescartes).append(" over :")
                    .append(questionModel.getQueryConditionLimit()).append("");
            logger.error(sb.toString());
            throw new OverflowQueryConditionException(sb.toString());
        }
        // 
        QueryContextSplitResult splitResult = queryContextSplitService.split(questionModel, dataSourceInfo, cube,
                queryContext, preSplitStrategy);
        DataModel result = null;
        //  ?
        // TODO 
        if (splitResult != null && (!splitResult.getCompileContexts().isEmpty()
                || !splitResult.getConditionQueryContext().isEmpty())) {
            DataSourceInfo dsInfo = dataSourceInfo;
            Cube finalCube = cube;
            // TODO ,???
            splitResult.getConditionQueryContext().forEach((con, context) -> {
                DataModel dm = null;
                if (con instanceof CallbackCondition) {
                    try {
                        SearchIndexResultSet resultSet = callbackSearchService.query(context, QueryRequestBuilder
                                .buildQueryRequest(dsInfo, finalCube, context, questionModel.isUseIndex(), null));
                        dm = new DataModelBuilder(resultSet, context).build(true);
                    } catch (Exception e) {
                        logger.error("catch error when process callback measure {}", e.getMessage());
                        throw new RuntimeException(e);
                    }
                } else {
                    dm = executeQuery(dsInfo, finalCube, context, questionModel.isUseIndex(),
                            questionModel.getPageInfo());
                }
                splitResult.getDataModels().put(con, dm);
            });

            result = queryContextSplitService.mergeDataModel(splitResult);
        } else {
            result = executeQuery(dataSourceInfo, cube, queryContext, questionModel.isUseIndex(),
                    questionModel.getPageInfo());
        }
        return result;

    }

    private DataModel executeQuery(DataSourceInfo dataSourceInfo, Cube cube, QueryContext queryContext,
            boolean useIndex, PageInfo pageInfo) throws MiniCubeQueryException {
        long current = System.currentTimeMillis();
        QueryRequest queryRequest = QueryRequestBuilder.buildQueryRequest(dataSourceInfo, cube, queryContext,
                useIndex, pageInfo);
        logger.info("transfer queryContext:{} to queryRequest:{} cost:{} ", queryContext, queryRequest,
                System.currentTimeMillis() - current);
        if (statDimensionNode(queryContext.getRowMemberTrees(), false, false) == 0
                || (statDimensionNode(queryContext.getColumnMemberTrees(), false, false) == 0
                        && CollectionUtils.isEmpty(queryContext.getQueryMeasures()))) {
            return new DataModelBuilder(null, queryContext).build(false);
        }
        logger.info("cost :" + (System.currentTimeMillis() - current) + " to build query request.");
        current = System.currentTimeMillis();
        DataModel result = null;
        try {
            SearchIndexResultSet resultSet = searchService.query(queryRequest);

            if (queryRequest.getGroupBy() != null
                    && CollectionUtils.isNotEmpty(queryRequest.getGroupBy().getGroups())) {
                try {
                    resultSet = QueryRequestUtil.processGroupBy(resultSet, queryRequest, queryContext);
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                    logger.error(String.format(LogInfoConstants.INFO_PATTERN_FUNCTION_EXCEPTION, "query",
                            "[query:" + queryRequest + "]", e));
                    throw new IndexAndSearchException(
                            TesseractExceptionUtils.getExceptionMessage(
                                    IndexAndSearchException.QUERYEXCEPTION_MESSAGE,
                                    IndexAndSearchExceptionType.SEARCH_EXCEPTION),
                            e, IndexAndSearchExceptionType.SEARCH_EXCEPTION);
                }

            }

            result = new DataModelBuilder(resultSet, queryContext).build(false);
        } catch (IndexAndSearchException e) {
            logger.error("query occur when search queryRequest" + queryContext, e);
            throw new MiniCubeQueryException(e);
        }
        logger.info("cost :" + (System.currentTimeMillis() - current) + " to execute query.");
        return result;
    }

    private int stateQueryContextConditionCount(QueryContext context, boolean needSummary) {
        if (context == null) {
            throw new IllegalArgumentException("querycontext is null.");
        }
        // ?
        int rowConditionCount = statDimensionNode(context.getRowMemberTrees(), needSummary, true);
        // ??
        int columnConditionCount = statDimensionNode(context.getColumnMemberTrees(), needSummary, false);

        int filterConditionCount = 1;
        if (MapUtils.isNotEmpty(context.getFilterMemberValues())) {
            for (Set<String> nodeIds : context.getFilterMemberValues().values()) {
                filterConditionCount *= nodeIds.size();
            }
        }

        return rowConditionCount * columnConditionCount * filterConditionCount;
    }

    /**
     * ?????
     * 
     * @param treeNodes
     * @param needSummary
     * @return
     */
    private int statDimensionNode(List<MemberNodeTree> treeNodes, boolean needSummary, boolean isRow) {
        int rowConditionCount = 0;
        if (CollectionUtils.isNotEmpty(treeNodes)) {
            for (MemberNodeTree nodeTree : treeNodes) {
                int dimensionLeafIdCount = 0;
                // name?????
                if (StringUtils.isBlank(nodeTree.getName()) || MetaNameUtil.isAllMemberName(nodeTree.getName())) {
                    // ???????????
                    for (MemberNodeTree child : nodeTree.getChildren()) {
                        // ?????
                        if (isRow && needSummary) {
                            nodeTree.setName(MiniCubeMember.SUMMARY_NODE_NAME);
                            nodeTree.setUniqueName(MiniCubeMember.SUMMARY_NODE_NAME);
                            nodeTree.setCaption(MiniCubeMember.SUMMARY_NODE_CAPTION);
                            nodeTree.setSummary(true);
                            nodeTree.setQuerySource(child.getQuerySource());
                            nodeTree.getLeafIds().addAll(child.getLeafIds());
                        }
                        if (nodeTree.getLeafIds().size() == 1
                                && MetaNameUtil.isAllMemberName(nodeTree.getLeafIds().iterator().next())) {
                            continue;
                        } else {
                            dimensionLeafIdCount += child.getLeafIds().size();
                        }
                    }
                } else {
                    dimensionLeafIdCount = nodeTree.getLeafIds().size();
                }
                if (rowConditionCount == 0) {
                    rowConditionCount = dimensionLeafIdCount;
                } else {
                    // ???dimensionLeafIdCount?0
                    rowConditionCount *= (dimensionLeafIdCount == 0 ? 1 : dimensionLeafIdCount);
                }
            }
        }
        return rowConditionCount;
    }

}