All Products
Search
Document Center

Time Series Database:Query data

Last Updated:Mar 28, 2026

Use the Lindorm Time Series Database (TSDB) SDK to build and run queries against your time series data. This document covers synchronous and asynchronous queries, result ordering, and how to retrieve the latest data point for a time series.

Key concepts

ConceptClassDescription
QueryQueryThe top-level query object. Holds a time range and one or more sub queries.
Sub querySubQueryDefines what data to retrieve: a metric, an aggregator, optional downsampling, and tag filters. A single Query can contain multiple sub queries.
AggregatorAggregatorAn enumeration of aggregation functions. Common values: AVG, SUM, NONE.

Build a query

Construct a Query object using the builder pattern. At minimum, specify a time range and at least one sub query.

Query query = Query
    .timeRange(startTime, endTime)    // Specify the time range during which you want to query data.
    .sub(SubQuery.metric("hello").aggregator(Aggregator.AVG).tag("tagk1", "tagv1").build())
    .sub(SubQuery.metric("world").aggregator(Aggregator.SUM).tag("tagk2", "tagv2").build())
    .build();

Sub query parameters

Each SubQuery accepts the following parameters:

ParameterTypeDescriptionExample
metricStringThe metric name to query."cpu.usage"
aggregatorAggregatorThe aggregation function to apply.Aggregator.AVG
downsampleStringReduces data density by resampling. Format: <interval><unit>-<aggregator>. For example, 60m-avg produces one average per 60 minutes."60m-avg"
tagString, StringFilters results to a specific tag key-value pair. Call multiple times to add more filters."region", "us-west"

Example sub query with all parameters:

SubQuery subQuery = SubQuery
    .metric("test-metric")
    .aggregator(Aggregator.AVG)
    .downsample("60m-avg")    // One average per 60 minutes
    .tag("tagk1", "tagv1")
    .tag("tagk2", "tagv2")
    .build();

Run a synchronous query

Call tsdb.query(query) to run a query in thread synchronization mode. The method blocks until results are returned.

List<QueryResult> result = tsdb.query(query);
System.out.println("Returned result" + result);

Run an asynchronous query

Pass a QueryCallback to tsdb.query() to run the query asynchronously. The SDK invokes response() when results are available.

QueryCallback cb = new QueryCallback() {

    @Override
    public void response(Query input, List<QueryResult> result) {
        System.out.println("Query parameters:" + input);
        System.out.println("Returned result:" + result);
    }

};

tsdb.query(query, cb);

Query result structure

tsdb.query() returns List<QueryResult>. Each QueryResult corresponds to one sub query.

Call getDps() on a QueryResult to obtain the data points.

Sort query results by timestamp

By default, getDps() returns data points in an unordered map. Use getOrderDps() to get a timestamp-sorted collection:

MethodOrder
getDps()Unordered
getOrderDps()Ascending (oldest first)
getOrderDps(true)Descending (newest first)

The following example retrieves the same data points in all three orderings:

Query query = Query
    .timeRange(current - 1000, start + 1000)
    .sub(SubQuery.metric(metric).aggregator(Aggregator.NONE).tag(tags).build())
    .build();

try {
    List<QueryResult> result = tsdb.query(query);

    for (QueryResult queryResult : result) {
        // Unordered data points
        System.out.println(queryResult.getDps());
        System.out.println("-------------");
        // Ascending order by timestamp
        System.out.println(queryResult.getOrderDps());
        System.out.println("-------------");
        // Descending order by timestamp
        System.out.println(queryResult.getOrderDps(true));
    }
} catch (HttpUnknowStatusException e) {
    e.printStackTrace();
}

Query the latest data point

tsdb.queryLast() returns one LastDataValue per time series — the most recent data point before a given timestamp.

There are two ways to identify which time series to query:

MethodWhen to use
By metric and tagsFirst time querying, or when you don't have TSUIDs yet
By TSUIDSubsequent queries for the same time series

Recommended workflow: Query by metric and tags first, then save the TSUIDs from the result for use in subsequent queries.

By metric and tags

Specify the metric name and tag filters in a LastPointSubQuery:

// Define tag filters
Map<String, String> tags = new HashMap<String, String>();
tags.put("uid", "1");
tags.put("id", "6");

String metric = "test.1";

// Build and run the query
LastPointQuery query = LastPointQuery.builder()
    .timestamp(1537520409729l)    // Query the latest point before this timestamp
    .msResolution(true)           // Interpret the timestamp as milliseconds
    .sub(LastPointSubQuery.builder(metric, tags).build())
    .build();

List<LastDataValue> lastDataValues = tsdb.queryLast(query);
System.out.println(lastDataValues);

The result includes the TSUID for each matched time series. Save these TSUIDs to use in subsequent queries.

By TSUID

If you already have TSUIDs from a previous query, pass them directly:

// TSUIDs obtained from a prior queryLast() call
List<String> tsuids = new ArrayList<String>();
tsuids.add("10000B7C000095000081****FF00006F");

LastPointQuery query = LastPointQuery.builder()
    .timestamp(1537520409729l)
    .msResolution(true)
    .sub(LastPointSubQuery.builder(tsuids).build())
    .build();

List<LastDataValue> lastDataValues = tsdb.queryLast(query);
System.out.println(lastDataValues);