|
@@ -32,12 +32,13 @@ import (
|
|
|
)
|
|
|
|
|
|
type WindowConfig struct {
|
|
|
- Type ast.WindowType
|
|
|
- Length int64
|
|
|
- Interval int64 // If the interval is not set, it is equals to Length
|
|
|
- Delay int64
|
|
|
- RawInterval int
|
|
|
- TimeUnit ast.Token
|
|
|
+ TriggerCondition ast.Expr
|
|
|
+ Type ast.WindowType
|
|
|
+ Length int64
|
|
|
+ Interval int64 // If the interval is not set, it is equals to Length
|
|
|
+ Delay int64
|
|
|
+ RawInterval int
|
|
|
+ TimeUnit ast.Token
|
|
|
}
|
|
|
|
|
|
type WindowOperator struct {
|
|
@@ -50,9 +51,10 @@ type WindowOperator struct {
|
|
|
statManager metric.StatManager
|
|
|
ticker *clock.Ticker // For processing time only
|
|
|
// states
|
|
|
- triggerTime int64
|
|
|
- msgCount int
|
|
|
- delayTS []int64
|
|
|
+ triggerTime int64
|
|
|
+ msgCount int
|
|
|
+ delayTS []int64
|
|
|
+ triggerCondition ast.Expr
|
|
|
}
|
|
|
|
|
|
const (
|
|
@@ -91,6 +93,9 @@ func NewWindowOp(name string, w WindowConfig, options *api.RuleOption) (*WindowO
|
|
|
o.trigger = w
|
|
|
}
|
|
|
}
|
|
|
+ if w.TriggerCondition != nil {
|
|
|
+ o.triggerCondition = w.TriggerCondition
|
|
|
+ }
|
|
|
o.delayTS = make([]int64, 0)
|
|
|
return o, nil
|
|
|
}
|
|
@@ -331,16 +336,22 @@ func (o *WindowOperator) execProcessingWindow(ctx api.StreamContext, inputs []*x
|
|
|
case ast.NOT_WINDOW:
|
|
|
inputs = o.scan(inputs, d.Timestamp, ctx)
|
|
|
case ast.SLIDING_WINDOW:
|
|
|
- if o.window.Delay > 0 {
|
|
|
- go func(ts int64) {
|
|
|
- after := time.After(time.Duration(o.window.Delay) * time.Millisecond)
|
|
|
- select {
|
|
|
- case <-after:
|
|
|
- delayCh <- ts
|
|
|
- }
|
|
|
- }(d.Timestamp + o.window.Delay)
|
|
|
- } else {
|
|
|
+ if o.window.Type != ast.SLIDING_WINDOW {
|
|
|
inputs = o.scan(inputs, d.Timestamp, ctx)
|
|
|
+ } else {
|
|
|
+ if o.isMatchCondition(ctx, d) {
|
|
|
+ if o.window.Delay > 0 {
|
|
|
+ go func(ts int64) {
|
|
|
+ after := time.After(time.Duration(o.window.Delay) * time.Millisecond)
|
|
|
+ select {
|
|
|
+ case <-after:
|
|
|
+ delayCh <- ts
|
|
|
+ }
|
|
|
+ }(d.Timestamp + o.window.Delay)
|
|
|
+ } else {
|
|
|
+ inputs = o.scan(inputs, d.Timestamp, ctx)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
case ast.SESSION_WINDOW:
|
|
|
if timeoutTicker != nil {
|
|
@@ -598,3 +609,27 @@ func (o *WindowOperator) GetMetrics() [][]interface{} {
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func (o *WindowOperator) isMatchCondition(ctx api.StreamContext, d *xsql.Tuple) bool {
|
|
|
+ if o.triggerCondition == nil || o.window.Type != ast.SLIDING_WINDOW {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ log := ctx.GetLogger()
|
|
|
+ fv, _ := xsql.NewFunctionValuersForOp(ctx)
|
|
|
+ ve := &xsql.ValuerEval{Valuer: xsql.MultiValuer(d, fv)}
|
|
|
+ result := ve.Eval(o.triggerCondition)
|
|
|
+ // not match trigger condition
|
|
|
+ if result == nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ switch v := result.(type) {
|
|
|
+ case error:
|
|
|
+ log.Errorf("window %s trigger condition meet error: %v", o.name, v)
|
|
|
+ return false
|
|
|
+ case bool:
|
|
|
+ // match trigger condition
|
|
|
+ return v
|
|
|
+ default:
|
|
|
+ return false
|
|
|
+ }
|
|
|
+}
|