All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alipay.sofa.lookout.server.prom.ql.engine.QueryAnalyzer Maven / Gradle / Ivy

The newest version!
/*
 * 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 com.alipay.sofa.lookout.server.prom.ql.engine;

import com.alipay.sofa.lookout.server.prom.ql.ast.*;
import com.alipay.sofa.lookout.server.prom.ql.value.Series;
import com.alipay.sofa.lookout.server.prom.storage.Storage;
import com.alipay.sofa.lookout.server.prom.storage.query.AggregateStatement;
import com.alipay.sofa.lookout.server.prom.storage.query.Querier;
import com.alipay.sofa.lookout.server.prom.storage.query.QueryStatement;

import java.time.Instant;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicLong;

import static com.alipay.sofa.lookout.server.prom.common.QueryConstants.EXPRESSION_CONTEXT;
import static com.alipay.sofa.lookout.server.prom.ql.engine.Evaluator.LookbackDelta;

/**
 * @author: [email protected]
 * @create: 2019-04-29 18:04
 **/
public class QueryAnalyzer {
    private Storage storage;

    public QueryAnalyzer(Storage storage) {
        this.storage = storage;
    }

    public Analysis analyze(Query query) {
        //user required useNative?
        //1.如果storage不支持,那么跑错,2.如果storage支持,但用户暗示禁止,则不userNative;
        EvalStmt s = (EvalStmt) query.getStmt();
        Analysis analysis = new Analysis();
        analysis.setExpr(s.getExpr());
        //add query hint
        if (s.getExpr() instanceof VectorSelector) {
            query.hints.setVectorSelectQuery(true);
        }

        final AtomicLong maxOffset = new AtomicLong(0);
        Ast.traverses(s.getExpr(), new NodeInspector() {
            @Override
            public boolean inspect(Node node) {
                //for example,"sum(..)"
                if (node instanceof AggregateExpr) {
                    AggregateExpr agg = (AggregateExpr) node;
                    //aggr support?
                    if (!storage.querier().supportAggregator(agg.getOp())) {
                        analysis.setUseNative(false);
                        return true;
                    }

                    Expr expr = agg.getExpr();
                    if (expr instanceof Call) {
                        Call call = (Call) expr;
                        Call.Context ctx = call.getContext();
                        ctx.setAggregationType(agg.getOp());
                        ctx.setGrouping(agg.getGrouping());
                        analysis.setUseNative(true);
                    } else if (expr instanceof VectorSelector) {
                        VectorSelector vectorSelector = (VectorSelector) expr;
                        VectorSelector.Context ctx = vectorSelector.getContext();
                        ctx.setAggregationType(agg.getOp());
                        ctx.setGrouping(agg.getGrouping());
                        analysis.setUseNative(true);
                    }
                    //else expr type,useNative keep false;

                } else if (node instanceof Call) {
                    //for example,"sum_over_time(..[5m])"
                    Call call = (Call) node;
                    Call.Context callCtx = call.getContext();
                    //FIXME 需要传入[Call函数名称]
                    if (callCtx.getAggregationType() == null
                        || !storage.querier().supportAggregator(callCtx.getAggregationType())) {
                        //TODO Call function name must map with aggr;
                        analysis.setUseNative(false);
                        return true;
                    }
                    analysis.setUseNative(true);
                    for (Expr expr : call.getArgs().getExpressions()) {
                        if (expr instanceof MatrixSelector) {
                            MatrixSelector ms = (MatrixSelector) expr;
                            MatrixSelector.Context ctx = ms.getContext();
                            ctx.setAggregationType(callCtx.getAggregationType());
                            ctx.setGrouping(callCtx.getGrouping());
                            ctx.setDownsampleFunction(call.getFunc());
                        }
                    }
                } else if (node instanceof VectorSelector) {
                    VectorSelector n = (VectorSelector) node;
                    if (maxOffset.get() < LookbackDelta.toMillis()) {
                        maxOffset.set(LookbackDelta.toMillis());
                    }
                    if (n.getOffset().toMillis() + LookbackDelta.toMillis() > maxOffset.get()) {
                        maxOffset.set(n.getOffset().plus(LookbackDelta).toMillis());
                    }
                } else if (node instanceof MatrixSelector) {
                    MatrixSelector n = (MatrixSelector) node;
                    if (maxOffset.get() < n.getRange().toMillis()) {
                        maxOffset.set(n.getRange().toMillis());
                    }
                    if (n.getOffset().toMillis() + n.getRange().toMillis() > maxOffset.get()) {
                        maxOffset.set(n.getOffset().plus(n.getRange()).toMillis());
                    }
                }
                return true;
            }
        });
        Instant mint = s.getStart().minusMillis(maxOffset.get());

        analysis.setStartTime(mint.toEpochMilli());
        analysis.setEndTime(s.getEnd().toEpochMilli());
        analysis.setStep(s.getInterval().toMillis());
        //support but config disable.
        if (analysis.isUseNative() && !query.hints().isUseNative()) {
            analysis.setUseNative(false);
        }
        return analysis;
    }

    /**
     * Query semi-finished data from the storage;
     */
    public void analyzeSelectorNode(Analysis analysis) {
        Querier querier = storage.querier();
        Ast.traverses(analysis.getExpr(), new NodeInspector() {
            @Override
            public boolean inspect(Node node) {
                if (node instanceof VectorSelector) {
                    VectorSelector n = (VectorSelector) node;
                    Collection set;
                    if (analysis.isUseNative()) {
                        AggregateStatement aggrStmt = querier.createAggregateStmt();
                        aggrStmt.setStartTime(analysis.getStartTime())
                            .setEndTime(analysis.getEndTime()).setMatchers(n.getMatchers());

                        aggrStmt.setAggregator(n.getContext().getAggregationType()).setGroups(
                            n.getContext().getGrouping());
                        aggrStmt.context().put(EXPRESSION_CONTEXT, n.getContext());
                        set = aggrStmt.executeQuery();
                    } else {
                        QueryStatement queryStmt = querier.createQueryStmt();
                        queryStmt.setStartTime(analysis.getStartTime())
                            .setEndTime(analysis.getEndTime()).setMatchers(n.getMatchers());
                        queryStmt.context().put(EXPRESSION_CONTEXT, n.getContext());
                        set = queryStmt.executeQuery();
                    }

                    if (set == null) {
                        throw new RuntimeException("error selecting series set");
                    }
                    n.getSeriess().addAll(set);
                } else if (node instanceof MatrixSelector) {
                    MatrixSelector n = (MatrixSelector) node;
                    Collection set;
                    if (analysis.isUseNative()) {
                        AggregateStatement aggrStmt = querier.createAggregateStmt();
                        aggrStmt.setStartTime(analysis.getStartTime())
                            .setEndTime(analysis.getEndTime()).setMatchers(n.getMatchers());

                        aggrStmt.setAggregator(n.getContext().getAggregationType()).setGroups(
                            n.getContext().getGrouping());
                        aggrStmt.context().put(EXPRESSION_CONTEXT, n.getContext());
                        set = aggrStmt.executeQuery();
                    } else {
                        QueryStatement queryStmt = querier.createQueryStmt();
                        queryStmt.setStartTime(analysis.getStartTime())
                            .setEndTime(analysis.getEndTime()).setMatchers(n.getMatchers());
                        queryStmt.context().put(EXPRESSION_CONTEXT, n.getContext());
                        set = queryStmt.executeQuery();
                    }

                    n.getSeriess().addAll(set);
                }
                return true;
            }
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy