Implementation:Apache Druid MakeTableQueryAndHints
| Knowledge Sources | |
|---|---|
| Domains | Visual_Exploration, Query_Processing |
| Last Updated | 2026-02-10 00:00 GMT |
Overview
Concrete SQL query builder function that generates optimized Druid SQL queries with column hints from visual exploration parameters.
Description
The makeTableQueryAndHints function (part of a 930-line module) is the core query generator for the Explore view. It takes visualization parameters (source, filters, dimensions, measures, time bucket, comparisons) and generates a QueryAndHints object containing:
- query: A complete SqlQuery object ready for execution
- columnHints: A Map of column metadata for visualization rendering (formatting, grouping labels, comparison deltas)
The function delegates to three internal strategies:
- makeNonCompareTableQueryAndHints: Standard GROUP BY queries
- makeFilteredCompareTableQueryAndHints: Period comparison using FILTER clauses
- makeJoinCompareTableQueryAndHints: Period comparison using self-JOINs
Additionally, rewriteAggregate (from aggregate.ts) expands the AGGREGATE() macro into actual SQL aggregation expressions based on the measures configuration.
Usage
Call this function whenever visualization parameters change. The returned query is executed via runSqlQuery() and results are passed to the visualization module component.
Code Reference
Source Location
- Repository: Apache Druid
- File: web-console/src/views/explore-view/utils/table-query.ts
- Lines: L378-L461
- Related: web-console/src/views/explore-view/query-macros/aggregate.ts (L25-L77)
Signature
interface MakeTableQueryAndHintsOptions {
source: SqlQuery;
where: SqlExpression;
splitColumns: ExpressionMeta[];
timeBucket?: string;
showColumns: ExpressionMeta[];
multipleValueMode?: MultipleValueMode;
measures: Measure[];
compares?: Compare[];
compareStrategy?: CompareStrategy;
compareTypes?: CompareType[];
restrictTop?: RestrictTop;
maxRows: number;
pivotColumn?: ExpressionMeta;
pivotValues?: string[];
orderBy: SqlOrderByExpression | undefined;
totalSubQueryLimit?: number;
useGroupingToOrderSubQueries?: boolean;
topValuesK?: number;
}
interface QueryAndHints {
query: SqlQuery;
columnHints: Map<string, ColumnHint>;
}
export function makeTableQueryAndHints(
options: MakeTableQueryAndHintsOptions,
): QueryAndHints
Import
import { makeTableQueryAndHints } from './utils/table-query';
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| source | SqlQuery | Yes | Base datasource query |
| where | SqlExpression | Yes | Filter WHERE clause |
| splitColumns | ExpressionMeta[] | Yes | Dimensions for GROUP BY |
| measures | Measure[] | Yes | Aggregation measures for SELECT |
| timeBucket | string | No | Time granularity (PT1M, PT1H, P1D, etc.) |
| maxRows | number | Yes | Maximum result rows |
| compares | Compare[] | No | Time period comparisons |
| orderBy | SqlOrderByExpression | No | Result ordering |
Outputs
| Name | Type | Description |
|---|---|---|
| query | SqlQuery | Complete SQL query ready for execution |
| columnHints | Map<string, ColumnHint> | Column metadata for visualization rendering |
Usage Examples
Generating a Time Series Query
import { makeTableQueryAndHints } from './utils/table-query';
const { query, columnHints } = makeTableQueryAndHints({
source: SqlQuery.parse('SELECT * FROM "events"'),
where: SqlLiteral.TRUE,
splitColumns: [{ name: '__time', expression: C('__time') }],
timeBucket: 'PT1H',
showColumns: [],
measures: [Measure.COUNT, new Measure({ expression: F.sum(C('value')), as: 'total' })],
maxRows: 10000,
orderBy: undefined,
});
// Generated SQL:
// SELECT TIME_FLOOR("__time", 'PT1H') AS "__time",
// COUNT(*) AS "Count",
// SUM("value") AS "total"
// FROM "events"
// GROUP BY 1
// ORDER BY 1 ASC
// LIMIT 10000