-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed optimized (wrapped) percentiles #84
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,74 +2,40 @@ package expr | |
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/getlantern/goexpr" | ||
"github.com/getlantern/msgpack" | ||
) | ||
|
||
// PERCENTILEOPT returns an optimized PERCENTILE that wraps an existing | ||
// PERCENTILE and reuses its storage. | ||
// PERCENTILE. | ||
func PERCENTILEOPT(wrapped interface{}, percentile interface{}) Expr { | ||
var expr Expr | ||
switch t := wrapped.(type) { | ||
case *ptileOptimized: | ||
expr = t.wrapped | ||
expr = &t.ptile | ||
default: | ||
expr = wrapped.(*ptile) | ||
} | ||
return &ptileOptimized{Wrapped: expr, wrapped: expr.(*ptile), Percentile: exprFor(percentile)} | ||
return &ptileOptimized{Wrapped: expr, ptile: *expr.(*ptile), Percentile: exprFor(percentile)} | ||
} | ||
|
||
type ptileOptimized struct { | ||
ptile | ||
Wrapped Expr | ||
wrapped *ptile | ||
Percentile Expr | ||
} | ||
|
||
func (e *ptileOptimized) Validate() error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most of this stuff is now inherited from |
||
return e.wrapped.Validate() | ||
} | ||
|
||
func (e *ptileOptimized) EncodedWidth() int { | ||
return 0 | ||
} | ||
|
||
func (e *ptileOptimized) Shift() time.Duration { | ||
return 0 | ||
} | ||
|
||
func (e *ptileOptimized) Update(b []byte, params Params, metadata goexpr.Params) ([]byte, float64, bool) { | ||
return b, 0, false | ||
} | ||
|
||
func (e *ptileOptimized) Merge(b []byte, x []byte, y []byte) ([]byte, []byte, []byte) { | ||
return b, x, y | ||
} | ||
|
||
func (e *ptileOptimized) SubMergers(subs []Expr) []SubMerge { | ||
return nil | ||
} | ||
|
||
func (e *ptileOptimized) Get(b []byte) (float64, bool, []byte) { | ||
histo, wasSet, remain := e.wrapped.load(b) | ||
histo, wasSet, remain := e.ptile.load(b) | ||
percentile, _, remain := e.Percentile.Get(remain) | ||
if !wasSet { | ||
return 0, wasSet, remain | ||
} | ||
return e.wrapped.calc(histo, percentile), wasSet, remain | ||
} | ||
|
||
func (e *ptileOptimized) IsConstant() bool { | ||
return false | ||
} | ||
|
||
func (e *ptileOptimized) DeAggregate() Expr { | ||
return PERCENTILE(e.wrapped.DeAggregate(), e.Percentile.DeAggregate(), scaleFromInt(e.wrapped.Min, e.wrapped.Precision), scaleFromInt(e.wrapped.Max, e.wrapped.Precision), e.wrapped.Precision) | ||
return e.ptile.calc(histo, percentile), wasSet, remain | ||
} | ||
|
||
func (e *ptileOptimized) String() string { | ||
return fmt.Sprintf("PERCENTILE(%v, %v)", e.wrapped.String(), e.Percentile) | ||
return fmt.Sprintf("PERCENTILE(%v, %v)", e.Wrapped.String(), e.Percentile) | ||
} | ||
|
||
func (e *ptileOptimized) DecodeMsgpack(dec *msgpack.Decoder) error { | ||
|
@@ -81,7 +47,7 @@ func (e *ptileOptimized) DecodeMsgpack(dec *msgpack.Decoder) error { | |
wrapped := m["Wrapped"].(*ptile) | ||
percentile := m["Percentile"].(Expr) | ||
e.Wrapped = wrapped | ||
e.wrapped = wrapped | ||
e.ptile = *wrapped | ||
e.Percentile = percentile | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -361,6 +361,8 @@ view_a: | |
wg.Add(1) | ||
go testSimpleQuery(&wg, t, db, includeMemStore, epoch, resolution) | ||
wg.Add(1) | ||
go testPercentileOptimizedQuery(&wg, t, db, includeMemStore, epoch, resolution) | ||
wg.Add(1) | ||
go testCrosstabWithHavingQuery(&wg, t, db, includeMemStore, epoch, resolution) | ||
wg.Add(1) | ||
go testStrideQuery(&wg, t, db, includeMemStore, epoch, resolution) | ||
|
@@ -463,6 +465,27 @@ ORDER BY _time` | |
}) | ||
} | ||
|
||
func testPercentileOptimizedQuery(wg *sync.WaitGroup, t *testing.T, db *DB, includeMemStore bool, epoch time.Time, resolution time.Duration) { | ||
defer wg.Done() | ||
|
||
sqlString := ` | ||
SELECT PERCENTILE(pp_5p, 90) AS pp_opt | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shows an example of what's now possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool! Thanks also, the context is helpful. |
||
FROM test_a | ||
GROUP BY _ | ||
ORDER BY _time` | ||
|
||
epoch = encoding.RoundTimeUp(epoch, resolution) | ||
assertExpectedResult(t, db, sqlString, includeMemStore, testsupport.ExpectedResult{ | ||
testsupport.ExpectedRow{ | ||
epoch, | ||
map[string]interface{}{}, | ||
map[string]float64{ | ||
"pp_opt": 90, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
// testHavingQuery makes sure that a HAVING clause works even when the field in | ||
// that clause does not appear in the SELECT clause | ||
func testCrosstabWithHavingQuery(wg *sync.WaitGroup, t *testing.T, db *DB, includeMemStore bool, epoch time.Time, resolution time.Duration) { | ||
|
@@ -714,7 +737,7 @@ func assertExpectedResult(t *testing.T, db *DB, sqlString string, includeMemStor | |
var rows []*core.FlatRow | ||
source, err := db.Query(sqlString, false, nil, includeMemStore) | ||
if err != nil { | ||
return nil, errors.New("Unable to plan SQL query") | ||
return nil, errors.New("Unable to plan SQL query: %v", err) | ||
} | ||
|
||
var fields core.Fields | ||
|
@@ -728,7 +751,7 @@ func assertExpectedResult(t *testing.T, db *DB, sqlString string, includeMemStor | |
return true, nil | ||
}) | ||
if err != nil { | ||
return nil, errors.New("Unable to plan SQL query") | ||
return nil, errors.New("Unable to plan SQL query: %v", err) | ||
} | ||
|
||
if false { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer attempt to reuse the existing percentile's storage, we assume separate storage for this percentile.