mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-31 15:06:26 +00:00
wip
This commit is contained in:
parent
e25b2e7f05
commit
e8e49405ef
2 changed files with 70 additions and 34 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/slicesutil"
|
||||||
)
|
)
|
||||||
|
@ -312,7 +313,9 @@ func (shard *pipeMathProcessorShard) executeExpr(me *mathExpr, br *blockResult)
|
||||||
shard.executeExpr(arg, br)
|
shard.executeExpr(arg, br)
|
||||||
}
|
}
|
||||||
|
|
||||||
me.f(shard.rs[rIdx], shard.rs[rIdx+1:])
|
result := shard.rs[rIdx]
|
||||||
|
args := shard.rs[rIdx+1:]
|
||||||
|
me.f(result, args)
|
||||||
|
|
||||||
shard.rs = shard.rs[:rIdx+1]
|
shard.rs = shard.rs[:rIdx+1]
|
||||||
shard.rsBuf = shard.rsBuf[:rsBufLen]
|
shard.rsBuf = shard.rsBuf[:rsBufLen]
|
||||||
|
@ -386,14 +389,14 @@ func parseMathEntry(lex *lexer) (*mathEntry, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lex.isKeyword("as") {
|
// skip optional 'as'
|
||||||
return nil, fmt.Errorf("missing 'as' after [%s]", me)
|
if lex.isKeyword("as") {
|
||||||
|
lex.nextToken()
|
||||||
}
|
}
|
||||||
lex.nextToken()
|
|
||||||
|
|
||||||
resultField, err := parseFieldName(lex)
|
resultField, err := parseFieldName(lex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot parse result name: %w", err)
|
return nil, fmt.Errorf("cannot parse result name for [%s]: %w", me, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := &mathEntry{
|
e := &mathEntry{
|
||||||
|
@ -410,12 +413,12 @@ func parseMathExpr(lex *lexer) (*mathExpr, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if lex.isKeyword("as", "|", ")", ",", "") {
|
|
||||||
// There is no right operand
|
|
||||||
return left, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
if !isMathBinaryOp(lex.token) {
|
||||||
|
// There is no right operand
|
||||||
|
return left, nil
|
||||||
|
}
|
||||||
|
|
||||||
// parse operator
|
// parse operator
|
||||||
op := lex.token
|
op := lex.token
|
||||||
lex.nextToken()
|
lex.nextToken()
|
||||||
|
@ -444,11 +447,7 @@ func parseMathExpr(lex *lexer) (*mathExpr, error) {
|
||||||
me = left
|
me = left
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lex.isKeyword("as", "|", ")", ",", "") {
|
left = me
|
||||||
left = me
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return me, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,10 +478,12 @@ func parseMathExprOperand(lex *lexer) (*mathExpr, error) {
|
||||||
switch {
|
switch {
|
||||||
case lex.isKeyword("abs"):
|
case lex.isKeyword("abs"):
|
||||||
return parseMathExprAbs(lex)
|
return parseMathExprAbs(lex)
|
||||||
case lex.isKeyword("min"):
|
|
||||||
return parseMathExprMin(lex)
|
|
||||||
case lex.isKeyword("max"):
|
case lex.isKeyword("max"):
|
||||||
return parseMathExprMax(lex)
|
return parseMathExprMax(lex)
|
||||||
|
case lex.isKeyword("min"):
|
||||||
|
return parseMathExprMin(lex)
|
||||||
|
case lex.isKeyword("round"):
|
||||||
|
return parseMathExprRound(lex)
|
||||||
case lex.isKeyword("-"):
|
case lex.isKeyword("-"):
|
||||||
return parseMathExprUnaryMinus(lex)
|
return parseMathExprUnaryMinus(lex)
|
||||||
case lex.isKeyword("+"):
|
case lex.isKeyword("+"):
|
||||||
|
@ -507,6 +508,17 @@ func parseMathExprAbs(lex *lexer) (*mathExpr, error) {
|
||||||
return me, nil
|
return me, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseMathExprMax(lex *lexer) (*mathExpr, error) {
|
||||||
|
me, err := parseMathExprGenericFunc(lex, "max", mathFuncMax)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(me.args) < 2 {
|
||||||
|
return nil, fmt.Errorf("'max' function needs at least 2 args; got %d args: [%s]", len(me.args), me)
|
||||||
|
}
|
||||||
|
return me, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseMathExprMin(lex *lexer) (*mathExpr, error) {
|
func parseMathExprMin(lex *lexer) (*mathExpr, error) {
|
||||||
me, err := parseMathExprGenericFunc(lex, "min", mathFuncMin)
|
me, err := parseMathExprGenericFunc(lex, "min", mathFuncMin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -518,13 +530,13 @@ func parseMathExprMin(lex *lexer) (*mathExpr, error) {
|
||||||
return me, nil
|
return me, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseMathExprMax(lex *lexer) (*mathExpr, error) {
|
func parseMathExprRound(lex *lexer) (*mathExpr, error) {
|
||||||
me, err := parseMathExprGenericFunc(lex, "max", mathFuncMax)
|
me, err := parseMathExprGenericFunc(lex, "round", mathFuncRound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(me.args) < 2 {
|
if len(me.args) != 2 {
|
||||||
return nil, fmt.Errorf("'max' function needs at least 2 args; got %d args: [%s]", len(me.args), me)
|
return nil, fmt.Errorf("'round' function needs 2 args; got %d args: [%s]", len(me.args), me)
|
||||||
}
|
}
|
||||||
return me, nil
|
return me, nil
|
||||||
}
|
}
|
||||||
|
@ -618,7 +630,7 @@ func parseMathExprConstNumber(lex *lexer) (*mathExpr, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseMathExprFieldName(lex *lexer) (*mathExpr, error) {
|
func parseMathExprFieldName(lex *lexer) (*mathExpr, error) {
|
||||||
fieldName, err := parseFieldName(lex)
|
fieldName, err := getCompoundMathToken(lex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -711,6 +723,18 @@ func mathFuncUnaryMinus(result []float64, args [][]float64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mathFuncMax(result []float64, args [][]float64) {
|
||||||
|
for i := range result {
|
||||||
|
f := nan
|
||||||
|
for _, arg := range args {
|
||||||
|
if math.IsNaN(f) || arg[i] > f {
|
||||||
|
f = arg[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[i] = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func mathFuncMin(result []float64, args [][]float64) {
|
func mathFuncMin(result []float64, args [][]float64) {
|
||||||
for i := range result {
|
for i := range result {
|
||||||
f := nan
|
f := nan
|
||||||
|
@ -723,14 +747,23 @@ func mathFuncMin(result []float64, args [][]float64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mathFuncMax(result []float64, args [][]float64) {
|
func mathFuncRound(result []float64, args [][]float64) {
|
||||||
|
arg := args[0]
|
||||||
|
nearest := args[1]
|
||||||
|
var f float64
|
||||||
for i := range result {
|
for i := range result {
|
||||||
f := nan
|
if i == 0 || arg[i-1] != arg[i] || nearest[i-1] != nearest[i] {
|
||||||
for _, arg := range args {
|
f = round(arg[i], nearest[i])
|
||||||
if math.IsNaN(f) || arg[i] > f {
|
|
||||||
f = arg[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result[i] = f
|
result[i] = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func round(f, nearest float64) float64 {
|
||||||
|
_, e := decimal.FromFloat(nearest)
|
||||||
|
p10 := math.Pow10(int(-e))
|
||||||
|
f += 0.5 * math.Copysign(nearest, f)
|
||||||
|
f -= math.Mod(f, nearest)
|
||||||
|
f, _ = math.Modf(f * p10)
|
||||||
|
return f / p10
|
||||||
|
}
|
||||||
|
|
|
@ -14,12 +14,13 @@ func TestParsePipeMathSuccess(t *testing.T) {
|
||||||
f(`math -123 as a`)
|
f(`math -123 as a`)
|
||||||
f(`math 12.345KB as a`)
|
f(`math 12.345KB as a`)
|
||||||
f(`math (-2 + 2) as a`)
|
f(`math (-2 + 2) as a`)
|
||||||
f(`math min(3, foo, (1 + bar) / baz) as a, max(a, b) as b, (abs(c) + 5) as d`)
|
|
||||||
f(`math x as a, z as y`)
|
f(`math x as a, z as y`)
|
||||||
f(`math (foo / bar + baz * abc % -45ms) as a`)
|
f(`math (foo / bar + baz * abc % -45ms) as a`)
|
||||||
f(`math (foo / (bar + baz) * abc ^ 2) as a`)
|
f(`math (foo / (bar + baz) * abc ^ 2) as a`)
|
||||||
f(`math (foo / ((bar + baz) * abc) ^ -2) as a`)
|
f(`math (foo / ((bar + baz) * abc) ^ -2) as a`)
|
||||||
f(`math (foo + bar / baz - abc) as a`)
|
f(`math (foo + bar / baz - abc) as a`)
|
||||||
|
f(`math min(3, foo, (1 + bar) / baz) as a, max(a, b) as b, (abs(c) + 5) as d`)
|
||||||
|
f(`math round(foo, 0.1) as y`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParsePipeMathFailure(t *testing.T) {
|
func TestParsePipeMathFailure(t *testing.T) {
|
||||||
|
@ -30,7 +31,6 @@ func TestParsePipeMathFailure(t *testing.T) {
|
||||||
|
|
||||||
f(`math`)
|
f(`math`)
|
||||||
f(`math x`)
|
f(`math x`)
|
||||||
f(`math x y`)
|
|
||||||
f(`math x as`)
|
f(`math x as`)
|
||||||
f(`math abs() as x`)
|
f(`math abs() as x`)
|
||||||
f(`math abs(a, b) as x`)
|
f(`math abs(a, b) as x`)
|
||||||
|
@ -38,6 +38,9 @@ func TestParsePipeMathFailure(t *testing.T) {
|
||||||
f(`math min(a) as x`)
|
f(`math min(a) as x`)
|
||||||
f(`math max() as x`)
|
f(`math max() as x`)
|
||||||
f(`math max(a) as x`)
|
f(`math max(a) as x`)
|
||||||
|
f(`math round() as x`)
|
||||||
|
f(`math round(a) as x`)
|
||||||
|
f(`math round(a, b, c) as x`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPipeMath(t *testing.T) {
|
func TestPipeMath(t *testing.T) {
|
||||||
|
@ -60,7 +63,7 @@ func TestPipeMath(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
f("math 10 * 5 - 3 as a", [][]Field{
|
f("math 10 * 5 - 3 a", [][]Field{
|
||||||
{
|
{
|
||||||
{"a", "v1"},
|
{"a", "v1"},
|
||||||
{"b", "2"},
|
{"b", "2"},
|
||||||
|
@ -131,7 +134,7 @@ func TestPipeMath(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
f("math (2*c + (b%c))/(c-b)^(b-1) as a", [][]Field{
|
f("math round((2*c + (b%c))/(c-b)^(b-1), 0.001) as a", [][]Field{
|
||||||
{
|
{
|
||||||
{"a", "v"},
|
{"a", "v"},
|
||||||
{"b", "2"},
|
{"b", "2"},
|
||||||
|
@ -153,12 +156,12 @@ func TestPipeMath(t *testing.T) {
|
||||||
{"c", "3"},
|
{"c", "3"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{"a", "42.25"},
|
{"a", "3.25"},
|
||||||
{"b", "3"},
|
{"b", "3"},
|
||||||
{"c", "5"},
|
{"c", "5"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{"a", "25"},
|
{"a", "1.667"},
|
||||||
{"b", "3"},
|
{"b", "3"},
|
||||||
{"c", "6"},
|
{"c", "6"},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue