Merge pull request #1695 from rachithrr/decimal-groupby-added

CORE-777: Added DecimalAgg field in GroupCount to output decimal sum
This commit is contained in:
rachithrr 2021-09-16 10:49:57 -05:00 committed by GitHub
commit cd1e17d0ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 18 deletions

View file

@ -1825,10 +1825,14 @@ func (e *executor) executeSumCountShard(ctx context.Context, qcx *Qcx, index str
if err != nil {
return ValCount{}, errors.Wrap(err, "computing sum")
}
return ValCount{
out := ValCount{
Val: int64(vsum) + (int64(vcount) * bsig.Base),
Count: int64(vcount),
}, nil
}
if field.Type() == FieldTypeDecimal {
out.FloatVal = float64(int64(vsum)+(int64(vcount)*bsig.Base)) / math.Pow(10, float64(bsig.Scale))
}
return out, nil
}
// executeMinShard calculates the min for bsiGroups on a shard.
@ -3044,6 +3048,13 @@ func (e *executor) executeGroupBy(ctx context.Context, qcx *Qcx, index string, c
aggType = "aggregate"
}
}
for _, res := range results {
if res.DecimalAgg != 0 && aggType == "sum" {
aggType = "decimalSum"
break
}
}
return NewGroupCounts(aggType, results...), nil
}
@ -3132,9 +3143,10 @@ func (fr FieldRow) String() string {
type aggregateType int
const (
nilAggregate aggregateType = 0
sumAggregate aggregateType = 1
distinctAggregate aggregateType = 2
nilAggregate aggregateType = 0
sumAggregate aggregateType = 1
distinctAggregate aggregateType = 2
decimalSumAggregate aggregateType = 3
)
// GroupCounts is a list of GroupCount.
@ -3152,6 +3164,8 @@ func (g *GroupCounts) AggregateColumn() string {
return "sum"
case distinctAggregate:
return "aggregate"
case decimalSumAggregate:
return "decimalSum"
default:
return ""
}
@ -3176,6 +3190,8 @@ func NewGroupCounts(agg string, groups ...GroupCount) *GroupCounts {
aggType = sumAggregate
case "aggregate":
aggType = distinctAggregate
case "decimalSum":
aggType = decimalSumAggregate
case "":
aggType = nilAggregate
default:
@ -3246,42 +3262,57 @@ func (g *GroupCounts) MarshalJSON() ([]byte, error) {
if len(groups) == 0 {
return []byte("[]"), nil
}
switch g.aggregateType {
case sumAggregate:
counts = *(*[]groupCountSum)(unsafe.Pointer(&groups))
case distinctAggregate:
counts = *(*[]groupCountAggregate)(unsafe.Pointer(&groups))
case decimalSumAggregate:
counts = *(*[]groupCountDecimalSum)(unsafe.Pointer(&groups))
}
return json.Marshal(counts)
}
// GroupCount represents a result item for a group by query.
type GroupCount struct {
Group []FieldRow `json:"group"`
Count uint64 `json:"count"`
Agg int64 `json:"-"`
Group []FieldRow `json:"group"`
Count uint64 `json:"count"`
Agg int64 `json:"-"`
DecimalAgg float64 `json:"-"`
}
type groupCountSum struct {
Group []FieldRow `json:"group"`
Count uint64 `json:"count"`
Agg int64 `json:"sum"`
Group []FieldRow `json:"group"`
Count uint64 `json:"count"`
Agg int64 `json:"sum"`
DecimalAgg float64 `json:"-"`
}
type groupCountAggregate struct {
Group []FieldRow `json:"group"`
Count uint64 `json:"count"`
Agg int64 `json:"aggregate"`
Group []FieldRow `json:"group"`
Count uint64 `json:"count"`
Agg int64 `json:"aggregate"`
DecimalAgg float64 `json:"-"`
}
type groupCountDecimalSum struct {
Group []FieldRow `json:"group"`
Count uint64 `json:"count"`
Agg int64 `json:"-"`
DecimalAgg float64 `json:"sum"`
}
var _ GroupCount = GroupCount(groupCountSum{})
var _ GroupCount = GroupCount(groupCountAggregate{})
var _ GroupCount = GroupCount(groupCountDecimalSum{})
func (g *GroupCount) Clone() (r *GroupCount) {
r = &GroupCount{
Group: make([]FieldRow, len(g.Group)),
Count: g.Count,
Agg: g.Agg,
Group: make([]FieldRow, len(g.Group)),
Count: g.Count,
Agg: g.Agg,
DecimalAgg: g.DecimalAgg,
}
for i := range g.Group {
r.Group[i] = *(g.Group[i].Clone())
@ -3306,6 +3337,7 @@ func mergeGroupCounts(a, b []GroupCount, limit int) []GroupCount {
case 0:
a[i].Count += b[j].Count
a[i].Agg += b[j].Agg
a[i].DecimalAgg += b[j].DecimalAgg
ret = append(ret, a[i])
i++
j++
@ -7939,6 +7971,7 @@ func (gbi *groupByIterator) Next(ctx context.Context) (ret GroupCount, done bool
}
ret.Count = uint64(result.Count)
ret.Agg = result.Val
ret.DecimalAgg = result.FloatVal
}
}
if ret.Count == 0 {

View file

@ -38,7 +38,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/molecula/featurebase/v2"
pilosa "github.com/molecula/featurebase/v2"
"github.com/molecula/featurebase/v2/boltdb"
"github.com/molecula/featurebase/v2/disco"
"github.com/molecula/featurebase/v2/http"
@ -5151,6 +5151,8 @@ func TestExecutor_GroupByStrings(t *testing.T) {
c.CreateField(t, "istring", pilosa.IndexOptions{Keys: true}, "v", pilosa.OptFieldTypeInt(0, 1000))
c.CreateField(t, "istring", pilosa.IndexOptions{Keys: true}, "vv", pilosa.OptFieldTypeInt(0, 1000))
c.CreateField(t, "istring", pilosa.IndexOptions{Keys: true}, "nv", pilosa.OptFieldTypeInt(-1000, 1000))
c.CreateField(t, "istring", pilosa.IndexOptions{Keys: true}, "dv", pilosa.OptFieldTypeDecimal(2))
c.CreateField(t, "istring", pilosa.IndexOptions{Keys: true}, "ndv", pilosa.OptFieldTypeDecimal(1))
if err := c.GetNode(0).API.Import(context.Background(), nil, &pilosa.ImportRequest{
Index: "istring",
@ -5167,6 +5169,8 @@ func TestExecutor_GroupByStrings(t *testing.T) {
var v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 int64 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
var nv1, nv2, nv3, nv4 int64 = -1, -2, -3, -4
var dv1, dv2, dv3, dv4, dv5, dv6, dv7, dv8, dv9, dv10 int64 = 111, 222, 333, 444, 555, 666, 777, 888, 999, 1000
var ndv1, ndv2, ndv3, ndv4, ndv5, ndv6, ndv7, ndv8, ndv9, ndv10 int64 = -111, -222, -333, -444, -555, -666, -777, -888, -999, -1000
if err := m0.API.ImportValue(context.Background(), qcx, &pilosa.ImportValueRequest{
Index: "istring",
Field: "v",
@ -5197,6 +5201,26 @@ func TestExecutor_GroupByStrings(t *testing.T) {
t.Fatalf("importing: %v", err)
}
if err := m0.API.ImportValue(context.Background(), qcx, &pilosa.ImportValueRequest{
Index: "istring",
Field: "dv",
Shard: 0,
ColumnKeys: []string{"c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10"},
Values: []int64{dv1, dv2, dv3, dv4, dv5, dv6, dv7, dv8, dv9, dv10},
}); err != nil {
t.Fatalf("importing: %v", err)
}
if err := m0.API.ImportValue(context.Background(), qcx, &pilosa.ImportValueRequest{
Index: "istring",
Field: "ndv",
Shard: 0,
ColumnKeys: []string{"c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10"},
Values: []int64{ndv1, ndv2, ndv3, ndv4, ndv5, ndv6, ndv7, ndv8, ndv9, ndv10},
}); err != nil {
t.Fatalf("importing: %v", err)
}
tests := []struct {
query string
expected []pilosa.GroupCount
@ -5221,6 +5245,20 @@ func TestExecutor_GroupByStrings(t *testing.T) {
{Group: []pilosa.FieldRow{{Field: "generals", RowID: 2, RowKey: "r2"}}, Count: 5, Agg: 30},
},
},
{
query: "GroupBy(Rows(generals), aggregate=Sum(field=dv))",
expected: []pilosa.GroupCount{
{Group: []pilosa.FieldRow{{Field: "generals", RowID: 1, RowKey: "r1"}}, Count: 5, Agg: 2775, DecimalAgg: 27.75},
{Group: []pilosa.FieldRow{{Field: "generals", RowID: 2, RowKey: "r2"}}, Count: 5, Agg: 3220, DecimalAgg: 32.20},
},
},
{
query: "GroupBy(Rows(generals), aggregate=Sum(field=ndv))",
expected: []pilosa.GroupCount{
{Group: []pilosa.FieldRow{{Field: "generals", RowID: 1, RowKey: "r1"}}, Count: 5, Agg: -2775, DecimalAgg: -277.5},
{Group: []pilosa.FieldRow{{Field: "generals", RowID: 2, RowKey: "r2"}}, Count: 5, Agg: -3220, DecimalAgg: -322.0},
},
},
{
query: "GroupBy(Rows(generals), aggregate=Sum(field=v), having=Condition(sum>25))",
expected: []pilosa.GroupCount{