fix: use str_match replace LIKE for contains for alert (#7670)

### **User description**
str_match we can use secondary index now.


___

### **PR Type**
Bug fix, Enhancement


___

### **Description**
- Expose secondary index fields in config response  

- Replace SQL LIKE with `str_match` for contains


___



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Configuration
changes</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>mod.rs</strong><dd><code>Expose secondary index in
config response</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

src/handler/http/request/status/mod.rs

<ul><li>Imported <code>SQL_SECONDARY_INDEX_SEARCH_FIELDS</code> constant
<br> <li> Added <code>default_secondary_index_fields</code> to
<code>ConfigResponse</code> <br> <li> Populated new field in
<code>zo_config</code> handler</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7670/files#diff-ca09c9c9b020049bdbc3382c466bfcca80daac92e98760d9a9a76172abf34049">+7/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Bug fix</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>mod.rs</strong><dd><code>Use `str_match` for contains
operator</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></summary>
<hr>

src/service/alerts/mod.rs

<ul><li>Replaced <code>LIKE '%value%'</code> with <code>str_match</code>
for <code>Contains</code> <br> <li> Left <code>NotContains</code> using
<code>NOT LIKE</code> unchanged</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/7670/files#diff-ba9b65130898444f7815fd6068bdb0dc590612f74cc893f79d91b0afc44cc851">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

</details>

___
This commit is contained in:
Hengfei Yang
2025-07-23 12:08:54 +08:00
committed by GitHub
parent c2cd361b25
commit 0329bbdbec
3 changed files with 58 additions and 56 deletions
+20 -13
View File
@@ -117,20 +117,27 @@ pub static SQL_FULL_TEXT_SEARCH_FIELDS: Lazy<Vec<String>> = Lazy::new(|| {
fields
});
const _DEFAULT_SQL_SECONDARY_INDEX_SEARCH_FIELDS: [&str; 3] =
["trace_id", "service_name", "operation_name"];
pub static SQL_SECONDARY_INDEX_SEARCH_FIELDS: Lazy<Vec<String>> = Lazy::new(|| {
let mut fields = get_config()
.common
.feature_secondary_index_extra_fields
.split(',')
.filter_map(|s| {
let s = s.trim();
if s.is_empty() {
None
} else {
Some(s.to_string())
}
})
.collect::<Vec<_>>();
let mut fields = chain(
_DEFAULT_SQL_SECONDARY_INDEX_SEARCH_FIELDS
.iter()
.map(|s| s.to_string()),
get_config()
.common
.feature_secondary_index_extra_fields
.split(',')
.filter_map(|s| {
let s = s.trim();
if s.is_empty() {
None
} else {
Some(s.to_string())
}
}),
)
.collect::<Vec<_>>();
fields.sort();
fields.dedup();
fields
+7 -1
View File
@@ -24,7 +24,8 @@ use actix_web::{
};
use arrow_schema::Schema;
use config::{
Config, META_ORG_ID, QUICK_MODEL_FIELDS, SQL_FULL_TEXT_SEARCH_FIELDS, TIMESTAMP_COL_NAME,
Config, META_ORG_ID, QUICK_MODEL_FIELDS, SQL_FULL_TEXT_SEARCH_FIELDS,
SQL_SECONDARY_INDEX_SEARCH_FIELDS, TIMESTAMP_COL_NAME,
cluster::LOCAL_NODE,
get_config, get_instance_id,
meta::{
@@ -92,6 +93,7 @@ struct ConfigResponse<'a> {
build_date: String,
build_type: String,
default_fts_keys: Vec<String>,
default_secondary_index_fields: Vec<String>,
default_quick_mode_fields: Vec<String>,
telemetry_enabled: bool,
default_functions: Vec<ZoFunction<'a>>,
@@ -288,6 +290,10 @@ pub async fn zo_config() -> Result<HttpResponse, Error> {
.iter()
.map(|s| s.to_string())
.collect(),
default_secondary_index_fields: SQL_SECONDARY_INDEX_SEARCH_FIELDS
.iter()
.map(|s| s.to_string())
.collect(),
default_quick_mode_fields: QUICK_MODEL_FIELDS.to_vec(),
default_functions: DEFAULT_FUNCTIONS.to_vec(),
sql_base64_enabled: cfg.common.ui_sql_base64_enabled,
+31 -42
View File
@@ -689,7 +689,7 @@ async fn build_sql(
let where_sql = conditions
.to_sql(&schema)
.await
.map_err(|err| anyhow::anyhow!("Error building SQL on stream {}: {}", &stream_name, err))?;
.map_err(|err| anyhow::anyhow!("Error building SQL on stream {stream_name}: {err}"))?;
if query_condition.aggregation.is_none() {
return Ok(format!("SELECT * FROM \"{stream_name}\" WHERE {where_sql}"));
}
@@ -702,9 +702,8 @@ async fn build_sql(
Ok(field) => field.data_type(),
Err(_) => {
return Err(anyhow::anyhow!(
"Aggregation column {} not found on stream {}",
"Aggregation column {} not found on stream {stream_name}",
&agg.having.column,
&stream_name
));
}
};
@@ -766,17 +765,17 @@ fn build_expr(
cond.value.to_string()
};
match cond.operator {
Operator::EqualTo => format!("\"{}\" {} '{}'", field_alias, "=", val),
Operator::NotEqualTo => format!("\"{}\" {} '{}'", field_alias, "!=", val),
Operator::GreaterThan => format!("\"{}\" {} '{}'", field_alias, ">", val),
Operator::EqualTo => format!("\"{field_alias}\" = '{val}'"),
Operator::NotEqualTo => format!("\"{field_alias}\" != '{val}'"),
Operator::GreaterThan => format!("\"{field_alias}\" > '{val}'"),
Operator::GreaterThanEquals => {
format!("\"{}\" {} '{}'", field_alias, ">=", val)
format!("\"{field_alias}\" >= '{val}'")
}
Operator::LessThan => format!("\"{}\" {} '{}'", field_alias, "<", val),
Operator::LessThanEquals => format!("\"{}\" {} '{}'", field_alias, "<=", val),
Operator::Contains => format!("\"{}\" {} '%{}%'", field_alias, "LIKE", val),
Operator::LessThan => format!("\"{field_alias}\" < '{val}'"),
Operator::LessThanEquals => format!("\"{field_alias}\" <= '{val}'"),
Operator::Contains => format!("str_match(\"{field_alias}\", '%{val}%')"),
Operator::NotContains => {
format!("\"{}\" {} '%{}%'", field_alias, "NOT LIKE", val)
format!("\"{field_alias}\" NOT LIKE '%{val}%'")
}
}
}
@@ -790,30 +789,27 @@ fn build_expr(
.parse()
.map_err(|e| {
anyhow::anyhow!(
"Column [{}] dataType is [{}] but value is [{}], err: {}",
"Column [{}] dataType is [{field_type}] but value is [{}], err: {e}",
cond.column,
field_type,
cond.value,
e
)
})?
};
match cond.operator {
Operator::EqualTo => format!("\"{}\" {} {}", field_alias, "=", val),
Operator::NotEqualTo => format!("\"{}\" {} {}", field_alias, "!=", val),
Operator::GreaterThan => format!("\"{}\" {} {}", field_alias, ">", val),
Operator::EqualTo => format!("\"{field_alias}\" = {val}"),
Operator::NotEqualTo => format!("\"{field_alias}\" != {val}"),
Operator::GreaterThan => format!("\"{field_alias}\" > {val}"),
Operator::GreaterThanEquals => {
format!("\"{}\" {} {}", field_alias, ">=", val)
format!("\"{field_alias}\" >= {val}")
}
Operator::LessThan => format!("\"{}\" {} {}", field_alias, "<", val),
Operator::LessThan => format!("\"{field_alias}\" < {val}"),
Operator::LessThanEquals => {
format!("\"{}\" {} {}", field_alias, "<=", val)
format!("\"{field_alias}\" <= {val}")
}
_ => {
return Err(anyhow::anyhow!(
"Column {} has data_type [{}] and it does not supported operator [{:?}]",
"Column {} has data_type [{field_type}] and it does not supported operator [{:?}]",
cond.column,
field_type,
cond.operator
));
}
@@ -829,30 +825,27 @@ fn build_expr(
.parse()
.map_err(|e| {
anyhow::anyhow!(
"Column [{}] dataType is [{}] but value is [{}], err: {}",
"Column [{}] dataType is [{field_type}] but value is [{}], err: {e}",
cond.column,
field_type,
cond.value,
e
)
})?
};
match cond.operator {
Operator::EqualTo => format!("\"{}\" {} {}", field_alias, "=", val),
Operator::NotEqualTo => format!("\"{}\" {} {}", field_alias, "!=", val),
Operator::GreaterThan => format!("\"{}\" {} {}", field_alias, ">", val),
Operator::EqualTo => format!("\"{field_alias}\" = {val}"),
Operator::NotEqualTo => format!("\"{field_alias}\" != {val}"),
Operator::GreaterThan => format!("\"{field_alias}\" > {val}"),
Operator::GreaterThanEquals => {
format!("\"{}\" {} {}", field_alias, ">=", val)
format!("\"{field_alias}\" >= {val}")
}
Operator::LessThan => format!("\"{}\" {} {}", field_alias, "<", val),
Operator::LessThan => format!("\"{field_alias}\" < {val}"),
Operator::LessThanEquals => {
format!("\"{}\" {} {}", field_alias, "<=", val)
format!("\"{field_alias}\" <= {val}")
}
_ => {
return Err(anyhow::anyhow!(
"Column {} has data_type [{}] and it does not supported operator [{:?}]",
"Column {} has data_type [{field_type}] and it does not supported operator [{:?}]",
cond.column,
field_type,
cond.operator
));
}
@@ -868,22 +861,19 @@ fn build_expr(
.parse()
.map_err(|e| {
anyhow::anyhow!(
"Column [{}] dataType is [{}] but value is [{}], err: {}",
"Column [{}] dataType is [{field_type}] but value is [{}], err: {e}",
cond.column,
field_type,
cond.value,
e
)
})?
};
match cond.operator {
Operator::EqualTo => format!("\"{}\" {} {}", field_alias, "=", val),
Operator::NotEqualTo => format!("\"{}\" {} {}", field_alias, "!=", val),
Operator::EqualTo => format!("\"{field_alias}\" = {val}"),
Operator::NotEqualTo => format!("\"{field_alias}\" != {val}"),
_ => {
return Err(anyhow::anyhow!(
"Column {} has data_type [{}] and it does not supported operator [{:?}]",
"Column {} has data_type [{field_type}] and it does not supported operator [{:?}]",
cond.column,
field_type,
cond.operator
));
}
@@ -891,9 +881,8 @@ fn build_expr(
}
_ => {
return Err(anyhow::anyhow!(
"Column {} has data_type [{}] and it does not supported by alert, if you think this is a bug please report it to us",
"Column {} has data_type [{field_type}] and it does not supported by alert, if you think this is a bug please report it to us",
cond.column,
field_type
));
}
};