Search in sources :

Example 11 with TSSubQuery

use of net.opentsdb.core.TSSubQuery in project opentsdb by OpenTSDB.

the class TestQueryRpc method parseQueryMTypeWDS.

@Test
public void parseQueryMTypeWDS() throws Exception {
    HttpQuery query = NettyMocks.getQuery(tsdb, "/api/query?start=1h-ago&m=sum:1h-avg:sys.cpu.0");
    TSQuery tsq = (TSQuery) parseQuery.invoke(rpc, tsdb, query, expressions);
    TSSubQuery sub = tsq.getQueries().get(0);
    assertEquals("1h-avg", sub.getDownsample());
}
Also used : TSQuery(net.opentsdb.core.TSQuery) TSSubQuery(net.opentsdb.core.TSSubQuery) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 12 with TSSubQuery

use of net.opentsdb.core.TSSubQuery in project opentsdb by OpenTSDB.

the class QueryExecutor method serialize.

/**
   * Writes the results to a ChannelBuffer to return to the caller. This will
   * iterate over all of the outputs and drop in meta data where appropriate.
   * @throws Exception if something went pear shaped
   */
private Deferred<ChannelBuffer> serialize() throws Exception {
    final long start = System.currentTimeMillis();
    // buffers and an array list to stored the deferreds
    final ChannelBuffer response = ChannelBuffers.dynamicBuffer();
    final OutputStream output_stream = new ChannelBufferOutputStream(response);
    final JsonGenerator json = JSON.getFactory().createGenerator(output_stream);
    json.writeStartObject();
    json.writeFieldName("outputs");
    json.writeStartArray();
    // We want the serializer to execute serially so we need to create a callback
    // chain so that when one DPsResolver is finished, it triggers the next to
    // start serializing.
    final Deferred<Object> cb_chain = new Deferred<Object>();
    // default to the expressions if there, or fall back to the metrics
    final List<Output> outputs;
    if (query.getOutputs() == null || query.getOutputs().isEmpty()) {
        if (query.getExpressions() != null && !query.getExpressions().isEmpty()) {
            outputs = new ArrayList<Output>(query.getExpressions().size());
            for (final Expression exp : query.getExpressions()) {
                outputs.add(Output.Builder().setId(exp.getId()).build());
            }
        } else if (query.getMetrics() != null && !query.getMetrics().isEmpty()) {
            outputs = new ArrayList<Output>(query.getMetrics().size());
            for (final Metric metric : query.getMetrics()) {
                outputs.add(Output.Builder().setId(metric.getId()).build());
            }
        } else {
            throw new IllegalArgumentException("How did we get here?? No metrics or expressions??");
        }
    } else {
        outputs = query.getOutputs();
    }
    for (final Output output : outputs) {
        if (expressions != null) {
            final ExpressionIterator it = expressions.get(output.getId());
            if (it != null) {
                cb_chain.addCallback(new SerializeExpressionIterator(tsdb, json, output, it, ts_query));
                continue;
            }
        }
        if (query.getMetrics() != null && !query.getMetrics().isEmpty()) {
            final TSSubQuery sub = sub_queries.get(output.getId());
            if (sub != null) {
                final TimeSyncedIterator it = new TimeSyncedIterator(output.getId(), sub.getFilterTagKs(), sub_query_results.get(output.getId()));
                cb_chain.addCallback(new SerializeSubIterator(tsdb, json, output, it));
                continue;
            }
        } else {
            LOG.warn("Couldn't find a variable matching: " + output.getId() + " in query " + query);
        }
    }
    /** Final callback to close out the JSON array and return our results */
    class FinalCB implements Callback<ChannelBuffer, Object> {

        public ChannelBuffer call(final Object obj) throws Exception {
            json.writeEndArray();
            //        ts_query.getQueryStats().setTimeSerialization(
            //            DateTime.currentTimeMillis() - start);
            ts_query.getQueryStats().markSerializationSuccessful();
            // dump the original query
            if (true) {
                json.writeFieldName("query");
                json.writeObject(QueryExecutor.this.query);
            }
            // IMPORTANT Make sure the close the JSON array and the generator
            json.writeEndObject();
            json.close();
            return response;
        }
    }
    // trigger the callback chain here
    cb_chain.callback(null);
    return cb_chain.addCallback(new FinalCB());
}
Also used : ChannelBufferOutputStream(org.jboss.netty.buffer.ChannelBufferOutputStream) ExpressionIterator(net.opentsdb.query.expression.ExpressionIterator) ChannelBufferOutputStream(org.jboss.netty.buffer.ChannelBufferOutputStream) OutputStream(java.io.OutputStream) Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) TimeSyncedIterator(net.opentsdb.query.expression.TimeSyncedIterator) TSSubQuery(net.opentsdb.core.TSSubQuery) ChannelBuffer(org.jboss.netty.buffer.ChannelBuffer) Callback(com.stumbleupon.async.Callback) Expression(net.opentsdb.query.pojo.Expression) Output(net.opentsdb.query.pojo.Output) JsonGenerator(com.fasterxml.jackson.core.JsonGenerator) Metric(net.opentsdb.query.pojo.Metric)

Example 13 with TSSubQuery

use of net.opentsdb.core.TSSubQuery in project opentsdb by OpenTSDB.

the class QueryExecutor method execute.

/**
   * Execute the RPC and serialize the response
   * @param query The HTTP query to parse and and return results to
   */
public void execute(final HttpQuery query) {
    http_query = query;
    final QueryStats query_stats = new QueryStats(query.getRemoteAddress(), ts_query, query.getHeaders());
    ts_query.setQueryStats(query_stats);
    /**
     * Sends the serialized results to the caller. This should be the very
     * last callback executed.
     */
    class CompleteCB implements Callback<Object, ChannelBuffer> {

        @Override
        public Object call(final ChannelBuffer cb) throws Exception {
            query.sendReply(cb);
            return null;
        }
    }
    /**
     * After all of the queries have run and we have data (or not) then we
     * need to compile the iterators.
     * This class could probably be improved:
     * First we iterate over the results AND for each result, iterate over
     * the expressions, giving a time synced iterator to each expression that 
     * needs the result set.
     * THEN we iterate over the expressions again and build a DAG to determine
     * if any of the expressions require the output of an expression. If so
     * then we add the expressions to the proper parent and compile them in
     * order.
     * After all of that we're ready to start serializing and iterating
     * over the results.
     */
    class QueriesCB implements Callback<Object, ArrayList<DataPoints[]>> {

        public Object call(final ArrayList<DataPoints[]> query_results) throws Exception {
            for (int i = 0; i < query_results.size(); i++) {
                final TSSubQuery sub = ts_query.getQueries().get(i);
                Iterator<Entry<String, TSSubQuery>> it = sub_queries.entrySet().iterator();
                while (it.hasNext()) {
                    final Entry<String, TSSubQuery> entry = it.next();
                    if (entry.getValue().equals(sub)) {
                        sub_query_results.put(entry.getKey(), query_results.get(i));
                        for (final ExpressionIterator ei : expressions.values()) {
                            if (ei.getVariableNames().contains(entry.getKey())) {
                                final TimeSyncedIterator tsi = new TimeSyncedIterator(entry.getKey(), sub.getFilterTagKs(), query_results.get(i));
                                final NumericFillPolicy fill = fills.get(entry.getKey());
                                if (fill != null) {
                                    tsi.setFillPolicy(fill);
                                }
                                ei.addResults(entry.getKey(), tsi);
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug("Added results for " + entry.getKey() + " to " + ei.getId());
                                }
                            }
                        }
                    }
                }
            }
            // handle nested expressions
            final DirectedAcyclicGraph<String, DefaultEdge> graph = new DirectedAcyclicGraph<String, DefaultEdge>(DefaultEdge.class);
            for (final Entry<String, ExpressionIterator> eii : expressions.entrySet()) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug(String.format("Expression entry key is %s, value is %s", eii.getKey(), eii.getValue().toString()));
                    LOG.debug(String.format("Time to loop through the variable names " + "for %s", eii.getKey()));
                }
                if (!graph.containsVertex(eii.getKey())) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Adding vertex " + eii.getKey());
                    }
                    graph.addVertex(eii.getKey());
                }
                for (final String var : eii.getValue().getVariableNames()) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug(String.format("var is %s", var));
                    }
                    final ExpressionIterator ei = expressions.get(var);
                    if (ei != null) {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug(String.format("The expression iterator for %s is %s", var, ei.toString()));
                        }
                        // TODO - really ought to calculate this earlier
                        if (eii.getKey().equals(var)) {
                            throw new IllegalArgumentException("Self referencing expression found: " + eii.getKey());
                        }
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Nested expression detected. " + eii.getKey() + " depends on " + var);
                        }
                        if (!graph.containsVertex(eii.getKey())) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("Added vertex " + eii.getKey());
                            }
                            graph.addVertex(eii.getKey());
                        } else if (LOG.isDebugEnabled()) {
                            LOG.debug("Already contains vertex " + eii.getKey());
                        }
                        if (!graph.containsVertex(var)) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("Added vertex " + var);
                            }
                            graph.addVertex(var);
                        } else if (LOG.isDebugEnabled()) {
                            LOG.debug("Already contains vertex " + var);
                        }
                        try {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("Added Edge " + eii.getKey() + " - " + var);
                            }
                            graph.addDagEdge(eii.getKey(), var);
                        } catch (CycleFoundException cfe) {
                            throw new IllegalArgumentException("Circular reference found: " + eii.getKey(), cfe);
                        }
                    } else if (LOG.isDebugEnabled()) {
                        LOG.debug(String.format("The expression iterator for %s is null", var));
                    }
                }
            }
            // compile all of the expressions
            final long intersect_start = DateTime.currentTimeMillis();
            final Integer expressionLength = expressions.size();
            final ExpressionIterator[] compile_stack = new ExpressionIterator[expressionLength];
            final TopologicalOrderIterator<String, DefaultEdge> it = new TopologicalOrderIterator<String, DefaultEdge>(graph);
            if (LOG.isDebugEnabled()) {
                LOG.debug(String.format("Expressions Size is %d", expressionLength));
                LOG.debug(String.format("Topology Iterator %s", it.toString()));
            }
            int i = 0;
            while (it.hasNext()) {
                String next = it.next();
                if (LOG.isDebugEnabled()) {
                    LOG.debug(String.format("Expression: %s", next));
                }
                ExpressionIterator ei = expressions.get(next);
                if (LOG.isDebugEnabled()) {
                    LOG.debug(String.format("Expression Iterator: %s", ei.toString()));
                }
                if (ei == null) {
                    LOG.error(String.format("The expression iterator for %s is null", next));
                }
                compile_stack[i] = ei;
                if (LOG.isDebugEnabled()) {
                    LOG.debug(String.format("Added expression %s to compile_stack[%d]", next, i));
                }
                i++;
            }
            if (i != expressionLength) {
                throw new IOException(String.format(" Internal Error: Fewer " + "expressions where added to the compile stack than " + "expressions.size (%d instead of %d)", i, expressionLength));
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug(String.format("compile stack length: %d", compile_stack.length));
            }
            for (int x = compile_stack.length - 1; x >= 0; x--) {
                if (compile_stack[x] == null) {
                    throw new NullPointerException(String.format("Item %d in " + "compile_stack[] is null", x));
                }
                // look for and add expressions
                for (final String var : compile_stack[x].getVariableNames()) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug(String.format("Looking for variable %s for %s", var, compile_stack[x].getId()));
                    }
                    ExpressionIterator source = expressions.get(var);
                    if (source != null) {
                        compile_stack[x].addResults(var, source.getCopy());
                        if (LOG.isDebugEnabled()) {
                            LOG.debug(String.format("Adding expression %s to %s", source.getId(), compile_stack[x].getId()));
                        }
                    }
                }
                compile_stack[x].compile();
                if (LOG.isDebugEnabled()) {
                    LOG.debug(String.format("Successfully compiled %s", compile_stack[x].getId()));
                }
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug("Finished compilations in " + (DateTime.currentTimeMillis() - intersect_start) + " ms");
            }
            return serialize().addCallback(new CompleteCB()).addErrback(new ErrorCB());
        }
    }
    /**
     * Callback executed after we have resolved the metric, tag names and tag
     * values to their respective UIDs. This callback then runs the actual 
     * queries and fetches their results.
     */
    class BuildCB implements Callback<Deferred<Object>, net.opentsdb.core.Query[]> {

        @Override
        public Deferred<Object> call(final net.opentsdb.core.Query[] queries) {
            final ArrayList<Deferred<DataPoints[]>> deferreds = new ArrayList<Deferred<DataPoints[]>>(queries.length);
            for (final net.opentsdb.core.Query query : queries) {
                deferreds.add(query.runAsync());
            }
            return Deferred.groupInOrder(deferreds).addCallback(new QueriesCB()).addErrback(new ErrorCB());
        }
    }
    // TODO - only run the ones that will be involved in an output. Folks WILL
    // ask for stuff they don't need.... *sigh*
    ts_query.buildQueriesAsync(tsdb).addCallback(new BuildCB()).addErrback(new ErrorCB());
}
Also used : ExpressionIterator(net.opentsdb.query.expression.ExpressionIterator) Query(net.opentsdb.query.pojo.Query) TSQuery(net.opentsdb.core.TSQuery) TSSubQuery(net.opentsdb.core.TSSubQuery) Deferred(com.stumbleupon.async.Deferred) ArrayList(java.util.ArrayList) TopologicalOrderIterator(org.jgrapht.traverse.TopologicalOrderIterator) DataPoints(net.opentsdb.core.DataPoints) TimeSyncedIterator(net.opentsdb.query.expression.TimeSyncedIterator) DirectedAcyclicGraph(org.jgrapht.experimental.dag.DirectedAcyclicGraph) ChannelBuffer(org.jboss.netty.buffer.ChannelBuffer) Entry(java.util.Map.Entry) CycleFoundException(org.jgrapht.experimental.dag.DirectedAcyclicGraph.CycleFoundException) DefaultEdge(org.jgrapht.graph.DefaultEdge) IOException(java.io.IOException) TSSubQuery(net.opentsdb.core.TSSubQuery) DataPoint(net.opentsdb.core.DataPoint) ExpressionDataPoint(net.opentsdb.query.expression.ExpressionDataPoint) Callback(com.stumbleupon.async.Callback) QueryStats(net.opentsdb.stats.QueryStats) NumericFillPolicy(net.opentsdb.query.expression.NumericFillPolicy)

Example 14 with TSSubQuery

use of net.opentsdb.core.TSSubQuery in project opentsdb by OpenTSDB.

the class QueryRpc method parseMTypeSubQuery.

/**
   * Parses a query string "m=..." type query and adds it to the TSQuery.
   * This will generate a TSSubQuery and add it to the TSQuery if successful
   * @param query_string The value of the m query string parameter, i.e. what
   * comes after the equals sign
   * @param data_query The query we're building
   * @throws BadRequestException if we are unable to parse the query or it is
   * missing components
   */
private static void parseMTypeSubQuery(final String query_string, TSQuery data_query) {
    if (query_string == null || query_string.isEmpty()) {
        throw new BadRequestException("The query string was empty");
    }
    // m is of the following forms:
    // agg:[interval-agg:][rate:]metric[{tag=value,...}]
    // where the parts in square brackets `[' .. `]' are optional.
    final String[] parts = Tags.splitString(query_string, ':');
    int i = parts.length;
    if (i < 2 || i > 5) {
        throw new BadRequestException("Invalid parameter m=" + query_string + " (" + (i < 2 ? "not enough" : "too many") + " :-separated parts)");
    }
    final TSSubQuery sub_query = new TSSubQuery();
    // the aggregator is first
    sub_query.setAggregator(parts[0]);
    // Move to the last part (the metric name).
    i--;
    List<TagVFilter> filters = new ArrayList<TagVFilter>();
    sub_query.setMetric(Tags.parseWithMetricAndFilters(parts[i], filters));
    sub_query.setFilters(filters);
    // parse out the rate and downsampler 
    for (int x = 1; x < parts.length - 1; x++) {
        if (parts[x].toLowerCase().startsWith("rate")) {
            sub_query.setRate(true);
            if (parts[x].indexOf("{") >= 0) {
                sub_query.setRateOptions(QueryRpc.parseRateOptions(true, parts[x]));
            }
        } else if (Character.isDigit(parts[x].charAt(0))) {
            sub_query.setDownsample(parts[x]);
        } else if (parts[x].toLowerCase().startsWith("explicit_tags")) {
            sub_query.setExplicitTags(true);
        }
    }
    if (data_query.getQueries() == null) {
        final ArrayList<TSSubQuery> subs = new ArrayList<TSSubQuery>(1);
        data_query.setQueries(subs);
    }
    data_query.getQueries().add(sub_query);
}
Also used : TagVFilter(net.opentsdb.query.filter.TagVFilter) ArrayList(java.util.ArrayList) TSSubQuery(net.opentsdb.core.TSSubQuery) IncomingDataPoint(net.opentsdb.core.IncomingDataPoint)

Example 15 with TSSubQuery

use of net.opentsdb.core.TSSubQuery in project opentsdb by OpenTSDB.

the class QueryRpc method parseTsuidTypeSubQuery.

/**
   * Parses a "tsuid=..." type query and adds it to the TSQuery.
   * This will generate a TSSubQuery and add it to the TSQuery if successful
   * @param query_string The value of the m query string parameter, i.e. what
   * comes after the equals sign
   * @param data_query The query we're building
   * @throws BadRequestException if we are unable to parse the query or it is
   * missing components
   */
private static void parseTsuidTypeSubQuery(final String query_string, TSQuery data_query) {
    if (query_string == null || query_string.isEmpty()) {
        throw new BadRequestException("The tsuid query string was empty");
    }
    // tsuid queries are of the following forms:
    // agg:[interval-agg:][rate:]tsuid[,s]
    // where the parts in square brackets `[' .. `]' are optional.
    final String[] parts = Tags.splitString(query_string, ':');
    int i = parts.length;
    if (i < 2 || i > 5) {
        throw new BadRequestException("Invalid parameter m=" + query_string + " (" + (i < 2 ? "not enough" : "too many") + " :-separated parts)");
    }
    final TSSubQuery sub_query = new TSSubQuery();
    // the aggregator is first
    sub_query.setAggregator(parts[0]);
    // Move to the last part (the metric name).
    i--;
    final List<String> tsuid_array = Arrays.asList(parts[i].split(","));
    sub_query.setTsuids(tsuid_array);
    // parse out the rate and downsampler 
    for (int x = 1; x < parts.length - 1; x++) {
        if (parts[x].toLowerCase().startsWith("rate")) {
            sub_query.setRate(true);
            if (parts[x].indexOf("{") >= 0) {
                sub_query.setRateOptions(QueryRpc.parseRateOptions(true, parts[x]));
            }
        } else if (Character.isDigit(parts[x].charAt(0))) {
            sub_query.setDownsample(parts[x]);
        }
    }
    if (data_query.getQueries() == null) {
        final ArrayList<TSSubQuery> subs = new ArrayList<TSSubQuery>(1);
        data_query.setQueries(subs);
    }
    data_query.getQueries().add(sub_query);
}
Also used : ArrayList(java.util.ArrayList) TSSubQuery(net.opentsdb.core.TSSubQuery) IncomingDataPoint(net.opentsdb.core.IncomingDataPoint)

Aggregations

TSSubQuery (net.opentsdb.core.TSSubQuery)37 TSQuery (net.opentsdb.core.TSQuery)30 Test (org.junit.Test)26 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)26 ArrayList (java.util.ArrayList)10 TagVWildcardFilter (net.opentsdb.query.filter.TagVWildcardFilter)7 Callback (com.stumbleupon.async.Callback)4 Deferred (com.stumbleupon.async.Deferred)4 HashMap (java.util.HashMap)4 DataPoints (net.opentsdb.core.DataPoints)4 IOException (java.io.IOException)3 DataPoint (net.opentsdb.core.DataPoint)3 IncomingDataPoint (net.opentsdb.core.IncomingDataPoint)3 ChannelBuffer (org.jboss.netty.buffer.ChannelBuffer)3 JsonGenerator (com.fasterxml.jackson.core.JsonGenerator)2 OutputStream (java.io.OutputStream)2 Map (java.util.Map)2 Query (net.opentsdb.core.Query)2 ExpressionIterator (net.opentsdb.query.expression.ExpressionIterator)2 TimeSyncedIterator (net.opentsdb.query.expression.TimeSyncedIterator)2