feat: alias database matcher for promql (#5522)

* feat: provide an alias db matcher for promql

* refactor: rename __db__ to __database__

* chore: fix sqlness test
This commit is contained in:
Ning Sun
2025-02-13 00:37:37 -08:00
committed by GitHub
parent 02af9dd21a
commit 198ee87675
4 changed files with 61 additions and 1 deletions

View File

@@ -99,6 +99,7 @@ const FIELD_COLUMN_MATCHER: &str = "__field__";
/// Special modifier for cross schema query
const SCHEMA_COLUMN_MATCHER: &str = "__schema__";
const DB_COLUMN_MATCHER: &str = "__database__";
/// Threshold for scatter scan mode
const MAX_SCATTER_POINTS: i64 = 400;
@@ -724,7 +725,7 @@ impl PromPlanner {
.field_column_matcher
.get_or_insert_default()
.push(matcher.clone());
} else if matcher.name == SCHEMA_COLUMN_MATCHER {
} else if matcher.name == SCHEMA_COLUMN_MATCHER || matcher.name == DB_COLUMN_MATCHER {
ensure!(
matcher.op == MatchOp::Equal,
UnsupportedMatcherOpSnafu {
@@ -3323,6 +3324,13 @@ mod test {
indie_query_plan_compare(query, expected).await;
let query = "some_alt_metric{__database__=\"greptime_private\"}";
let expected = String::from(
"PromInstantManipulate: range=[0..100000000], lookback=[1000], interval=[5000], time index=[timestamp] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesNormalize: offset=[0], time index=[timestamp], filter NaN: [false] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesDivide: tags=[\"tag_0\"] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Sort: greptime_private.some_alt_metric.tag_0 DESC NULLS LAST, greptime_private.some_alt_metric.timestamp DESC NULLS LAST [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Filter: greptime_private.some_alt_metric.timestamp >= TimestampMillisecond(-1000, None) AND greptime_private.some_alt_metric.timestamp <= TimestampMillisecond(100001000, None) [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n TableScan: greptime_private.some_alt_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]"
);
indie_query_plan_compare(query, expected).await;
let query = "some_alt_metric{__schema__=\"greptime_private\"} / some_metric";
let expected = String::from("Projection: some_metric.tag_0, some_metric.timestamp, greptime_private.some_alt_metric.field_0 / some_metric.field_0 AS greptime_private.some_alt_metric.field_0 / some_metric.field_0 [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), greptime_private.some_alt_metric.field_0 / some_metric.field_0:Float64;N]\n Inner Join: greptime_private.some_alt_metric.tag_0 = some_metric.tag_0, greptime_private.some_alt_metric.timestamp = some_metric.timestamp [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N, tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n SubqueryAlias: greptime_private.some_alt_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromInstantManipulate: range=[0..100000000], lookback=[1000], interval=[5000], time index=[timestamp] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesNormalize: offset=[0], time index=[timestamp], filter NaN: [false] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesDivide: tags=[\"tag_0\"] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Sort: greptime_private.some_alt_metric.tag_0 DESC NULLS LAST, greptime_private.some_alt_metric.timestamp DESC NULLS LAST [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Filter: greptime_private.some_alt_metric.timestamp >= TimestampMillisecond(-1000, None) AND greptime_private.some_alt_metric.timestamp <= TimestampMillisecond(100001000, None) [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n TableScan: greptime_private.some_alt_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n SubqueryAlias: some_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromInstantManipulate: range=[0..100000000], lookback=[1000], interval=[5000], time index=[timestamp] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesNormalize: offset=[0], time index=[timestamp], filter NaN: [false] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n PromSeriesDivide: tags=[\"tag_0\"] [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Sort: some_metric.tag_0 DESC NULLS LAST, some_metric.timestamp DESC NULLS LAST [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n Filter: some_metric.timestamp >= TimestampMillisecond(-1000, None) AND some_metric.timestamp <= TimestampMillisecond(100001000, None) [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]\n TableScan: some_metric [tag_0:Utf8, timestamp:Timestamp(Millisecond, None), field_0:Float64;N]");
@@ -3334,6 +3342,8 @@ mod test {
let queries = &[
"some_alt_metric{__schema__!=\"greptime_private\"}",
"some_alt_metric{__schema__=~\"lalala\"}",
"some_alt_metric{__database__!=\"greptime_private\"}",
"some_alt_metric{__database__=~\"lalala\"}",
];
for query in queries {

View File

@@ -602,6 +602,33 @@ async fn cross_schema_query(instance: Arc<dyn MockInstance>) {
check_unordered_output_stream(query_output, expected).await;
let query_output = promql_query(
ins.clone(),
r#"http_requests{__database__="greptime_private"}"#,
QueryContext::arc(),
start,
end,
interval,
lookback_delta,
)
.await
.unwrap();
let expected = r#"+------------+----------+------------+-------+---------------------+
| job | instance | group | value | ts |
+------------+----------+------------+-------+---------------------+
| api-server | 0 | production | 100.0 | 1970-01-01T00:00:00 |
| api-server | 0 | canary | 300.0 | 1970-01-01T00:00:00 |
| api-server | 1 | production | 200.0 | 1970-01-01T00:00:00 |
| api-server | 1 | canary | 400.0 | 1970-01-01T00:00:00 |
| app-server | 0 | canary | 700.0 | 1970-01-01T00:00:00 |
| app-server | 0 | production | 500.0 | 1970-01-01T00:00:00 |
| app-server | 1 | canary | 800.0 | 1970-01-01T00:00:00 |
| app-server | 1 | production | 600.0 | 1970-01-01T00:00:00 |
+------------+----------+------------+-------+---------------------+"#;
check_unordered_output_stream(query_output, expected).await;
let query_output = promql_query(
ins.clone(),
r#"http_requests"#,

View File

@@ -49,6 +49,23 @@ TQL EVAL (0, 10, '5s') test{__schema__="greptime_private"};
Error: 4001(TableNotFound), Table not found: greptime.greptime_private.test
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (0, 10, '5s') test{__database__="public"};
+-----+---------------------+---+
| i | j | k |
+-----+---------------------+---+
| 1.0 | 1970-01-01T00:00:05 | b |
| 1.0 | 1970-01-01T00:00:10 | b |
| 2.0 | 1970-01-01T00:00:05 | a |
| 2.0 | 1970-01-01T00:00:10 | a |
+-----+---------------------+---+
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (0, 10, '5s') test{__database__="greptime_private"};
Error: 4001(TableNotFound), Table not found: greptime.greptime_private.test
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (0, 10, '5s') {__name__="test", __field__="i"};

View File

@@ -16,6 +16,12 @@ TQL EVAL (0, 10, '5s') test{__schema__="public"};
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (0, 10, '5s') test{__schema__="greptime_private"};
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (0, 10, '5s') test{__database__="public"};
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (0, 10, '5s') test{__database__="greptime_private"};
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (0, 10, '5s') {__name__="test", __field__="i"};