Skip to content

Commit

Permalink
Support for expressions and distinct sums when evaluating Scores. #1067
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisala committed Feb 12, 2025
1 parent c4d518e commit be7c6a6
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class Aggregation extends AggregationConfig {
String property
}

class DistinctAggregationConfig extends Aggregation {
String keyProperty
}

class AggregationResult {
String label
int count
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class AggregatorFactory {
else if (config.containsKey('childAggregations')) {
configObject = new CompositeAggregationConfig(label:config.label, childAggregations: createChildConfig(config))
}
else if (config.keyProperty) {
configObject = new DistinctAggregationConfig(config)
}
else {
configObject = new Aggregation(config)
}
Expand Down Expand Up @@ -83,11 +86,14 @@ class AggregatorFactory {
return new Aggregators.AverageAggregator(config.label, config.property)
break;
case Score.AGGREGATION_TYPE.HISTOGRAM.name():
return new Aggregators.HistogramAggregator(config.label, config.property)
return new Aggregators. HistogramAggregator(config.label, config.property)
break;
case Score.AGGREGATION_TYPE.SET.name():
return new Aggregators.SetAggregator(config.label, config.property)
break;
case Score.AGGREGATION_TYPE.DISTINCT_SUM.name():
return new Aggregators.DistinctSumAggregator(config.label, config.property, ((DistinctAggregationConfig)config).keyProperty)
break
default:
throw new IllegalAccessException("Invalid aggregation type: ${config.type}, label:${config.label}, property:${config.property}")
}
Expand Down
29 changes: 29 additions & 0 deletions src/main/groovy/au/org/ala/ecodata/reporting/Aggregators.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,33 @@ class Aggregators {
}
}

/**
* The DistinctSumAggregator will sum the values of a property where a second property is distinct.
* The use case for this is to sum data in values that appear more than once during aggregation.
* For example, most aggregation is done with Output data, and each one contains the Activity and owner (e.g. Project)
* data as well.
* The specific use case for this is to sum the data from Organisation reports and divide by the total
* funding, which is a property on the Organisation object.
* The keyProperty is the property that is used to determine if the value is distinct. The case of the
* organisation funding amount, the organisationId would be used as the key property.
*/
static class DistinctSumAggregator extends SummingAggegrator {
protected PropertyAccessor keyPropertyAccessor
protected Set seenKeys
DistinctSumAggregator(String label, String property, String keyProperty) {
super(label, property)
keyPropertyAccessor = new PropertyAccessor(keyProperty)
seenKeys = new HashSet()
}

void aggregateSingle(Map data) {
def key = keyPropertyAccessor.getPropertyValue(data)
if (!seenKeys.contains(key)) {
seenKeys.add(key)
super.aggregateSingle(data)
}
}

}

}
2 changes: 1 addition & 1 deletion src/main/groovy/au/org/ala/ecodata/reporting/Score.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package au.org.ala.ecodata.reporting
class Score {

/** Enumerates the currently supported ways to aggregate output scores. */
enum AGGREGATION_TYPE {SUM, AVERAGE, COUNT, HISTOGRAM, SET}
enum AGGREGATION_TYPE {SUM, AVERAGE, COUNT, HISTOGRAM, SET, DISTINCT_SUM}

/** The name of the output to which the score belongs */
String outputName
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package au.org.ala.ecodata.reporting

import spock.lang.Specification

class DistinctSumAggregatorSpec extends Specification {

// write a test for the DistinctSumAggregator
def "The DistinctSumAggregator can sum the distinct values of a property"() {
given:
Map config = [
label:"value1",
"property": "data.value1",
"type": "DISTINCT_SUM",
"keyProperty": "data.group"
]
Aggregators.DistinctSumAggregator aggregator = new AggregatorFactory().createAggregator(config)

when:
aggregator.aggregate([data:[value1:1, group: "group1"]])
aggregator.aggregate([data:[value1:1, group: "group1"]])
aggregator.aggregate([data:[value1:2, group: "group1"]])
aggregator.aggregate([data:[value1:2, group: "group2"]])
aggregator.aggregate([data:[value1:3, group: "group3"]])

AggregationResult result = aggregator.result()

then:
result.result == 6
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class ExpressionAggregatorSpec extends Specification {
[
label:"value2",
"property": "data.value2",
"type": "SUM"
"keyProperty": "data.group",
"type": "DISTINCT_SUM"
],
[
label:"value3",
Expand Down

0 comments on commit be7c6a6

Please sign in to comment.