func NewTimestampAggregator(query *parser.SelectQuery, _ *parser.Value) (Aggregator, error) { duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return nil, err } var durationPtr *int64 if duration != nil { newDuration := int64(*duration / time.Microsecond) durationPtr = &newDuration } return &TimestampAggregator{ timestamps: make(map[string]map[interface{}]int64), duration: durationPtr, }, nil }
func (self *QueryEngine) executeCountQueryWithGroupBy(query *parser.SelectQuery, yield func(*protocol.Series) error) error { self.aggregateYield = yield duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return err } self.isAggregateQuery = true self.duration = duration self.aggregators = []Aggregator{} for _, value := range query.GetColumnNames() { if !value.IsFunctionCall() { continue } lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("%s", err)) } self.aggregators = append(self.aggregators, aggregator) } for _, elem := range query.GetGroupByClause().Elems { if elem.IsFunctionCall() { continue } self.elems = append(self.elems, elem) } self.fillWithZero = query.GetGroupByClause().FillWithZero self.initializeFields() err = self.distributeQuery(query, func(series *protocol.Series) error { if len(series.Points) == 0 { return nil } return self.aggregateValuesForSeries(series) }) return err }
func Filter(query *parser.SelectQuery, series *protocol.Series) (*protocol.Series, error) { if query.GetWhereCondition() == nil { return series, nil } columns := map[string]bool{} getColumns(query.GetColumnNames(), columns) getColumns(query.GetGroupByClause().Elems, columns) points := series.Points series.Points = nil for _, point := range points { ok, err := matches(query.GetWhereCondition(), series.Fields, point) if err != nil { return nil, err } if ok { filterColumns(columns, series.Fields, point) series.Points = append(series.Points, point) } } if !columns["*"] { newFields := []string{} for _, f := range series.Fields { if _, ok := columns[f]; !ok { continue } newFields = append(newFields, f) } series.Fields = newFields } return series, nil }
func NewPointFilter(query *parser.SelectQuery, queryColumnNames []string) *PointFilter { columns := map[string]bool{} getColumns(query.GetColumnNames(), columns) getColumns(query.GetGroupByClause().Elems, columns) return &PointFilter{columns: columns, queryColumnNames: queryColumnNames, where: query.GetWhereCondition()} }
func (self *QueryEngine) executeCountQueryWithGroupBy(user common.User, database string, query *parser.SelectQuery, yield func(*protocol.Series) error) error { duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return err } aggregators := []Aggregator{} for _, value := range query.GetColumnNames() { if value.IsFunctionCall() { lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return err } aggregators = append(aggregators, aggregator) } } timestampAggregator, err := NewTimestampAggregator(query, nil) if err != nil { return err } groups := make(map[string]map[Group]bool) pointsRange := make(map[string]*PointRange) groupBy := query.GetGroupByClause() err = self.distributeQuery(user, database, query, func(series *protocol.Series) error { if len(series.Points) == 0 { return nil } var mapper Mapper mapper, err = createValuesToInterface(groupBy, series.Fields) if err != nil { return err } for _, aggregator := range aggregators { if err := aggregator.InitializeFieldsMetadata(series); err != nil { return err } } currentRange := pointsRange[*series.Name] for _, point := range series.Points { value := mapper(point) for _, aggregator := range aggregators { err := aggregator.AggregatePoint(*series.Name, value, point) if err != nil { return err } } timestampAggregator.AggregatePoint(*series.Name, value, point) seriesGroups := groups[*series.Name] if seriesGroups == nil { seriesGroups = make(map[Group]bool) groups[*series.Name] = seriesGroups } seriesGroups[value] = true if currentRange == nil { currentRange = &PointRange{*point.Timestamp, *point.Timestamp} pointsRange[*series.Name] = currentRange } else { currentRange.UpdateRange(point) } } return nil }) if err != nil { return err } fields := []string{} for _, aggregator := range aggregators { columnNames := aggregator.ColumnNames() fields = append(fields, columnNames...) } for _, value := range groupBy.Elems { if value.IsFunctionCall() { continue } tempName := value.Name fields = append(fields, tempName) } for table, tableGroups := range groups { tempTable := table points := []*protocol.Point{} var _groups []Group if !query.GetGroupByClause().FillWithZero || duration == nil { // sort the table groups by timestamp _groups = make([]Group, 0, len(tableGroups)) for groupId, _ := range tableGroups { _groups = append(_groups, groupId) } } else { groupsWithTime := map[Group]bool{} timeRange, ok := pointsRange[table] if ok { first := timeRange.startTime * 1000 / int64(*duration) * int64(*duration) end := timeRange.endTime * 1000 / int64(*duration) * int64(*duration) for i := 0; ; i++ { timestamp := first + int64(i)*int64(*duration) if end < timestamp { break } for group, _ := range tableGroups { groupWithTime := group.WithoutTimestamp().WithTimestamp(timestamp / 1000) groupsWithTime[groupWithTime] = true } } for groupId, _ := range groupsWithTime { _groups = append(_groups, groupId) } } } fillWithZero := duration != nil && query.GetGroupByClause().FillWithZero var sortedGroups SortableGroups if fillWithZero { if query.Ascending { sortedGroups = &AscendingGroupTimestampSortableGroups{CommonSortableGroups{_groups, table}} } else { sortedGroups = &DescendingGroupTimestampSortableGroups{CommonSortableGroups{_groups, table}} } } else { if query.Ascending { sortedGroups = &AscendingAggregatorSortableGroups{CommonSortableGroups{_groups, table}, timestampAggregator} } else { sortedGroups = &DescendingAggregatorSortableGroups{CommonSortableGroups{_groups, table}, timestampAggregator} } } sort.Sort(sortedGroups) for _, groupId := range sortedGroups.GetSortedGroups() { var timestamp int64 if groupId.HasTimestamp() { timestamp = groupId.GetTimestamp() } else { timestamp = *timestampAggregator.GetValues(table, groupId)[0][0].Int64Value } values := [][][]*protocol.FieldValue{} for _, aggregator := range aggregators { values = append(values, aggregator.GetValues(table, groupId)) } // do cross product of all the values _values := crossProduct(values) for _, v := range _values { /* groupPoints := []*protocol.Point{} */ point := &protocol.Point{ Values: v, } point.SetTimestampInMicroseconds(timestamp) // FIXME: this should be looking at the fields slice not the group by clause // FIXME: we should check whether the selected columns are in the group by clause for idx, _ := range groupBy.Elems { if duration != nil && idx == 0 { continue } value := groupId.GetValue(idx) switch x := value.(type) { case string: point.Values = append(point.Values, &protocol.FieldValue{StringValue: &x}) case bool: point.Values = append(point.Values, &protocol.FieldValue{BoolValue: &x}) case float64: point.Values = append(point.Values, &protocol.FieldValue{DoubleValue: &x}) case int64: point.Values = append(point.Values, &protocol.FieldValue{Int64Value: &x}) case nil: point.Values = append(point.Values, nil) } } points = append(points, point) } } expectedData := &protocol.Series{ Name: &tempTable, Fields: fields, Points: points, } yield(expectedData) } return nil }
func (self *QueryEngine) executeCountQueryWithGroupBy(query *parser.SelectQuery, yield func(*protocol.Series) error) error { self.aggregateYield = yield duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return err } self.isAggregateQuery = true self.duration = duration self.aggregators = []Aggregator{} for _, value := range query.GetColumnNames() { if value.IsFunctionCall() { lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return err } self.aggregators = append(self.aggregators, aggregator) } } timestampAggregator, err := NewTimestampAggregator(query, nil) if err != nil { return err } self.timestampAggregator = timestampAggregator self.groups = make(map[string]map[Group]bool) self.pointsRange = make(map[string]*PointRange) self.groupBy = query.GetGroupByClause() err = self.distributeQuery(query, func(series *protocol.Series) error { if len(series.Points) == 0 { return nil } var mapper Mapper mapper, err = createValuesToInterface(self.groupBy, series.Fields) if err != nil { return err } for _, aggregator := range self.aggregators { if err := aggregator.InitializeFieldsMetadata(series); err != nil { return err } } currentRange := self.pointsRange[*series.Name] for _, point := range series.Points { value := mapper(point) for _, aggregator := range self.aggregators { err := aggregator.AggregatePoint(*series.Name, value, point) if err != nil { return err } } self.timestampAggregator.AggregatePoint(*series.Name, value, point) seriesGroups := self.groups[*series.Name] if seriesGroups == nil { seriesGroups = make(map[Group]bool) self.groups[*series.Name] = seriesGroups } seriesGroups[value] = true if currentRange == nil { currentRange = &PointRange{*point.Timestamp, *point.Timestamp} self.pointsRange[*series.Name] = currentRange } else { currentRange.UpdateRange(point) } } return nil }) return err }
func (self *QueryEngine) executeCountQueryWithGroupBy(query *parser.SelectQuery, yield func(*protocol.Series) error) error { self.aggregateYield = yield duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return err } self.isAggregateQuery = true self.duration = duration self.aggregators = []Aggregator{} for _, value := range query.GetColumnNames() { if !value.IsFunctionCall() { continue } lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("%s", err)) } self.aggregators = append(self.aggregators, aggregator) } timestampAggregator, err := NewTimestampAggregator(query, nil) if err != nil { return err } self.timestampAggregator = timestampAggregator self.groups = make(map[string]map[Group]bool) self.pointsRange = make(map[string]*PointRange) self.groupBy = query.GetGroupByClause() self.initializeFields() err = self.distributeQuery(query, func(series *protocol.Series) error { if len(series.Points) == 0 { return nil } // if we're not doing group by time() then keep all the state in // memory until the query finishes reading all data points if self.duration == nil || query.GetGroupByClause().FillWithZero { return self.aggregateValuesForSeries(series) } // otherwise, keep the state for the current bucket. Once ticks // come in for a different time bucket, we flush the state that's // kept in memory by the aggregators // split the time series by time buckets bucketedSeries := []*protocol.Series{} currentSeries := &protocol.Series{ Name: series.Name, Fields: series.Fields, Points: []*protocol.Point{series.Points[0]}, } currentBucket := self.getTimestampFromPoint(series.Points[0]) for _, p := range series.Points[1:] { bucket := self.getTimestampFromPoint(p) if bucket != currentBucket { bucketedSeries = append(bucketedSeries, currentSeries) currentSeries = &protocol.Series{Name: series.Name, Fields: series.Fields} currentBucket = bucket } currentSeries.Points = append(currentSeries.Points, p) } bucketedSeries = append(bucketedSeries, currentSeries) for _, s := range bucketedSeries[:len(bucketedSeries)-1] { if err := self.aggregateValuesForSeries(s); err != nil { return err } self.calculateSummariesForTable(*s.Name) } last := bucketedSeries[len(bucketedSeries)-1] bucket := self.getTimestampFromPoint(last.Points[0]) if b, ok := self.buckets[*series.Name]; ok && b != bucket { self.calculateSummariesForTable(*last.Name) } self.buckets[*series.Name] = bucket return self.aggregateValuesForSeries(last) }) return err }