2017-08-15 19:24:22 +00:00
|
|
|
package query
|
2015-11-04 21:06:06 +00:00
|
|
|
|
|
|
|
import (
|
2017-10-11 14:08:31 +00:00
|
|
|
"context"
|
2015-11-04 21:06:06 +00:00
|
|
|
"fmt"
|
2017-08-22 18:18:41 +00:00
|
|
|
"io"
|
2015-11-04 21:06:06 +00:00
|
|
|
"sort"
|
2018-04-02 19:49:22 +00:00
|
|
|
"strings"
|
2018-02-27 23:10:10 +00:00
|
|
|
"time"
|
2017-08-15 19:24:22 +00:00
|
|
|
|
2018-04-02 19:49:22 +00:00
|
|
|
"github.com/influxdata/influxdb/pkg/tracing"
|
2018-04-17 16:16:54 +00:00
|
|
|
"github.com/influxdata/influxdb/query/internal/gota"
|
2017-10-30 21:40:26 +00:00
|
|
|
"github.com/influxdata/influxql"
|
2015-11-04 21:06:06 +00:00
|
|
|
)
|
|
|
|
|
2018-03-14 14:42:51 +00:00
|
|
|
var DefaultTypeMapper = influxql.MultiTypeMapper(
|
|
|
|
FunctionTypeMapper{},
|
2018-03-30 21:58:37 +00:00
|
|
|
MathTypeMapper{},
|
2018-03-14 14:42:51 +00:00
|
|
|
)
|
|
|
|
|
2016-02-11 20:11:04 +00:00
|
|
|
// SelectOptions are options that customize the select call.
|
|
|
|
type SelectOptions struct {
|
2017-05-05 17:20:00 +00:00
|
|
|
// Authorizer is used to limit access to data
|
|
|
|
Authorizer Authorizer
|
|
|
|
|
2016-06-10 15:14:21 +00:00
|
|
|
// Node to exclusively read from.
|
|
|
|
// If zero, all nodes are used.
|
|
|
|
NodeID uint64
|
|
|
|
|
2016-08-08 16:39:38 +00:00
|
|
|
// Maximum number of concurrent series.
|
|
|
|
MaxSeriesN int
|
2017-08-22 18:18:41 +00:00
|
|
|
|
2018-03-02 16:59:40 +00:00
|
|
|
// Maximum number of points to read from the query.
|
|
|
|
// This requires the passed in context to have a Monitor that is
|
|
|
|
// created using WithMonitor.
|
|
|
|
MaxPointN int
|
|
|
|
|
2017-08-22 18:18:41 +00:00
|
|
|
// Maximum number of buckets for a statement.
|
|
|
|
MaxBucketsN int
|
|
|
|
}
|
|
|
|
|
|
|
|
// ShardMapper retrieves and maps shards into an IteratorCreator that can later be
|
|
|
|
// used for executing queries.
|
|
|
|
type ShardMapper interface {
|
2017-08-23 20:54:07 +00:00
|
|
|
MapShards(sources influxql.Sources, t influxql.TimeRange, opt SelectOptions) (ShardGroup, error)
|
2017-08-22 18:18:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ShardGroup represents a shard or a collection of shards that can be accessed
|
|
|
|
// for creating iterators.
|
2017-08-28 14:34:36 +00:00
|
|
|
// When creating iterators, the resource used for reading the iterators should be
|
|
|
|
// separate from the resource used to map the shards. When the ShardGroup is closed,
|
|
|
|
// it should not close any resources associated with the created Iterator. Those
|
|
|
|
// resources belong to the Iterator and will be closed when the Iterator itself is
|
|
|
|
// closed.
|
|
|
|
// The query engine operates under this assumption and will close the shard group
|
|
|
|
// after creating the iterators, but before the iterators are actually read.
|
2017-08-22 18:18:41 +00:00
|
|
|
type ShardGroup interface {
|
|
|
|
IteratorCreator
|
|
|
|
influxql.FieldMapper
|
|
|
|
io.Closer
|
2016-02-11 20:11:04 +00:00
|
|
|
}
|
|
|
|
|
2017-08-23 18:20:51 +00:00
|
|
|
// Select is a prepared statement that is ready to be executed.
|
|
|
|
type PreparedStatement interface {
|
|
|
|
// Select creates the Iterators that will be used to read the query.
|
2018-03-01 20:12:22 +00:00
|
|
|
Select(ctx context.Context) (Cursor, error)
|
2017-08-28 14:34:36 +00:00
|
|
|
|
2017-08-24 16:27:29 +00:00
|
|
|
// Explain outputs the explain plan for this statement.
|
|
|
|
Explain() (string, error)
|
|
|
|
|
2017-08-28 14:34:36 +00:00
|
|
|
// Close closes the resources associated with this prepared statement.
|
|
|
|
// This must be called as the mapped shards may hold open resources such
|
|
|
|
// as network connections.
|
|
|
|
Close() error
|
2017-08-23 18:20:51 +00:00
|
|
|
}
|
2017-08-22 18:18:41 +00:00
|
|
|
|
2017-08-23 18:20:51 +00:00
|
|
|
// Prepare will compile the statement with the default compile options and
|
|
|
|
// then prepare the query.
|
|
|
|
func Prepare(stmt *influxql.SelectStatement, shardMapper ShardMapper, opt SelectOptions) (PreparedStatement, error) {
|
|
|
|
c, err := Compile(stmt, CompileOptions{})
|
2017-08-22 18:18:41 +00:00
|
|
|
if err != nil {
|
2017-08-23 18:20:51 +00:00
|
|
|
return nil, err
|
2017-08-22 18:18:41 +00:00
|
|
|
}
|
2017-08-23 18:20:51 +00:00
|
|
|
return c.Prepare(shardMapper, opt)
|
|
|
|
}
|
2017-08-22 18:18:41 +00:00
|
|
|
|
2017-08-23 18:20:51 +00:00
|
|
|
// Select compiles, prepares, and then initiates execution of the query using the
|
|
|
|
// default compile options.
|
2018-03-01 20:12:22 +00:00
|
|
|
func Select(ctx context.Context, stmt *influxql.SelectStatement, shardMapper ShardMapper, opt SelectOptions) (Cursor, error) {
|
2017-08-23 18:20:51 +00:00
|
|
|
s, err := Prepare(stmt, shardMapper, opt)
|
2015-11-04 21:06:06 +00:00
|
|
|
if err != nil {
|
2018-03-01 20:12:22 +00:00
|
|
|
return nil, err
|
2017-08-22 18:18:41 +00:00
|
|
|
}
|
2017-08-28 14:34:36 +00:00
|
|
|
// Must be deferred so it runs after Select.
|
|
|
|
defer s.Close()
|
2017-10-11 14:08:31 +00:00
|
|
|
return s.Select(ctx)
|
2017-08-23 18:20:51 +00:00
|
|
|
}
|
2017-08-22 18:18:41 +00:00
|
|
|
|
2017-08-23 18:20:51 +00:00
|
|
|
type preparedStatement struct {
|
2017-08-28 14:34:36 +00:00
|
|
|
stmt *influxql.SelectStatement
|
|
|
|
opt IteratorOptions
|
|
|
|
ic interface {
|
|
|
|
IteratorCreator
|
|
|
|
io.Closer
|
|
|
|
}
|
2018-03-02 16:59:40 +00:00
|
|
|
columns []string
|
|
|
|
maxPointN int
|
|
|
|
now time.Time
|
2017-08-23 18:20:51 +00:00
|
|
|
}
|
2017-08-22 18:18:41 +00:00
|
|
|
|
2018-03-01 20:12:22 +00:00
|
|
|
func (p *preparedStatement) Select(ctx context.Context) (Cursor, error) {
|
2018-02-27 23:10:10 +00:00
|
|
|
// TODO(jsternberg): Remove this hacky method of propagating now.
|
|
|
|
// Each level of the query should use a time range discovered during
|
|
|
|
// compilation, but that requires too large of a refactor at the moment.
|
|
|
|
ctx = context.WithValue(ctx, "now", p.now)
|
2018-03-02 16:59:40 +00:00
|
|
|
|
|
|
|
opt := p.opt
|
|
|
|
opt.InterruptCh = ctx.Done()
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
cur, err := buildCursor(ctx, p.stmt, p.ic, opt)
|
2017-08-22 18:18:41 +00:00
|
|
|
if err != nil {
|
2018-03-01 20:12:22 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-03-02 16:59:40 +00:00
|
|
|
// If a monitor exists and we are told there is a maximum number of points,
|
|
|
|
// register the monitor function.
|
|
|
|
if m := MonitorFromContext(ctx); m != nil {
|
|
|
|
if p.maxPointN > 0 {
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
monitor := PointLimitMonitor(cur, DefaultStatsInterval, p.maxPointN)
|
2018-03-02 16:59:40 +00:00
|
|
|
m.Monitor(monitor)
|
|
|
|
}
|
|
|
|
}
|
2018-03-01 20:12:22 +00:00
|
|
|
return cur, nil
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
2015-11-04 21:06:06 +00:00
|
|
|
|
2017-08-28 14:34:36 +00:00
|
|
|
func (p *preparedStatement) Close() error {
|
|
|
|
return p.ic.Close()
|
|
|
|
}
|
|
|
|
|
2015-11-04 21:06:06 +00:00
|
|
|
// buildExprIterator creates an iterator for an expression.
|
2017-10-11 14:08:31 +00:00
|
|
|
func buildExprIterator(ctx context.Context, expr influxql.Expr, ic IteratorCreator, sources influxql.Sources, opt IteratorOptions, selector, writeMode bool) (Iterator, error) {
|
2015-11-04 21:06:06 +00:00
|
|
|
opt.Expr = expr
|
2016-11-23 20:32:42 +00:00
|
|
|
b := exprIteratorBuilder{
|
2017-05-17 16:10:51 +00:00
|
|
|
ic: ic,
|
|
|
|
sources: sources,
|
|
|
|
opt: opt,
|
|
|
|
selector: selector,
|
|
|
|
writeMode: writeMode,
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
2015-11-04 21:06:06 +00:00
|
|
|
|
|
|
|
switch expr := expr.(type) {
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.VarRef:
|
2017-10-11 14:08:31 +00:00
|
|
|
return b.buildVarRefIterator(ctx, expr)
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.Call:
|
2017-10-11 14:08:31 +00:00
|
|
|
return b.buildCallIterator(ctx, expr)
|
2016-11-23 20:32:42 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("invalid expression type: %T", expr)
|
|
|
|
}
|
|
|
|
}
|
2015-11-04 21:06:06 +00:00
|
|
|
|
2016-11-23 20:32:42 +00:00
|
|
|
type exprIteratorBuilder struct {
|
2017-05-17 16:10:51 +00:00
|
|
|
ic IteratorCreator
|
2017-08-15 19:24:22 +00:00
|
|
|
sources influxql.Sources
|
2017-05-17 16:10:51 +00:00
|
|
|
opt IteratorOptions
|
|
|
|
selector bool
|
|
|
|
writeMode bool
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
2016-10-04 21:20:35 +00:00
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
func (b *exprIteratorBuilder) buildVarRefIterator(ctx context.Context, expr *influxql.VarRef) (Iterator, error) {
|
2016-11-23 20:32:42 +00:00
|
|
|
inputs := make([]Iterator, 0, len(b.sources))
|
|
|
|
if err := func() error {
|
|
|
|
for _, source := range b.sources {
|
|
|
|
switch source := source.(type) {
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.Measurement:
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := b.ic.CreateIterator(ctx, source, b.opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
inputs = append(inputs, input)
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.SubQuery:
|
2017-02-28 21:40:43 +00:00
|
|
|
subquery := subqueryBuilder{
|
|
|
|
ic: b.ic,
|
|
|
|
stmt: source.Statement,
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
2016-05-12 21:11:19 +00:00
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := subquery.buildVarRefIterator(ctx, expr, b.opt)
|
2017-02-28 21:40:43 +00:00
|
|
|
if err != nil {
|
2016-11-23 20:32:42 +00:00
|
|
|
return err
|
2018-03-27 19:56:27 +00:00
|
|
|
} else if input != nil {
|
|
|
|
inputs = append(inputs, input)
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}(); err != nil {
|
|
|
|
Iterators(inputs).Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Variable references in this section will always go into some call
|
|
|
|
// iterator. Combine it with a merge iterator.
|
|
|
|
itr := NewMergeIterator(inputs, b.opt)
|
|
|
|
if itr == nil {
|
|
|
|
itr = &nilFloatIterator{}
|
|
|
|
}
|
|
|
|
|
|
|
|
if b.opt.InterruptCh != nil {
|
|
|
|
itr = NewInterruptIterator(itr, b.opt.InterruptCh)
|
|
|
|
}
|
|
|
|
return itr, nil
|
|
|
|
}
|
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
func (b *exprIteratorBuilder) buildCallIterator(ctx context.Context, expr *influxql.Call) (Iterator, error) {
|
2016-11-23 20:32:42 +00:00
|
|
|
// TODO(jsternberg): Refactor this. This section needs to die in a fire.
|
2017-04-05 16:47:57 +00:00
|
|
|
opt := b.opt
|
|
|
|
// Eliminate limits and offsets if they were previously set. These are handled by the caller.
|
|
|
|
opt.Limit, opt.Offset = 0, 0
|
2016-11-23 20:32:42 +00:00
|
|
|
switch expr.Name {
|
|
|
|
case "distinct":
|
2017-03-27 21:34:53 +00:00
|
|
|
opt.Ordered = true
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0].(*influxql.VarRef), b.ic, b.sources, opt, b.selector, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-27 21:34:53 +00:00
|
|
|
input, err = NewDistinctIterator(input, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-27 21:34:53 +00:00
|
|
|
return NewIntervalIterator(input, opt), nil
|
2016-11-23 20:32:42 +00:00
|
|
|
case "sample":
|
2017-03-27 21:34:53 +00:00
|
|
|
opt.Ordered = true
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0], b.ic, b.sources, opt, b.selector, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-08-15 19:24:22 +00:00
|
|
|
size := expr.Args[1].(*influxql.IntegerLiteral)
|
2016-11-23 20:32:42 +00:00
|
|
|
|
2017-03-27 21:34:53 +00:00
|
|
|
return newSampleIterator(input, opt, int(size.Val))
|
2016-11-23 20:32:42 +00:00
|
|
|
case "holt_winters", "holt_winters_with_fit":
|
2017-03-27 21:34:53 +00:00
|
|
|
opt.Ordered = true
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0], b.ic, b.sources, opt, b.selector, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-08-15 19:24:22 +00:00
|
|
|
h := expr.Args[1].(*influxql.IntegerLiteral)
|
|
|
|
m := expr.Args[2].(*influxql.IntegerLiteral)
|
2016-11-23 20:32:42 +00:00
|
|
|
|
|
|
|
includeFitData := "holt_winters_with_fit" == expr.Name
|
|
|
|
|
2017-04-05 16:47:57 +00:00
|
|
|
interval := opt.Interval.Duration
|
2016-11-23 20:32:42 +00:00
|
|
|
// Redefine interval to be unbounded to capture all aggregate results
|
2017-08-15 19:24:22 +00:00
|
|
|
opt.StartTime = influxql.MinTime
|
|
|
|
opt.EndTime = influxql.MaxTime
|
2016-11-23 20:32:42 +00:00
|
|
|
opt.Interval = Interval{}
|
|
|
|
|
|
|
|
return newHoltWintersIterator(input, opt, int(h.Val), int(m.Val), includeFitData, interval)
|
2018-05-16 23:40:12 +00:00
|
|
|
case "derivative", "non_negative_derivative", "difference", "non_negative_difference", "moving_average", "exponential_moving_average", "double_exponential_moving_average", "triple_exponential_moving_average", "relative_strength_index", "triple_exponential_derivative", "kaufmans_efficiency_ratio", "kaufmans_adaptive_moving_average", "chande_momentum_oscillator", "elapsed":
|
2016-11-23 20:32:42 +00:00
|
|
|
if !opt.Interval.IsZero() {
|
|
|
|
if opt.Ascending {
|
|
|
|
opt.StartTime -= int64(opt.Interval.Duration)
|
|
|
|
} else {
|
|
|
|
opt.EndTime += int64(opt.Interval.Duration)
|
|
|
|
}
|
|
|
|
}
|
2017-03-27 21:34:53 +00:00
|
|
|
opt.Ordered = true
|
2016-11-23 20:32:42 +00:00
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0], b.ic, b.sources, opt, b.selector, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch expr.Name {
|
|
|
|
case "derivative", "non_negative_derivative":
|
|
|
|
interval := opt.DerivativeInterval()
|
|
|
|
isNonNegative := (expr.Name == "non_negative_derivative")
|
|
|
|
return newDerivativeIterator(input, opt, interval, isNonNegative)
|
|
|
|
case "elapsed":
|
|
|
|
interval := opt.ElapsedInterval()
|
|
|
|
return newElapsedIterator(input, opt, interval)
|
2017-03-31 02:26:14 +00:00
|
|
|
case "difference", "non_negative_difference":
|
|
|
|
isNonNegative := (expr.Name == "non_negative_difference")
|
|
|
|
return newDifferenceIterator(input, opt, isNonNegative)
|
2016-11-23 20:32:42 +00:00
|
|
|
case "moving_average":
|
2017-08-15 19:24:22 +00:00
|
|
|
n := expr.Args[1].(*influxql.IntegerLiteral)
|
2017-04-05 16:47:57 +00:00
|
|
|
if n.Val > 1 && !opt.Interval.IsZero() {
|
2016-11-23 20:32:42 +00:00
|
|
|
if opt.Ascending {
|
|
|
|
opt.StartTime -= int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
} else {
|
|
|
|
opt.EndTime += int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newMovingAverageIterator(input, int(n.Val), opt)
|
2018-05-16 23:40:12 +00:00
|
|
|
case "exponential_moving_average", "double_exponential_moving_average", "triple_exponential_moving_average", "relative_strength_index", "triple_exponential_derivative":
|
2018-04-17 16:16:54 +00:00
|
|
|
n := expr.Args[1].(*influxql.IntegerLiteral)
|
|
|
|
if n.Val > 1 && !opt.Interval.IsZero() {
|
|
|
|
if opt.Ascending {
|
|
|
|
opt.StartTime -= int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
} else {
|
|
|
|
opt.EndTime += int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nHold := -1
|
|
|
|
if len(expr.Args) >= 3 {
|
|
|
|
nHold = int(expr.Args[2].(*influxql.IntegerLiteral).Val)
|
|
|
|
}
|
|
|
|
|
|
|
|
warmupType := gota.WarmEMA
|
|
|
|
if len(expr.Args) >= 4 {
|
|
|
|
if warmupType, err = gota.ParseWarmupType(expr.Args[3].(*influxql.StringLiteral).Val); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch expr.Name {
|
|
|
|
case "exponential_moving_average":
|
|
|
|
return newExponentialMovingAverageIterator(input, int(n.Val), nHold, warmupType, opt)
|
|
|
|
case "double_exponential_moving_average":
|
|
|
|
return newDoubleExponentialMovingAverageIterator(input, int(n.Val), nHold, warmupType, opt)
|
|
|
|
case "triple_exponential_moving_average":
|
|
|
|
return newTripleExponentialMovingAverageIterator(input, int(n.Val), nHold, warmupType, opt)
|
|
|
|
case "relative_strength_index":
|
|
|
|
return newRelativeStrengthIndexIterator(input, int(n.Val), nHold, warmupType, opt)
|
2018-05-16 23:40:12 +00:00
|
|
|
case "triple_exponential_derivative":
|
|
|
|
return newTripleExponentialDerivativeIterator(input, int(n.Val), nHold, warmupType, opt)
|
2018-04-17 16:16:54 +00:00
|
|
|
}
|
|
|
|
case "kaufmans_efficiency_ratio", "kaufmans_adaptive_moving_average":
|
|
|
|
n := expr.Args[1].(*influxql.IntegerLiteral)
|
|
|
|
if n.Val > 1 && !opt.Interval.IsZero() {
|
|
|
|
if opt.Ascending {
|
|
|
|
opt.StartTime -= int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
} else {
|
|
|
|
opt.EndTime += int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nHold := -1
|
|
|
|
if len(expr.Args) >= 3 {
|
|
|
|
nHold = int(expr.Args[2].(*influxql.IntegerLiteral).Val)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch expr.Name {
|
|
|
|
case "kaufmans_efficiency_ratio":
|
|
|
|
return newKaufmansEfficiencyRatioIterator(input, int(n.Val), nHold, opt)
|
|
|
|
case "kaufmans_adaptive_moving_average":
|
|
|
|
return newKaufmansAdaptiveMovingAverageIterator(input, int(n.Val), nHold, opt)
|
|
|
|
}
|
|
|
|
case "chande_momentum_oscillator":
|
|
|
|
n := expr.Args[1].(*influxql.IntegerLiteral)
|
|
|
|
if n.Val > 1 && !opt.Interval.IsZero() {
|
|
|
|
if opt.Ascending {
|
|
|
|
opt.StartTime -= int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
} else {
|
|
|
|
opt.EndTime += int64(opt.Interval.Duration) * (n.Val - 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nHold := -1
|
|
|
|
if len(expr.Args) >= 3 {
|
|
|
|
nHold = int(expr.Args[2].(*influxql.IntegerLiteral).Val)
|
|
|
|
}
|
|
|
|
|
|
|
|
warmupType := gota.WarmupType(-1)
|
|
|
|
if len(expr.Args) >= 4 {
|
|
|
|
wt := expr.Args[3].(*influxql.StringLiteral).Val
|
|
|
|
if wt != "none" {
|
|
|
|
if warmupType, err = gota.ParseWarmupType(wt); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return newChandeMomentumOscillatorIterator(input, int(n.Val), nHold, warmupType, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
|
|
|
panic(fmt.Sprintf("invalid series aggregate function: %s", expr.Name))
|
|
|
|
case "cumulative_sum":
|
2017-03-27 21:34:53 +00:00
|
|
|
opt.Ordered = true
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0], b.ic, b.sources, opt, b.selector, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-27 21:34:53 +00:00
|
|
|
return newCumulativeSumIterator(input, opt)
|
2017-03-23 20:18:03 +00:00
|
|
|
case "integral":
|
|
|
|
opt.Ordered = true
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0].(*influxql.VarRef), b.ic, b.sources, opt, false, false)
|
2017-03-23 20:18:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
interval := opt.IntegralInterval()
|
|
|
|
return newIntegralIterator(input, opt, interval)
|
2017-04-11 15:30:06 +00:00
|
|
|
case "top":
|
|
|
|
if len(expr.Args) < 2 {
|
|
|
|
return nil, fmt.Errorf("top() requires 2 or more arguments, got %d", len(expr.Args))
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var input Iterator
|
|
|
|
if len(expr.Args) > 2 {
|
|
|
|
// Create a max iterator using the groupings in the arguments.
|
2017-05-17 16:10:51 +00:00
|
|
|
dims := make(map[string]struct{}, len(expr.Args)-2+len(opt.GroupBy))
|
2017-04-11 15:30:06 +00:00
|
|
|
for i := 1; i < len(expr.Args)-1; i++ {
|
2017-08-15 19:24:22 +00:00
|
|
|
ref := expr.Args[i].(*influxql.VarRef)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
dims[ref.Val] = struct{}{}
|
|
|
|
}
|
|
|
|
for dim := range opt.GroupBy {
|
|
|
|
dims[dim] = struct{}{}
|
2017-04-11 15:30:06 +00:00
|
|
|
}
|
|
|
|
|
2017-08-15 19:24:22 +00:00
|
|
|
call := &influxql.Call{
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
Name: "max",
|
|
|
|
Args: expr.Args[:1],
|
|
|
|
}
|
|
|
|
callOpt := opt
|
|
|
|
callOpt.Expr = call
|
|
|
|
callOpt.GroupBy = dims
|
2017-08-15 19:24:22 +00:00
|
|
|
callOpt.Fill = influxql.NoFill
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
|
|
|
builder := *b
|
|
|
|
builder.opt = callOpt
|
|
|
|
builder.selector = true
|
2017-05-17 16:10:51 +00:00
|
|
|
builder.writeMode = false
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
i, err := builder.callIterator(ctx, call, callOpt)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
input = i
|
|
|
|
} else {
|
|
|
|
// There are no arguments so do not organize the points by tags.
|
|
|
|
builder := *b
|
|
|
|
builder.opt.Expr = expr.Args[0]
|
|
|
|
builder.selector = true
|
2017-05-17 16:10:51 +00:00
|
|
|
builder.writeMode = false
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
2017-08-15 19:24:22 +00:00
|
|
|
ref := expr.Args[0].(*influxql.VarRef)
|
2017-10-11 14:08:31 +00:00
|
|
|
i, err := builder.buildVarRefIterator(ctx, ref)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
input = i
|
2017-04-11 15:30:06 +00:00
|
|
|
}
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
2017-08-15 19:24:22 +00:00
|
|
|
n := expr.Args[len(expr.Args)-1].(*influxql.IntegerLiteral)
|
2017-05-17 16:10:51 +00:00
|
|
|
return newTopIterator(input, opt, int(n.Val), b.writeMode)
|
2017-04-11 15:30:06 +00:00
|
|
|
case "bottom":
|
|
|
|
if len(expr.Args) < 2 {
|
|
|
|
return nil, fmt.Errorf("bottom() requires 2 or more arguments, got %d", len(expr.Args))
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var input Iterator
|
|
|
|
if len(expr.Args) > 2 {
|
|
|
|
// Create a max iterator using the groupings in the arguments.
|
|
|
|
dims := make(map[string]struct{}, len(expr.Args)-2)
|
2017-04-11 15:30:06 +00:00
|
|
|
for i := 1; i < len(expr.Args)-1; i++ {
|
2017-08-15 19:24:22 +00:00
|
|
|
ref := expr.Args[i].(*influxql.VarRef)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
dims[ref.Val] = struct{}{}
|
|
|
|
}
|
|
|
|
for dim := range opt.GroupBy {
|
|
|
|
dims[dim] = struct{}{}
|
2017-04-11 15:30:06 +00:00
|
|
|
}
|
|
|
|
|
2017-08-15 19:24:22 +00:00
|
|
|
call := &influxql.Call{
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
Name: "min",
|
|
|
|
Args: expr.Args[:1],
|
|
|
|
}
|
|
|
|
callOpt := opt
|
|
|
|
callOpt.Expr = call
|
|
|
|
callOpt.GroupBy = dims
|
2017-08-15 19:24:22 +00:00
|
|
|
callOpt.Fill = influxql.NoFill
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
|
|
|
builder := *b
|
|
|
|
builder.opt = callOpt
|
|
|
|
builder.selector = true
|
2017-05-17 16:10:51 +00:00
|
|
|
builder.writeMode = false
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
i, err := builder.callIterator(ctx, call, callOpt)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
input = i
|
|
|
|
} else {
|
|
|
|
// There are no arguments so do not organize the points by tags.
|
|
|
|
builder := *b
|
2017-05-30 15:56:16 +00:00
|
|
|
builder.opt.Expr = expr.Args[0]
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
builder.selector = true
|
2017-05-17 16:10:51 +00:00
|
|
|
builder.writeMode = false
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
2017-08-15 19:24:22 +00:00
|
|
|
ref := expr.Args[0].(*influxql.VarRef)
|
2017-10-11 14:08:31 +00:00
|
|
|
i, err := builder.buildVarRefIterator(ctx, ref)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
input = i
|
2017-04-11 15:30:06 +00:00
|
|
|
}
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
2017-08-15 19:24:22 +00:00
|
|
|
n := expr.Args[len(expr.Args)-1].(*influxql.IntegerLiteral)
|
2017-05-17 16:10:51 +00:00
|
|
|
return newBottomIterator(input, b.opt, int(n.Val), b.writeMode)
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
itr, err := func() (Iterator, error) {
|
|
|
|
switch expr.Name {
|
|
|
|
case "count":
|
|
|
|
switch arg0 := expr.Args[0].(type) {
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.Call:
|
2016-11-23 20:32:42 +00:00
|
|
|
if arg0.Name == "distinct" {
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, arg0, b.ic, b.sources, opt, b.selector, false)
|
2016-02-22 17:51:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-04-05 16:47:57 +00:00
|
|
|
return newCountIterator(input, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fallthrough
|
|
|
|
case "min", "max", "sum", "first", "last", "mean":
|
2017-10-11 14:08:31 +00:00
|
|
|
return b.callIterator(ctx, expr, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
case "median":
|
|
|
|
opt.Ordered = true
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0].(*influxql.VarRef), b.ic, b.sources, opt, false, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-02-22 17:51:45 +00:00
|
|
|
}
|
2016-11-23 20:32:42 +00:00
|
|
|
return newMedianIterator(input, opt)
|
|
|
|
case "mode":
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0].(*influxql.VarRef), b.ic, b.sources, opt, false, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-03-21 16:00:07 +00:00
|
|
|
}
|
2017-04-05 16:47:57 +00:00
|
|
|
return NewModeIterator(input, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
case "stddev":
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0].(*influxql.VarRef), b.ic, b.sources, opt, false, false)
|
2016-11-23 20:32:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
2017-04-05 16:47:57 +00:00
|
|
|
return newStddevIterator(input, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
case "spread":
|
|
|
|
// OPTIMIZE(benbjohnson): convert to map/reduce
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0].(*influxql.VarRef), b.ic, b.sources, opt, false, false)
|
2015-11-04 21:06:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-04-05 16:47:57 +00:00
|
|
|
return newSpreadIterator(input, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
case "percentile":
|
|
|
|
opt.Ordered = true
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr.Args[0].(*influxql.VarRef), b.ic, b.sources, opt, false, false)
|
2015-11-04 21:06:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-11-23 20:32:42 +00:00
|
|
|
var percentile float64
|
|
|
|
switch arg := expr.Args[1].(type) {
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.NumberLiteral:
|
2016-11-23 20:32:42 +00:00
|
|
|
percentile = arg.Val
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.IntegerLiteral:
|
2016-11-23 20:32:42 +00:00
|
|
|
percentile = float64(arg.Val)
|
|
|
|
}
|
|
|
|
return newPercentileIterator(input, opt, percentile)
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported call: %s", expr.Name)
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
2016-11-23 20:32:42 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-04-05 16:47:57 +00:00
|
|
|
if !b.selector || !opt.Interval.IsZero() {
|
|
|
|
itr = NewIntervalIterator(itr, opt)
|
2017-08-15 19:24:22 +00:00
|
|
|
if !opt.Interval.IsZero() && opt.Fill != influxql.NoFill {
|
2017-04-05 16:47:57 +00:00
|
|
|
itr = NewFillIterator(itr, expr, opt)
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-05 16:47:57 +00:00
|
|
|
if opt.InterruptCh != nil {
|
|
|
|
itr = NewInterruptIterator(itr, opt.InterruptCh)
|
2016-11-23 20:32:42 +00:00
|
|
|
}
|
|
|
|
return itr, nil
|
|
|
|
}
|
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
func (b *exprIteratorBuilder) callIterator(ctx context.Context, expr *influxql.Call, opt IteratorOptions) (Iterator, error) {
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
inputs := make([]Iterator, 0, len(b.sources))
|
|
|
|
if err := func() error {
|
|
|
|
for _, source := range b.sources {
|
|
|
|
switch source := source.(type) {
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.Measurement:
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := b.ic.CreateIterator(ctx, source, opt)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
inputs = append(inputs, input)
|
2017-08-15 19:24:22 +00:00
|
|
|
case *influxql.SubQuery:
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
// Identify the name of the field we are using.
|
2017-08-15 19:24:22 +00:00
|
|
|
arg0 := expr.Args[0].(*influxql.VarRef)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
|
2017-10-11 14:08:31 +00:00
|
|
|
input, err := buildExprIterator(ctx, arg0, b.ic, []influxql.Source{source}, opt, b.selector, false)
|
Optimize top() and bottom() using an incremental aggregator
The previous version of `top()` and `bottom()` would gather all of the
points to use in a slice, filter them (if necessary), then use a
slightly modified heap sort to retrieve the top or bottom values.
This performed horrendously from the standpoint of memory. Since it
consumed so much memory and spent so much time in allocations (along
with sorting a potentially very large slice), this affected speed too.
These calls have now been modified so they keep the top or bottom points
in a min or max heap. For `top()`, a new point will read the minimum
value from the heap. If the new point is greater than the minimum point,
it will replace the minimum point and fix the heap with the new value.
If the new point is smaller, it discards that point. For `bottom()`, the
process is the opposite.
It will then sort the final result to ensure the correct ordering of the
selected points.
When `top()` or `bottom()` contain a tag to select, they have now been
modified so this query:
SELECT top(value, host, 2) FROM cpu
Essentially becomes this query:
SELECT top(value, 2), host FROM (
SELECT max(value) FROM cpu GROUP BY host
)
This should drastically increase the performance of all `top()` and
`bottom()` queries.
2017-05-16 17:37:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap the result in a call iterator.
|
|
|
|
i, err := NewCallIterator(input, opt)
|
|
|
|
if err != nil {
|
|
|
|
input.Close()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
inputs = append(inputs, i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}(); err != nil {
|
|
|
|
Iterators(inputs).Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
itr, err := Iterators(inputs).Merge(opt)
|
|
|
|
if err != nil {
|
|
|
|
Iterators(inputs).Close()
|
|
|
|
return nil, err
|
|
|
|
} else if itr == nil {
|
|
|
|
itr = &nilFloatIterator{}
|
|
|
|
}
|
|
|
|
return itr, nil
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func buildCursor(ctx context.Context, stmt *influxql.SelectStatement, ic IteratorCreator, opt IteratorOptions) (Cursor, error) {
|
2018-04-02 19:49:22 +00:00
|
|
|
span := tracing.SpanFromContext(ctx)
|
|
|
|
if span != nil {
|
|
|
|
span = span.StartSpan("build_cursor")
|
|
|
|
defer span.Finish()
|
|
|
|
|
|
|
|
span.SetLabels("statement", stmt.String())
|
|
|
|
ctx = tracing.NewContextWithSpan(ctx, span)
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
switch opt.Fill {
|
|
|
|
case influxql.NumberFill:
|
|
|
|
if v, ok := opt.FillValue.(int); ok {
|
|
|
|
opt.FillValue = int64(v)
|
2016-02-19 04:06:41 +00:00
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
case influxql.PreviousFill:
|
|
|
|
opt.FillValue = SkipDefault
|
|
|
|
}
|
2016-02-19 04:06:41 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
fields := make([]*influxql.Field, 0, len(stmt.Fields)+1)
|
|
|
|
if !stmt.OmitTime {
|
|
|
|
// Add a field with the variable "time" if we have not omitted time.
|
|
|
|
fields = append(fields, &influxql.Field{
|
|
|
|
Expr: &influxql.VarRef{
|
|
|
|
Val: "time",
|
|
|
|
Type: influxql.Time,
|
2016-02-19 04:06:41 +00:00
|
|
|
},
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
})
|
|
|
|
}
|
2016-02-18 21:37:03 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Iterate through each of the fields to add them to the value mapper.
|
|
|
|
valueMapper := newValueMapper()
|
|
|
|
for _, f := range stmt.Fields {
|
|
|
|
fields = append(fields, valueMapper.Map(f))
|
2016-03-11 15:58:16 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// If the field is a top() or bottom() call, we need to also add
|
|
|
|
// the extra variables if we are not writing into a target.
|
|
|
|
if stmt.Target != nil {
|
|
|
|
continue
|
2016-02-19 04:06:41 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
switch expr := f.Expr.(type) {
|
|
|
|
case *influxql.Call:
|
|
|
|
if expr.Name == "top" || expr.Name == "bottom" {
|
|
|
|
for i := 1; i < len(expr.Args)-1; i++ {
|
|
|
|
nf := influxql.Field{Expr: expr.Args[i]}
|
|
|
|
fields = append(fields, valueMapper.Map(&nf))
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
}
|
2017-10-02 17:31:07 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Set the aliases on each of the columns to what the final name should be.
|
|
|
|
columns := stmt.ColumnNames()
|
|
|
|
for i, f := range fields {
|
|
|
|
f.Alias = columns[i]
|
|
|
|
}
|
2017-10-02 17:31:07 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Retrieve the refs to retrieve the auxiliary fields.
|
2018-03-30 21:58:37 +00:00
|
|
|
var auxKeys []influxql.VarRef
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
if len(valueMapper.refs) > 0 {
|
|
|
|
opt.Aux = make([]influxql.VarRef, 0, len(valueMapper.refs))
|
|
|
|
for ref := range valueMapper.refs {
|
|
|
|
opt.Aux = append(opt.Aux, *ref)
|
2017-03-19 09:58:09 +00:00
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
sort.Sort(influxql.VarRefs(opt.Aux))
|
2017-03-19 09:58:09 +00:00
|
|
|
|
2018-03-30 21:58:37 +00:00
|
|
|
auxKeys = make([]influxql.VarRef, len(opt.Aux))
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
for i, ref := range opt.Aux {
|
|
|
|
auxKeys[i] = valueMapper.symbols[ref.String()]
|
2017-03-19 09:58:09 +00:00
|
|
|
}
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// If there are no calls, then produce an auxiliary cursor.
|
|
|
|
if len(valueMapper.calls) == 0 {
|
2018-03-30 21:58:37 +00:00
|
|
|
// If all of the auxiliary keys are of an unknown type,
|
|
|
|
// do not construct the iterator and return a null cursor.
|
|
|
|
if !hasValidType(auxKeys) {
|
|
|
|
return newNullCursor(fields), nil
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
itr, err := buildAuxIterator(ctx, ic, stmt.Sources, opt)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
2016-02-18 21:37:03 +00:00
|
|
|
|
2018-03-30 21:58:37 +00:00
|
|
|
// Create a slice with an empty first element.
|
|
|
|
keys := []influxql.VarRef{{}}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
keys = append(keys, auxKeys...)
|
2016-02-19 04:06:41 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
scanner := NewIteratorScanner(itr, keys, opt.FillValue)
|
|
|
|
return newScannerCursor(scanner, fields, opt), nil
|
|
|
|
}
|
2016-02-19 04:06:41 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Check to see if this is a selector statement.
|
|
|
|
// It is a selector if it is the only selector call and the call itself
|
|
|
|
// is a selector.
|
|
|
|
selector := len(valueMapper.calls) == 1
|
|
|
|
if selector {
|
|
|
|
for call := range valueMapper.calls {
|
|
|
|
if !influxql.IsSelector(call) {
|
|
|
|
selector = false
|
|
|
|
}
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
}
|
2016-02-18 21:37:03 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Produce an iterator for every single call and create an iterator scanner
|
|
|
|
// associated with it.
|
|
|
|
scanners := make([]IteratorScanner, 0, len(valueMapper.calls))
|
2018-03-30 21:58:37 +00:00
|
|
|
for call := range valueMapper.calls {
|
|
|
|
driver := valueMapper.table[call]
|
|
|
|
if driver.Type == influxql.Unknown {
|
|
|
|
// The primary driver of this call is of unknown type, so skip this.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
itr, err := buildFieldIterator(ctx, call, ic, stmt.Sources, opt, selector, stmt.Target != nil)
|
|
|
|
if err != nil {
|
|
|
|
for _, s := range scanners {
|
|
|
|
s.Close()
|
|
|
|
}
|
|
|
|
return nil, err
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
2016-03-11 15:58:16 +00:00
|
|
|
|
2018-03-30 21:58:37 +00:00
|
|
|
keys := make([]influxql.VarRef, 0, len(auxKeys)+1)
|
|
|
|
keys = append(keys, driver)
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
keys = append(keys, auxKeys...)
|
2016-02-19 04:06:41 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
scanner := NewIteratorScanner(itr, keys, opt.FillValue)
|
|
|
|
scanners = append(scanners, scanner)
|
|
|
|
}
|
2016-02-19 04:06:41 +00:00
|
|
|
|
2018-03-30 21:58:37 +00:00
|
|
|
if len(scanners) == 0 {
|
|
|
|
return newNullCursor(fields), nil
|
|
|
|
} else if len(scanners) == 1 {
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
return newScannerCursor(scanners[0], fields, opt), nil
|
|
|
|
}
|
|
|
|
return newMultiScannerCursor(scanners, fields, opt), nil
|
|
|
|
}
|
2016-02-19 04:06:41 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func buildAuxIterator(ctx context.Context, ic IteratorCreator, sources influxql.Sources, opt IteratorOptions) (Iterator, error) {
|
2018-04-02 19:49:22 +00:00
|
|
|
span := tracing.SpanFromContext(ctx)
|
|
|
|
if span != nil {
|
|
|
|
span = span.StartSpan("iterator_scanner")
|
|
|
|
defer span.Finish()
|
|
|
|
|
|
|
|
auxFieldNames := make([]string, len(opt.Aux))
|
|
|
|
for i, ref := range opt.Aux {
|
|
|
|
auxFieldNames[i] = ref.String()
|
|
|
|
}
|
|
|
|
span.SetLabels("auxiliary_fields", strings.Join(auxFieldNames, ", "))
|
|
|
|
ctx = tracing.NewContextWithSpan(ctx, span)
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
inputs := make([]Iterator, 0, len(sources))
|
|
|
|
if err := func() error {
|
|
|
|
for _, source := range sources {
|
|
|
|
switch source := source.(type) {
|
|
|
|
case *influxql.Measurement:
|
|
|
|
input, err := ic.CreateIterator(ctx, source, opt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
inputs = append(inputs, input)
|
|
|
|
case *influxql.SubQuery:
|
|
|
|
b := subqueryBuilder{
|
|
|
|
ic: ic,
|
|
|
|
stmt: source.Statement,
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
input, err := b.buildAuxIterator(ctx, opt)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-03-27 19:56:27 +00:00
|
|
|
} else if input != nil {
|
|
|
|
inputs = append(inputs, input)
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
return nil
|
|
|
|
}(); err != nil {
|
|
|
|
Iterators(inputs).Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-10-02 17:31:07 +00:00
|
|
|
|
2019-02-03 20:27:43 +00:00
|
|
|
// Merge iterators to read auxiliary fields.
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
input, err := Iterators(inputs).Merge(opt)
|
|
|
|
if err != nil {
|
|
|
|
Iterators(inputs).Close()
|
|
|
|
return nil, err
|
|
|
|
} else if input == nil {
|
|
|
|
input = &nilFloatIterator{}
|
|
|
|
}
|
2017-03-19 09:58:09 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Filter out duplicate rows, if required.
|
|
|
|
if opt.Dedupe {
|
|
|
|
// If there is no group by and it is a float iterator, see if we can use a fast dedupe.
|
|
|
|
if itr, ok := input.(FloatIterator); ok && len(opt.Dimensions) == 0 {
|
|
|
|
if sz := len(opt.Aux); sz > 0 && sz < 3 {
|
|
|
|
input = newFloatFastDedupeIterator(itr)
|
|
|
|
} else {
|
|
|
|
input = NewDedupeIterator(itr)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
input = NewDedupeIterator(input)
|
2017-03-19 09:58:09 +00:00
|
|
|
}
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Apply limit & offset.
|
|
|
|
if opt.Limit > 0 || opt.Offset > 0 {
|
|
|
|
input = NewLimitIterator(input, opt)
|
|
|
|
}
|
|
|
|
return input, nil
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func buildFieldIterator(ctx context.Context, expr influxql.Expr, ic IteratorCreator, sources influxql.Sources, opt IteratorOptions, selector, writeMode bool) (Iterator, error) {
|
2018-04-02 19:49:22 +00:00
|
|
|
span := tracing.SpanFromContext(ctx)
|
|
|
|
if span != nil {
|
|
|
|
span = span.StartSpan("iterator_scanner")
|
|
|
|
defer span.Finish()
|
|
|
|
|
|
|
|
labels := []string{"expr", expr.String()}
|
|
|
|
if len(opt.Aux) > 0 {
|
|
|
|
auxFieldNames := make([]string, len(opt.Aux))
|
|
|
|
for i, ref := range opt.Aux {
|
|
|
|
auxFieldNames[i] = ref.String()
|
|
|
|
}
|
|
|
|
labels = append(labels, "auxiliary_fields", strings.Join(auxFieldNames, ", "))
|
|
|
|
}
|
|
|
|
span.SetLabels(labels...)
|
|
|
|
ctx = tracing.NewContextWithSpan(ctx, span)
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
input, err := buildExprIterator(ctx, expr, ic, sources, opt, selector, writeMode)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Apply limit & offset.
|
|
|
|
if opt.Limit > 0 || opt.Offset > 0 {
|
|
|
|
input = NewLimitIterator(input, opt)
|
|
|
|
}
|
|
|
|
return input, nil
|
|
|
|
}
|
2016-02-18 21:37:03 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
type valueMapper struct {
|
|
|
|
// An index that maps a node's string output to its symbol so that all
|
|
|
|
// nodes with the same signature are mapped the same.
|
2018-03-30 21:58:37 +00:00
|
|
|
symbols map[string]influxql.VarRef
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// An index that maps a specific expression to a symbol. This ensures that
|
|
|
|
// only expressions that were mapped get symbolized.
|
2018-03-30 21:58:37 +00:00
|
|
|
table map[influxql.Expr]influxql.VarRef
|
|
|
|
// A collection of all of the calls in the table.
|
|
|
|
calls map[*influxql.Call]struct{}
|
|
|
|
// A collection of all of the calls in the table.
|
|
|
|
refs map[*influxql.VarRef]struct{}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
i int
|
|
|
|
}
|
2016-02-18 21:37:03 +00:00
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func newValueMapper() *valueMapper {
|
|
|
|
return &valueMapper{
|
2018-03-30 21:58:37 +00:00
|
|
|
symbols: make(map[string]influxql.VarRef),
|
|
|
|
table: make(map[influxql.Expr]influxql.VarRef),
|
|
|
|
calls: make(map[*influxql.Call]struct{}),
|
|
|
|
refs: make(map[*influxql.VarRef]struct{}),
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func (v *valueMapper) Map(field *influxql.Field) *influxql.Field {
|
|
|
|
clone := *field
|
|
|
|
clone.Expr = influxql.CloneExpr(field.Expr)
|
|
|
|
|
|
|
|
influxql.Walk(v, clone.Expr)
|
|
|
|
clone.Expr = influxql.RewriteExpr(clone.Expr, v.rewriteExpr)
|
|
|
|
return &clone
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func (v *valueMapper) Visit(n influxql.Node) influxql.Visitor {
|
|
|
|
expr, ok := n.(influxql.Expr)
|
|
|
|
if !ok {
|
|
|
|
return v
|
2016-02-18 21:37:03 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
key := expr.String()
|
|
|
|
symbol, ok := v.symbols[key]
|
|
|
|
if !ok {
|
|
|
|
// This symbol has not been assigned yet.
|
2018-03-30 21:58:37 +00:00
|
|
|
// If this is a call or expression, mark the node
|
|
|
|
// as stored in the symbol table.
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
switch n := n.(type) {
|
|
|
|
case *influxql.Call:
|
|
|
|
if isMathFunction(n) {
|
|
|
|
return v
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
2018-03-30 21:58:37 +00:00
|
|
|
v.calls[n] = struct{}{}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
case *influxql.VarRef:
|
2018-03-30 21:58:37 +00:00
|
|
|
v.refs[n] = struct{}{}
|
2017-10-02 17:31:07 +00:00
|
|
|
default:
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
return v
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
2016-01-18 22:48:49 +00:00
|
|
|
|
2018-03-30 21:58:37 +00:00
|
|
|
// Determine the symbol name and the symbol type.
|
|
|
|
symbolName := fmt.Sprintf("val%d", v.i)
|
|
|
|
valuer := influxql.TypeValuerEval{
|
|
|
|
TypeMapper: DefaultTypeMapper,
|
|
|
|
}
|
|
|
|
typ, _ := valuer.EvalType(expr)
|
|
|
|
|
|
|
|
symbol = influxql.VarRef{
|
|
|
|
Val: symbolName,
|
|
|
|
Type: typ,
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Assign this symbol to the symbol table if it is not presently there
|
|
|
|
// and increment the value index number.
|
|
|
|
v.symbols[key] = symbol
|
|
|
|
v.i++
|
2016-01-18 22:48:49 +00:00
|
|
|
}
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
// Store the symbol for this expression so we can later rewrite
|
|
|
|
// the query correctly.
|
|
|
|
v.table[expr] = symbol
|
2016-01-18 22:48:49 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func (v *valueMapper) rewriteExpr(expr influxql.Expr) influxql.Expr {
|
|
|
|
symbol, ok := v.table[expr]
|
|
|
|
if !ok {
|
|
|
|
return expr
|
2015-11-04 21:06:06 +00:00
|
|
|
}
|
2018-03-30 21:58:37 +00:00
|
|
|
return &symbol
|
2017-10-02 17:31:07 +00:00
|
|
|
}
|
|
|
|
|
Refactor the math engine to compile the query and use eval
This change makes it so that we simplify the math engine so it doesn't
use a complicated set of nested iterators. That way, we have to change
math in one fewer place.
It also greatly simplifies the query engine as now we can create the
necessary iterators, join them by time, name, and tags, and then use the
cursor interface to read them and use eval to compute the result. It
makes it so the auxiliary iterators and all of their complexity can be
removed.
This also makes use of the new eval functionality that was recently
added to the influxql package.
No math functions have been added, but the scaffolding has been included
so things like trigonometry functions are just a single commit away.
This also introduces a small breaking change. Because of the call
optimization, it is now possible to use the same selector multiple times
as a selector. So if you do this:
SELECT max(value) * 2, max(value) / 2 FROM cpu
This will now return the timestamp of the max value rather than zero
since this query is considered to have only a single selector rather
than multiple separate selectors. If any aspect of the selector is
different, such as different selector functions or different arguments,
it will consider the selectors to be aggregates like the old behavior.
2018-03-19 17:05:55 +00:00
|
|
|
func validateTypes(stmt *influxql.SelectStatement) error {
|
|
|
|
valuer := influxql.TypeValuerEval{
|
|
|
|
TypeMapper: influxql.MultiTypeMapper(
|
|
|
|
FunctionTypeMapper{},
|
|
|
|
MathTypeMapper{},
|
|
|
|
),
|
|
|
|
}
|
|
|
|
for _, f := range stmt.Fields {
|
|
|
|
if _, err := valuer.EvalType(f.Expr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-03-19 09:58:09 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2018-03-30 21:58:37 +00:00
|
|
|
|
|
|
|
// hasValidType returns true if there is at least one non-unknown type
|
|
|
|
// in the slice.
|
|
|
|
func hasValidType(refs []influxql.VarRef) bool {
|
|
|
|
for _, ref := range refs {
|
|
|
|
if ref.Type != influxql.Unknown {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|