Tuesday, February 28, 2012

The proper aggregation, part 7: additive

From the last example you can see that the additive aggregation contains enough information in its state to generate the result rows quickly without an iteration. This means that keeping the saved result row for DELETEs doesn't give a whole lot of advantage and adds at least a little memory overhead.  We can change the code and avoid keeping it:

sub computeAverage # (table, context, aggop, opcode, rh, state, args...)
{
    my ($table, $context, $aggop, $opcode, $rh, $state, @args) = @_;
    my $rowchg;

    if ($aggop == &Triceps::AO_COLLAPSE) {
        return
    } elsif ($aggop == &Triceps::AO_AFTER_DELETE) {
        $state->{price_sum} -= $rh->getRow()->get("price");
    } elsif ($aggop == &Triceps::AO_AFTER_INSERT) {
        $state->{price_sum} += $rh->getRow()->get("price");
    }
    # on AO_BEFORE_MOD do nothing

    return if ($context->groupSize()==0
        || $opcode == &Triceps::OP_NOP);

    my $rLast = $context->last()->getRow() or die "$!";
    my $count = $context->groupSize();

    $context->makeHashSend($opcode,
        symbol => $rLast->get("symbol"),
        id => $rLast->get("id"),
        price => $state->{price_sum}/$count,
    ) or die "$!";
}

sub initAverage #  (@args)
{
    return { price_sum => 0 };
}

The other change in this example is that the sum gets directly added or subtracted in AO_AFTER_* instead of computing the sign first. It's all pretty much self-explanatory.

No comments:

Post a Comment