1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-08-15 20:02:56 +02:00

Refactor collect handling; restructure group and aggregation logic, unify loop operations, and improve method clarity

This commit is contained in:
Tim Voronov
2025-06-18 17:22:39 -04:00
parent 16137db876
commit 2e78bc4c64

View File

@@ -18,27 +18,35 @@ func NewCollectCompiler(ctx *CompilerContext) *CollectCompiler {
}
func (cc *CollectCompiler) Compile(ctx fql.ICollectClauseContext) {
// TODO: Undefine original loop variables
loop := cc.ctx.Loops.Current()
aggregator := ctx.CollectAggregator()
kvKeyReg, kvValReg, groupSelectors := cc.compileGrouping(ctx, aggregator != nil)
// We collect the aggregation keys
// And wrap each loop element by a KeyValuePair
// Where a key is either a single value or a list of values
// These KeyValuePairs are then added to the dataset
// Aggregation loop
if aggregator != nil {
cc.compileAggregation(aggregator, len(groupSelectors) > 0)
}
if len(groupSelectors) > 0 {
// Now we are defining new variables for the group selectors
cc.compileGroupSelectorVariables(groupSelectors, kvKeyReg, kvValReg, aggregator != nil)
}
}
func (cc *CollectCompiler) compileGrouping(ctx fql.ICollectClauseContext, aggregation bool) (vm.Operand, vm.Operand, []fql.ICollectSelectorContext) {
var kvKeyReg, kvValReg vm.Operand
var groupSelectors []fql.ICollectSelectorContext
var isGrouping bool
grouping := ctx.CollectGrouping()
counter := ctx.CollectCounter()
aggregator := ctx.CollectAggregator()
isCollecting := grouping != nil || counter != nil
if grouping == nil && counter == nil {
return kvKeyReg, kvValReg, groupSelectors
}
loop := cc.ctx.Loops.Current()
if isCollecting {
if grouping != nil {
isGrouping = true
groupSelectors = grouping.AllCollectSelector()
kvKeyReg = cc.compileCollectGroupKeySelectors(groupSelectors)
kvKeyReg = cc.compileGroupSelectors(groupSelectors)
}
kvValReg = cc.ctx.Registers.Allocate(core.Temp)
@@ -60,7 +68,7 @@ func (cc *CollectCompiler) Compile(ctx fql.ICollectClauseContext) {
} else if counter != nil {
projectionVariableName = counter.Identifier().GetText()
if isGrouping {
if grouping != nil {
collectorType = core.CollectorTypeKeyCounter
} else {
collectorType = core.CollectorTypeCounter
@@ -68,7 +76,7 @@ func (cc *CollectCompiler) Compile(ctx fql.ICollectClauseContext) {
}
// If we use aggregators, we need to collect group items by key
if aggregator != nil && collectorType != core.CollectorTypeKeyGroup {
if aggregation && collectorType != core.CollectorTypeKeyGroup {
// We need to patch the loop result to be a collector
collectorType = core.CollectorTypeKeyGroup
}
@@ -100,28 +108,20 @@ func (cc *CollectCompiler) Compile(ctx fql.ICollectClauseContext) {
loop.EmitKey(kvKeyReg, cc.ctx.Emitter)
//loop.EmitValue(kvValReg, cc.ctx.Emitter)
}
return kvKeyReg, kvValReg, groupSelectors
}
// Aggregation loop
if aggregator != nil {
cc.compileAggregation(aggregator, loop, isCollecting)
}
if isCollecting && isGrouping {
// Now we are defining new variables for the group selectors
cc.compileCollectGroupKeySelectorVariables(groupSelectors, kvKeyReg, kvValReg, aggregator != nil)
}
}
func (cc *CollectCompiler) compileAggregation(c fql.ICollectAggregatorContext, parentLoop *core.Loop, isCollected bool) {
if isCollected {
cc.compileGroupedAggregation(c, parentLoop)
func (cc *CollectCompiler) compileAggregation(c fql.ICollectAggregatorContext, isGrouped bool) {
if isGrouped {
cc.compileGroupedAggregation(c)
} else {
cc.compileGlobalAggregation(c, parentLoop)
cc.compileGlobalAggregation(c)
}
}
func (cc *CollectCompiler) compileGroupedAggregation(c fql.ICollectAggregatorContext, parentLoop *core.Loop) {
func (cc *CollectCompiler) compileGroupedAggregation(c fql.ICollectAggregatorContext) {
parentLoop := cc.ctx.Loops.Current()
// We need to allocate a temporary accumulators to store aggregation results
selectors := c.AllCollectAggregateSelector()
accums := cc.initAggrAccumulators(selectors)
@@ -164,7 +164,8 @@ func (cc *CollectCompiler) compileGroupedAggregation(c fql.ICollectAggregatorCon
// cc.ctx.Registers.Free(aggrIterVal)
}
func (cc *CollectCompiler) compileGlobalAggregation(c fql.ICollectAggregatorContext, parentLoop *core.Loop) {
func (cc *CollectCompiler) compileGlobalAggregation(c fql.ICollectAggregatorContext) {
parentLoop := cc.ctx.Loops.Current()
loop := parentLoop
// we create a custom collector for aggregators
cc.ctx.Emitter.PatchSwapAx(loop.ResultPos, vm.OpDataSetCollector, loop.Result, int(core.CollectorTypeKeyGroup))
@@ -269,7 +270,7 @@ func (cc *CollectCompiler) compileAggregationFuncCall(selectors []fql.ICollectAg
}
}
func (cc *CollectCompiler) compileCollectGroupKeySelectors(selectors []fql.ICollectSelectorContext) vm.Operand {
func (cc *CollectCompiler) compileGroupSelectors(selectors []fql.ICollectSelectorContext) vm.Operand {
if len(selectors) == 0 {
return vm.NoopOperand
}
@@ -298,7 +299,7 @@ func (cc *CollectCompiler) compileCollectGroupKeySelectors(selectors []fql.IColl
return kvKeyReg
}
func (cc *CollectCompiler) compileCollectGroupKeySelectorVariables(selectors []fql.ICollectSelectorContext, kvKeyReg, kvValReg vm.Operand, isAggregation bool) {
func (cc *CollectCompiler) compileGroupSelectorVariables(selectors []fql.ICollectSelectorContext, kvKeyReg, kvValReg vm.Operand, isAggregation bool) {
if len(selectors) > 1 {
variables := make([]vm.Operand, len(selectors))