mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-27 06:29:42 -08:00
promql: add power binary operation
This commit is contained in:
parent
f55a1d463d
commit
2fdc5717a3
|
@ -991,6 +991,8 @@ func scalarBinop(op itemType, lhs, rhs model.SampleValue) model.SampleValue {
|
||||||
return lhs * rhs
|
return lhs * rhs
|
||||||
case itemDIV:
|
case itemDIV:
|
||||||
return lhs / rhs
|
return lhs / rhs
|
||||||
|
case itemPOW:
|
||||||
|
return model.SampleValue(math.Pow(float64(lhs), float64(rhs)))
|
||||||
case itemMOD:
|
case itemMOD:
|
||||||
if rhs != 0 {
|
if rhs != 0 {
|
||||||
return model.SampleValue(int(lhs) % int(rhs))
|
return model.SampleValue(int(lhs) % int(rhs))
|
||||||
|
@ -1023,6 +1025,8 @@ func vectorElemBinop(op itemType, lhs, rhs model.SampleValue) (model.SampleValue
|
||||||
return lhs * rhs, true
|
return lhs * rhs, true
|
||||||
case itemDIV:
|
case itemDIV:
|
||||||
return lhs / rhs, true
|
return lhs / rhs, true
|
||||||
|
case itemPOW:
|
||||||
|
return model.SampleValue(math.Pow(float64(lhs), float64(rhs))), true
|
||||||
case itemMOD:
|
case itemMOD:
|
||||||
if rhs != 0 {
|
if rhs != 0 {
|
||||||
return model.SampleValue(int(lhs) % int(rhs)), true
|
return model.SampleValue(int(lhs) % int(rhs)), true
|
||||||
|
|
|
@ -100,11 +100,23 @@ func (i itemType) precedence() int {
|
||||||
return 4
|
return 4
|
||||||
case itemMUL, itemDIV, itemMOD:
|
case itemMUL, itemDIV, itemMOD:
|
||||||
return 5
|
return 5
|
||||||
|
case itemPOW:
|
||||||
|
return 6
|
||||||
default:
|
default:
|
||||||
return LowestPrec
|
return LowestPrec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i itemType) isRightAssociative() bool {
|
||||||
|
switch i {
|
||||||
|
case itemPOW:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
type itemType int
|
type itemType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -146,6 +158,7 @@ const (
|
||||||
itemGTR
|
itemGTR
|
||||||
itemEQLRegex
|
itemEQLRegex
|
||||||
itemNEQRegex
|
itemNEQRegex
|
||||||
|
itemPOW
|
||||||
operatorsEnd
|
operatorsEnd
|
||||||
|
|
||||||
aggregatorsStart
|
aggregatorsStart
|
||||||
|
@ -248,6 +261,7 @@ var itemTypeStr = map[itemType]string{
|
||||||
itemGTR: ">",
|
itemGTR: ">",
|
||||||
itemEQLRegex: "=~",
|
itemEQLRegex: "=~",
|
||||||
itemNEQRegex: "!~",
|
itemNEQRegex: "!~",
|
||||||
|
itemPOW: "^",
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -471,6 +485,8 @@ func lexStatements(l *lexer) stateFn {
|
||||||
l.emit(itemADD)
|
l.emit(itemADD)
|
||||||
case r == '-':
|
case r == '-':
|
||||||
l.emit(itemSUB)
|
l.emit(itemSUB)
|
||||||
|
case r == '^':
|
||||||
|
l.emit(itemPOW)
|
||||||
case r == '=':
|
case r == '=':
|
||||||
if t := l.peek(); t == '=' {
|
if t := l.peek(); t == '=' {
|
||||||
l.next()
|
l.next()
|
||||||
|
|
|
@ -208,6 +208,9 @@ var tests = []struct {
|
||||||
}, {
|
}, {
|
||||||
input: `/`,
|
input: `/`,
|
||||||
expected: []item{{itemDIV, 0, `/`}},
|
expected: []item{{itemDIV, 0, `/`}},
|
||||||
|
}, {
|
||||||
|
input: `^`,
|
||||||
|
expected: []item{{itemPOW, 0, `^`}},
|
||||||
}, {
|
}, {
|
||||||
input: `%`,
|
input: `%`,
|
||||||
expected: []item{{itemMOD, 0, `%`}},
|
expected: []item{{itemMOD, 0, `%`}},
|
||||||
|
|
|
@ -500,17 +500,20 @@ func (p *parser) expr() Expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) balance(lhs Expr, op itemType, rhs Expr, vecMatching *VectorMatching, returnBool bool) *BinaryExpr {
|
func (p *parser) balance(lhs Expr, op itemType, rhs Expr, vecMatching *VectorMatching, returnBool bool) *BinaryExpr {
|
||||||
if lhsBE, ok := lhs.(*BinaryExpr); ok && lhsBE.Op.precedence() < op.precedence() {
|
if lhsBE, ok := lhs.(*BinaryExpr); ok {
|
||||||
balanced := p.balance(lhsBE.RHS, op, rhs, vecMatching, returnBool)
|
precd := lhsBE.Op.precedence() - op.precedence()
|
||||||
if lhsBE.Op.isComparisonOperator() && !lhsBE.ReturnBool && balanced.Type() == model.ValScalar && lhsBE.LHS.Type() == model.ValScalar {
|
if (precd < 0) || (precd == 0 && op.isRightAssociative()) {
|
||||||
p.errorf("comparisons between scalars must use BOOL modifier")
|
balanced := p.balance(lhsBE.RHS, op, rhs, vecMatching, returnBool)
|
||||||
}
|
if lhsBE.Op.isComparisonOperator() && !lhsBE.ReturnBool && balanced.Type() == model.ValScalar && lhsBE.LHS.Type() == model.ValScalar {
|
||||||
return &BinaryExpr{
|
p.errorf("comparisons between scalars must use BOOL modifier")
|
||||||
Op: lhsBE.Op,
|
}
|
||||||
LHS: lhsBE.LHS,
|
return &BinaryExpr{
|
||||||
RHS: balanced,
|
Op: lhsBE.Op,
|
||||||
VectorMatching: lhsBE.VectorMatching,
|
LHS: lhsBE.LHS,
|
||||||
ReturnBool: lhsBE.ReturnBool,
|
RHS: balanced,
|
||||||
|
VectorMatching: lhsBE.VectorMatching,
|
||||||
|
ReturnBool: lhsBE.ReturnBool,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if op.isComparisonOperator() && !returnBool && rhs.Type() == model.ValScalar && lhs.Type() == model.ValScalar {
|
if op.isComparisonOperator() && !returnBool && rhs.Type() == model.ValScalar && lhs.Type() == model.ValScalar {
|
||||||
|
|
25
promql/testdata/operators.test
vendored
25
promql/testdata/operators.test
vendored
|
@ -8,7 +8,6 @@ load 5m
|
||||||
http_requests{job="app-server", instance="0", group="canary"} 0+70x10
|
http_requests{job="app-server", instance="0", group="canary"} 0+70x10
|
||||||
http_requests{job="app-server", instance="1", group="canary"} 0+80x10
|
http_requests{job="app-server", instance="1", group="canary"} 0+80x10
|
||||||
|
|
||||||
|
|
||||||
load 5m
|
load 5m
|
||||||
vector_matching_a{l="x"} 0+1x100
|
vector_matching_a{l="x"} 0+1x100
|
||||||
vector_matching_a{l="y"} 0+2x50
|
vector_matching_a{l="y"} 0+2x50
|
||||||
|
@ -35,6 +34,30 @@ eval instant at 50m SUM(http_requests) BY (job) % 3
|
||||||
{job="api-server"} 1
|
{job="api-server"} 1
|
||||||
{job="app-server"} 2
|
{job="app-server"} 2
|
||||||
|
|
||||||
|
eval instant at 50m SUM(http_requests) BY (job) ^ 2
|
||||||
|
{job="api-server"} 1000000
|
||||||
|
{job="app-server"} 6760000
|
||||||
|
|
||||||
|
eval instant at 50m SUM(http_requests) BY (job) % 3 ^ 2
|
||||||
|
{job="api-server"} 1
|
||||||
|
{job="app-server"} 8
|
||||||
|
|
||||||
|
eval instant at 50m SUM(http_requests) BY (job) % 2 ^ (3 ^ 2)
|
||||||
|
{job="api-server"} 488
|
||||||
|
{job="app-server"} 40
|
||||||
|
|
||||||
|
eval instant at 50m SUM(http_requests) BY (job) % 2 ^ 3 ^ 2
|
||||||
|
{job="api-server"} 488
|
||||||
|
{job="app-server"} 40
|
||||||
|
|
||||||
|
eval instant at 50m SUM(http_requests) BY (job) % 2 ^ 3 ^ 2 ^ 2
|
||||||
|
{job="api-server"} 1000
|
||||||
|
{job="app-server"} 2600
|
||||||
|
|
||||||
|
eval instant at 50m COUNT(http_requests) BY (job) ^ COUNT(http_requests) BY (job)
|
||||||
|
{job="api-server"} 256
|
||||||
|
{job="app-server"} 256
|
||||||
|
|
||||||
eval instant at 50m SUM(http_requests) BY (job) / 0
|
eval instant at 50m SUM(http_requests) BY (job) / 0
|
||||||
{job="api-server"} +Inf
|
{job="api-server"} +Inf
|
||||||
{job="app-server"} +Inf
|
{job="app-server"} +Inf
|
||||||
|
|
Loading…
Reference in a new issue