mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-03 20:02:54 +00:00
fix(promql-planner): correct AND/UNLESS operator behavior (#5557)
* fix(promql-planner): keep field column in left input for AND operator * test: add sqlness test * fix: fix unless operator
This commit is contained in:
@@ -2202,6 +2202,17 @@ impl PromPlanner {
|
||||
.context(DataFusionPlanningSnafu)?;
|
||||
}
|
||||
|
||||
ensure!(
|
||||
left_context.field_columns.len() == 1,
|
||||
MultiFieldsNotSupportedSnafu {
|
||||
operator: "AND operator"
|
||||
}
|
||||
);
|
||||
// Update the field column in context.
|
||||
// The AND/UNLESS operator only keep the field column in left input.
|
||||
let left_field_col = left_context.field_columns.first().unwrap();
|
||||
self.ctx.field_columns = vec![left_field_col.clone()];
|
||||
|
||||
// Generate join plan.
|
||||
// All set operations in PromQL are "distinct"
|
||||
match op.id() {
|
||||
@@ -2460,7 +2471,6 @@ impl PromPlanner {
|
||||
let project_fields = non_field_columns_iter
|
||||
.chain(field_columns_iter)
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
LogicalPlanBuilder::from(input)
|
||||
.project(project_fields)
|
||||
.context(DataFusionPlanningSnafu)?
|
||||
@@ -3292,6 +3302,47 @@ mod test {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_parse_and_operator() {
|
||||
let mut eval_stmt = EvalStmt {
|
||||
expr: PromExpr::NumberLiteral(NumberLiteral { val: 1.0 }),
|
||||
start: UNIX_EPOCH,
|
||||
end: UNIX_EPOCH
|
||||
.checked_add(Duration::from_secs(100_000))
|
||||
.unwrap(),
|
||||
interval: Duration::from_secs(5),
|
||||
lookback_delta: Duration::from_secs(1),
|
||||
};
|
||||
|
||||
let cases = [
|
||||
r#"count (max by (persistentvolumeclaim,namespace) (kubelet_volume_stats_used_bytes{namespace=~".+"} ) and (max by (persistentvolumeclaim,namespace) (kubelet_volume_stats_used_bytes{namespace=~".+"} )) / (max by (persistentvolumeclaim,namespace) (kubelet_volume_stats_capacity_bytes{namespace=~".+"} )) >= (80 / 100)) or vector (0)"#,
|
||||
r#"count (max by (persistentvolumeclaim,namespace) (kubelet_volume_stats_used_bytes{namespace=~".+"} ) unless (max by (persistentvolumeclaim,namespace) (kubelet_volume_stats_used_bytes{namespace=~".+"} )) / (max by (persistentvolumeclaim,namespace) (kubelet_volume_stats_capacity_bytes{namespace=~".+"} )) >= (80 / 100)) or vector (0)"#,
|
||||
];
|
||||
|
||||
for case in cases {
|
||||
let prom_expr = parser::parse(case).unwrap();
|
||||
eval_stmt.expr = prom_expr;
|
||||
let table_provider = build_test_table_provider_with_fields(
|
||||
&[
|
||||
(
|
||||
DEFAULT_SCHEMA_NAME.to_string(),
|
||||
"kubelet_volume_stats_used_bytes".to_string(),
|
||||
),
|
||||
(
|
||||
DEFAULT_SCHEMA_NAME.to_string(),
|
||||
"kubelet_volume_stats_capacity_bytes".to_string(),
|
||||
),
|
||||
],
|
||||
&["namespace", "persistentvolumeclaim"],
|
||||
)
|
||||
.await;
|
||||
// Should be ok
|
||||
let _ = PromPlanner::stmt_to_plan(table_provider, &eval_stmt, &build_session_state())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn value_matcher() {
|
||||
// template
|
||||
|
||||
@@ -465,6 +465,105 @@ drop table t2;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
create table stats_used_bytes (
|
||||
ts timestamp time index,
|
||||
namespace string,
|
||||
greptime_value double,
|
||||
primary key (namespace)
|
||||
);
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
create table stats_capacity_bytes (
|
||||
ts timestamp time index,
|
||||
namespace string,
|
||||
greptime_value double,
|
||||
primary key (namespace)
|
||||
);
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
insert into stats_used_bytes values
|
||||
(0, "namespace1", 1.0),
|
||||
(0, "namespace2", 2.0),
|
||||
(500000, "namespace1", 10.0),
|
||||
(500000, "namespace2", 20.0),
|
||||
(1000000, "namespace1", 25.0),
|
||||
(1000000, "namespace2", 26.0);
|
||||
|
||||
Affected Rows: 6
|
||||
|
||||
insert into stats_capacity_bytes values
|
||||
(0, "namespace1", 30.0),
|
||||
(0, "namespace2", 30.0),
|
||||
(500000, "namespace1", 30.0),
|
||||
(500000, "namespace2", 30.0),
|
||||
(1000000, "namespace1", 30.0),
|
||||
(1000000, "namespace2", 30.0);
|
||||
|
||||
Affected Rows: 6
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') max by (namespace) (stats_used_bytes{namespace=~".+"}) / max by (namespace) (stats_capacity_bytes{namespace=~".+"}) >= (80 / 100);
|
||||
|
||||
+------------+---------------------+-----------------------------------------------------------------------------------------------------------------------+
|
||||
| namespace | ts | stats_used_bytes.max(stats_used_bytes.greptime_value) / stats_capacity_bytes.max(stats_capacity_bytes.greptime_value) |
|
||||
+------------+---------------------+-----------------------------------------------------------------------------------------------------------------------+
|
||||
| namespace1 | 1970-01-01T00:20:00 | 0.8333333333333334 |
|
||||
| namespace2 | 1970-01-01T00:20:00 | 0.8666666666666667 |
|
||||
+------------+---------------------+-----------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') max by (namespace) (stats_used_bytes{namespace=~".+"}) and (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100));
|
||||
|
||||
+------------+---------------------+--------------------------------------+
|
||||
| namespace | ts | max(stats_used_bytes.greptime_value) |
|
||||
+------------+---------------------+--------------------------------------+
|
||||
| namespace1 | 1970-01-01T00:20:00 | 25.0 |
|
||||
| namespace2 | 1970-01-01T00:20:00 | 26.0 |
|
||||
+------------+---------------------+--------------------------------------+
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') count(max by (namespace) (stats_used_bytes{namespace=~".+"}) and (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100))) or vector(0);
|
||||
|
||||
+---------------------+---------------------------------------------+
|
||||
| ts | count(max(stats_used_bytes.greptime_value)) |
|
||||
+---------------------+---------------------------------------------+
|
||||
| 1970-01-01T00:00:00 | 0 |
|
||||
| 1970-01-01T00:06:40 | 0 |
|
||||
| 1970-01-01T00:13:20 | 0 |
|
||||
| 1970-01-01T00:20:00 | 2 |
|
||||
| 1970-01-01T00:26:40 | 0 |
|
||||
| 1970-01-01T00:33:20 | 0 |
|
||||
+---------------------+---------------------------------------------+
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') count(max by (namespace) (stats_used_bytes{namespace=~".+"}) and (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100)));
|
||||
|
||||
+---------------------+---------------------------------------------+
|
||||
| ts | count(max(stats_used_bytes.greptime_value)) |
|
||||
+---------------------+---------------------------------------------+
|
||||
| 1970-01-01T00:20:00 | 2 |
|
||||
+---------------------+---------------------------------------------+
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') count(max by (namespace) (stats_used_bytes{namespace=~".+"}) unless (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100)));
|
||||
|
||||
+---------------------+---------------------------------------------+
|
||||
| ts | count(max(stats_used_bytes.greptime_value)) |
|
||||
+---------------------+---------------------------------------------+
|
||||
| 1970-01-01T00:00:00 | 2 |
|
||||
| 1970-01-01T00:13:20 | 2 |
|
||||
+---------------------+---------------------------------------------+
|
||||
|
||||
drop table stats_used_bytes;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
drop table stats_capacity_bytes;
|
||||
|
||||
Affected Rows: 0
|
||||
|
||||
create table cache_hit (
|
||||
ts timestamp time index,
|
||||
job string,
|
||||
|
||||
@@ -207,6 +207,56 @@ drop table t1;
|
||||
|
||||
drop table t2;
|
||||
|
||||
create table stats_used_bytes (
|
||||
ts timestamp time index,
|
||||
namespace string,
|
||||
greptime_value double,
|
||||
primary key (namespace)
|
||||
);
|
||||
|
||||
create table stats_capacity_bytes (
|
||||
ts timestamp time index,
|
||||
namespace string,
|
||||
greptime_value double,
|
||||
primary key (namespace)
|
||||
);
|
||||
|
||||
insert into stats_used_bytes values
|
||||
(0, "namespace1", 1.0),
|
||||
(0, "namespace2", 2.0),
|
||||
(500000, "namespace1", 10.0),
|
||||
(500000, "namespace2", 20.0),
|
||||
(1000000, "namespace1", 25.0),
|
||||
(1000000, "namespace2", 26.0);
|
||||
|
||||
insert into stats_capacity_bytes values
|
||||
(0, "namespace1", 30.0),
|
||||
(0, "namespace2", 30.0),
|
||||
(500000, "namespace1", 30.0),
|
||||
(500000, "namespace2", 30.0),
|
||||
(1000000, "namespace1", 30.0),
|
||||
(1000000, "namespace2", 30.0);
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') max by (namespace) (stats_used_bytes{namespace=~".+"}) / max by (namespace) (stats_capacity_bytes{namespace=~".+"}) >= (80 / 100);
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') max by (namespace) (stats_used_bytes{namespace=~".+"}) and (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100));
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') count(max by (namespace) (stats_used_bytes{namespace=~".+"}) and (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100))) or vector(0);
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') count(max by (namespace) (stats_used_bytes{namespace=~".+"}) and (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100)));
|
||||
|
||||
-- SQLNESS SORT_RESULT 3 1
|
||||
tql eval (0, 2000, '400') count(max by (namespace) (stats_used_bytes{namespace=~".+"}) unless (max by (namespace) (stats_used_bytes{namespace=~".+"}) / (max by (namespace) (stats_capacity_bytes{namespace=~".+"})) >= (80 / 100)));
|
||||
|
||||
drop table stats_used_bytes;
|
||||
|
||||
drop table stats_capacity_bytes;
|
||||
|
||||
|
||||
create table cache_hit (
|
||||
ts timestamp time index,
|
||||
job string,
|
||||
|
||||
Reference in New Issue
Block a user