mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 00:55:55 +00:00
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:
commit
cd1e17d0ba
2 changed files with 89 additions and 18 deletions
67
executor.go
67
executor.go
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue