influxdb icon indicating copy to clipboard operation
influxdb copied to clipboard

Inconsistent Mode aggregation on all unique values

Open vdpoora opened this issue 10 months ago • 0 comments

Running influx v1.8.10 I have noticed an inconsistency in the behavior of the Mode aggregation:

  • When aggregating over all unique values, the Mode aggregation returns the smallest value
  • When aggregating over values that are not all unique, but there are ties, the Mode aggregation returns the earliest value (this is the documented behaviour: https://docs.influxdata.com/influxdb/v1/query_language/functions/#mode)

Expected behavior is that in all cases the mode aggregation returns the earliest value in case of a tie

These unit tests showcase the two cases:


func TestCallIterator_Mode_Float_All_Equal_Occurrences_All_Unique(t *testing.T) {
	itr, _ := query.NewModeIterator(&FloatIterator{Points: []query.FloatPoint{
		{Time: 0, Value: 2, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 1, Value: 1, Tags: ParseTags("region=us-west,host=hostA")},
		{Time: 2, Value: 4, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 3, Value: 6, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 4, Value: 0, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 6, Value: 9, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 7, Value: 3, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 8, Value: 5, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 9, Value: 7, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 10, Value: 8, Tags: ParseTags("region=us-east,host=hostA")},
	}},
		query.IteratorOptions{
			Expr:       MustParseExpr(`mode("value")`),
			Dimensions: []string{"host"},
			Interval:   query.Interval{Duration: 11 * time.Nanosecond},
			Ordered:    true,
			Ascending:  true,
		},
	)

	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
		t.Fatalf("unexpected error: %s", err)
	} else if diff := cmp.Diff(a, [][]query.Point{
		// The smallest value is returned
		{&query.FloatPoint{Time: 0, Value: 0, Tags: ParseTags("host=hostA"), Aggregated: 0}},
	}); diff != "" {
		t.Fatalf("unexpected points:\n%s", diff)
	}
}

func TestCallIterator_Mode_Float_All_Equal_Occurrences_Not_Unique(t *testing.T) {
	itr, _ := query.NewModeIterator(&FloatIterator{Points: []query.FloatPoint{
		{Time: 0, Value: 2, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 1, Value: 2, Tags: ParseTags("region=us-west,host=hostA")},
		{Time: 2, Value: 4, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 3, Value: 4, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 4, Value: 0, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 6, Value: 0, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 7, Value: 3, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 8, Value: 3, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 9, Value: 7, Tags: ParseTags("region=us-east,host=hostA")},
		{Time: 10, Value: 7, Tags: ParseTags("region=us-east,host=hostA")},
	}},
		query.IteratorOptions{
			Expr:       MustParseExpr(`mode("value")`),
			Dimensions: []string{"host"},
			Interval:   query.Interval{Duration: 11 * time.Nanosecond},
			Ordered:    true,
			Ascending:  true,
		},
	)

	if a, err := Iterators([]query.Iterator{itr}).ReadAll(); err != nil {
		t.Fatalf("unexpected error: %s", err)
	} else if diff := cmp.Diff(a, [][]query.Point{
		// The earliest value is returned
		{&query.FloatPoint{Time: 0, Value: 2, Tags: ParseTags("host=hostA"), Aggregated: 0}},
	}); diff != "" {
		t.Fatalf("unexpected points:\n%s", diff)
	}
}

vdpoora avatar Mar 12 '25 12:03 vdpoora