Example #1
0
// NewOperator creates a new binary operator function.
// the binary operators display a natural join semantic.
func NewOperator(op string, operator func(float64, float64) float64) function.MetricFunction {
	return function.MetricFunction{
		Name:         op,
		MinArguments: 2,
		MaxArguments: 2,
		Compute: func(context *function.EvaluationContext, args []function.Expression, groups function.Groups) (function.Value, error) {
			evaluated, err := function.EvaluateMany(context, args)
			if err != nil {
				return nil, err
			}
			leftValue := evaluated[0]
			rightValue := evaluated[1]
			leftList, err := leftValue.ToSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			rightList, err := rightValue.ToSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}

			joined := join.Join([]api.SeriesList{leftList, rightList})

			result := make([]api.Timeseries, len(joined.Rows))

			for i, row := range joined.Rows {
				left := row.Row[0]
				right := row.Row[1]
				array := make([]float64, len(left.Values))
				for j := 0; j < len(left.Values); j++ {
					array[j] = operator(left.Values[j], right.Values[j])
				}
				result[i] = api.Timeseries{Values: array, TagSet: row.TagSet}
			}

			query := fmt.Sprintf("(%s %s %s)", leftValue.GetName(), op, rightValue.GetName())
			return api.SeriesList{
				Series:    result,
				Timerange: context.Timerange,
				Name:      query,
				Query:     query,
			}, nil
		},
	}
}
Example #2
0
// NewOperator creates a new binary operator function.
// the binary operators display a natural join semantic.
func NewOperator(op string, operator func(float64, float64) float64) function.MetricFunction {
	return function.MetricFunction{
		Name:         op,
		MinArguments: 2,
		MaxArguments: 2,
		Compute: func(context function.EvaluationContext, args []function.Expression, groups []string) (function.Value, error) {
			leftChannel := make(chan function.Value, 1)
			rightChannel := make(chan function.Value, 1)
			errs := make(chan error, 2)
			go func() {
				leftValue, err := args[0].Evaluate(context)
				leftChannel <- leftValue
				errs <- err
			}()
			go func() {
				rightValue, err := args[1].Evaluate(context)
				rightChannel <- rightValue
				errs <- err
			}()
			err := <-errs
			if err != nil {
				return nil, err
			}
			err = <-errs
			if err != nil {
				return nil, err
			}
			leftValue := <-leftChannel
			rightValue := <-rightChannel

			leftList, err := leftValue.ToSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			rightList, err := rightValue.ToSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}

			joined := join.Join([]api.SeriesList{leftList, rightList})

			result := make([]api.Timeseries, len(joined.Rows))

			for i, row := range joined.Rows {
				left := row.Row[0]
				right := row.Row[1]
				array := make([]float64, len(left.Values))
				for j := 0; j < len(left.Values); j++ {
					array[j] = operator(left.Values[j], right.Values[j])
				}
				result[i] = api.Timeseries{array, row.TagSet}
			}

			return function.SeriesListValue(api.SeriesList{
				Series:    result,
				Timerange: context.Timerange,
				Name:      fmt.Sprintf("(%s %s %s)", leftValue.GetName(), op, rightValue.GetName()),
			}), nil
		},
	}
}