This commit is contained in:
Aliaksandr Valialkin 2024-05-30 14:48:36 +02:00
parent a53b5570eb
commit b021020e03
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
4 changed files with 42 additions and 21 deletions

View file

@ -20,6 +20,7 @@ according to [these docs](https://docs.victoriametrics.com/victorialogs/quicksta
## tip
* FEATURE: add `default` operator to [`math` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#math-pipe). It allows setting `NaN` result to the given default value.
* FEATURE: allow omitting result name in [`math` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#math-pipe) expresions. In this case the result name is automatically set to string representation of the corresponding math expression. For example, `_time:5m | math duration / 1000` is equivalent to `_time:5m | math (duration / 1000) as "duration / 1000"`.
* FEATURE: allow omitting result name in [`stats` pipe](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe). In this case the result name is automatically set to string representation of the corresponding [stats function expression](https://docs.victoriametrics.com/victorialogs/logsql/#stats-pipe-functions). For example, `_time:5m | count(*)` is valid [LogsQL query](https://docs.victoriametrics.com/victorialogs/logsql/) now. It is equivalent to `_time:5m | stats count(*) as "count(*)"`.
* BUGFIX: properly calculate the number of matching rows in `* | field_values x | stats count() rows` and in `* | unroll (x) | stats count() rows` queries.

View file

@ -1594,6 +1594,19 @@ See also:
### math pipe
`| math ...` [pipe](#pipes) performs mathematical calculations over numeric values stored in [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model).
It has the following format:
```
| math
expr1 as resultName1,
...
exprN as resultNameN
```
Where `exprX` is one of the supported math expressions mentioned below, while `resultNameX` is the name of the field to store the calculated result to.
The `as` keyword is optional. The result name can be omitted. In this case the result is stored to a field with the name equal to string represenation
of the corresponding math expression.
For example, the following query divides `duration_msecs` field value by 1000, then rounds it to integer and stores the result in the `duration_secs` field:
```logsql
@ -1621,15 +1634,6 @@ Every `argX` argument in every mathematical operation can contain one of the fol
- Any [supported numeric value](#numeric-values). For example, `response_size_bytes / 1MiB`.
- Another mathematical expression. Optionally, it may be put inside `(...)`. For example, `(a + b) * c`.
Multiple distinct results can be calculated in a single `math ...` pipe - just separate them with `,`. For example, the following query calculates the error rate
and the number of successful requests from `errors`, `warnings` and `requests` [log fields](https://docs.victoriametrics.com/victorialogs/keyconcepts/#data-model):
```logsql
_time:5m | math
(errors / requests) as error_rate,
(requests - (errors + warnings)) as success_requests
```
See also:
- [`stats` pipe](#stats-pipe)

View file

@ -384,14 +384,20 @@ func parseMathEntry(lex *lexer) (*mathEntry, error) {
return nil, err
}
// skip optional 'as'
if lex.isKeyword("as") {
lex.nextToken()
}
resultField := ""
if lex.isKeyword(",", "|", ")", "") {
resultField = me.String()
} else {
if lex.isKeyword("as") {
// skip optional 'as'
lex.nextToken()
}
resultField, err := parseFieldName(lex)
if err != nil {
return nil, fmt.Errorf("cannot parse result name for [%s]: %w", me, err)
fieldName, err := parseFieldName(lex)
if err != nil {
return nil, fmt.Errorf("cannot parse result name for [%s]: %w", me, err)
}
resultField = fieldName
}
e := &mathEntry{

View file

@ -32,7 +32,6 @@ func TestParsePipeMathFailure(t *testing.T) {
}
f(`math`)
f(`math x`)
f(`math x as`)
f(`math abs() as x`)
f(`math abs(a, b) as x`)
@ -64,7 +63,7 @@ func TestPipeMath(t *testing.T) {
},
})
f("math a / b default 10 as c", [][]Field{
f("math a / b default c", [][]Field{
{
{"a", "v1"},
{"b", "2"},
@ -79,21 +78,32 @@ func TestPipeMath(t *testing.T) {
{"a", "3"},
{"b", "2"},
},
{
{"a", "3"},
{"b", "foo"},
},
}, [][]Field{
{
{"a", "v1"},
{"b", "2"},
{"c", "10"},
{"c", "3"},
{"a / b default c", "3"},
},
{
{"a", "0"},
{"b", "0"},
{"c", "10"},
{"c", "3"},
{"a / b default c", "3"},
},
{
{"a", "3"},
{"b", "2"},
{"c", "1.5"},
{"a / b default c", "1.5"},
},
{
{"a", "3"},
{"b", "foo"},
{"a / b default c", "NaN"},
},
})