=== modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/DefaultAggregationService.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/DefaultAggregationService.java 2010-07-04 10:48:51 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/DefaultAggregationService.java 2010-07-04 11:50:16 +0000 @@ -37,6 +37,7 @@ import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; import org.hisp.dhis.indicator.Indicator; import org.hisp.dhis.organisationunit.OrganisationUnit; +import static org.hisp.dhis.system.util.DateUtils.*; import static org.hisp.dhis.dataelement.DataElement.*; @@ -72,6 +73,13 @@ this.averageIntDataElementAggregation = averageIntDataElementAggregation; } + private AbstractDataElementAggregation averageIntSingleValueAggregation; + + public void setAverageIntSingleValueAggregation( AbstractDataElementAggregation averageIntSingleValueAggregation ) + { + this.averageIntSingleValueAggregation = averageIntSingleValueAggregation; + } + private AbstractDataElementAggregation averageBoolDataElementAggregation; public void setAverageBoolDataElementAggregation( AbstractDataElementAggregation averageBoolDataElementAggregation ) @@ -101,7 +109,7 @@ OrganisationUnit organisationUnit ) { AbstractDataElementAggregation dataElementAggregation = - getInstance( dataElement.getType(), dataElement.getAggregationOperator() ); + getInstance( dataElement.getType(), dataElement.getAggregationOperator(), startDate, endDate, dataElement ); return dataElementAggregation.getAggregatedValue( dataElement, optionCombo, startDate, endDate, organisationUnit ); } @@ -137,7 +145,7 @@ // Supportive methods // ------------------------------------------------------------------------- - private AbstractDataElementAggregation getInstance( String valueType, String aggregationOperator ) + private AbstractDataElementAggregation getInstance( String valueType, String aggregationOperator, Date startDate, Date endDate, DataElement dataElement ) { if ( valueType.equals( VALUE_TYPE_INT ) && aggregationOperator.equals( AGGREGATION_OPERATOR_SUM ) ) { @@ -147,6 +155,10 @@ { return sumBoolDataElementAggregation; } + else if ( valueType.equals( VALUE_TYPE_INT ) && aggregationOperator.equals( AGGREGATION_OPERATOR_AVERAGE ) && dataElement.getFrequencyOrder() >= getDaysInclusive( startDate, endDate ) ) + { + return averageIntSingleValueAggregation; + } else if ( valueType.equals( VALUE_TYPE_INT ) && aggregationOperator.equals( AGGREGATION_OPERATOR_AVERAGE ) ) { return averageIntDataElementAggregation; === modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/cache/AggregationCache.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/cache/AggregationCache.java 2010-06-27 15:34:05 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/cache/AggregationCache.java 2010-07-04 11:50:16 +0000 @@ -46,7 +46,7 @@ Period getPeriod( int periodId ); - Collection getPeriodIds( Date startDate, Date endDate ); + Collection getIntersectingPeriodIds( Date startDate, Date endDate ); double getAggregatedDataValue( DataElement dataElement, DataElementCategoryOptionCombo optionCombo, Date startDate, Date endDate, OrganisationUnit organisationUnit ); === modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/cache/MemoryAggregationCache.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/cache/MemoryAggregationCache.java 2010-06-27 15:34:05 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/cache/MemoryAggregationCache.java 2010-07-04 11:50:16 +0000 @@ -114,7 +114,7 @@ return period; } - public Collection getPeriodIds( Date startDate, Date endDate ) + public Collection getIntersectingPeriodIds( Date startDate, Date endDate ) { String key = startDate.toString() + SEPARATOR + endDate.toString(); === modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageBoolDataElementAggregation.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageBoolDataElementAggregation.java 2010-06-08 19:47:40 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageBoolDataElementAggregation.java 2010-07-04 11:50:16 +0000 @@ -70,7 +70,7 @@ { OrganisationUnitHierarchy hierarchy = aggregationCache.getOrganisationUnitHierarchy(); - Collection periods = aggregationCache.getPeriodIds( startDate, endDate ); + Collection periods = aggregationCache.getIntersectingPeriodIds( startDate, endDate ); Collection values = aggregationStore.getDataValues( hierarchy.getChildren( organisationUnitId ), dataElementId, optionComboId, periods ); === modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageIntDataElementAggregation.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageIntDataElementAggregation.java 2010-06-27 15:34:05 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageIntDataElementAggregation.java 2010-07-04 11:50:16 +0000 @@ -96,7 +96,7 @@ protected Collection getDataValues( int dataElementId, int optionComboId, int organisationUnitId, Date startDate, Date endDate ) { - Collection periods = aggregationCache.getPeriodIds( startDate, endDate ); + Collection periods = aggregationCache.getIntersectingPeriodIds( startDate, endDate ); Collection values = aggregationStore.getDataValues( organisationUnitId, dataElementId, optionComboId, periods ); @@ -128,7 +128,7 @@ * aggregation period * @param aggregationEndDate The original end date of the entire aggregation * period - * @return The numerator and denominator of the AVERAGE value + * @return The AVERAGE value. */ protected double[] getAggregateOfValues( Collection dataValues, Date startDate, Date endDate, Date aggregationStartDate, Date aggregationEndDate ) === added file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageIntSingleValueDataElementAggregation.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageIntSingleValueDataElementAggregation.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/AverageIntSingleValueDataElementAggregation.java 2010-07-04 11:50:16 +0000 @@ -0,0 +1,140 @@ +package org.hisp.dhis.aggregation.impl.dataelement; + +/* + * Copyright (c) 2004-2010, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import static org.hisp.dhis.system.util.DateUtils.getDays; + +import java.util.Collection; +import java.util.Date; + +import org.hisp.dhis.aggregation.AggregationService; +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo; +import org.hisp.dhis.datavalue.DataValue; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.organisationunit.OrganisationUnitHierarchy; +import org.hisp.dhis.period.Period; + +/** + * @author Lars Helge Overland + * @version $Id: SumBoolDataElementAggregation.java 4753 2008-03-14 12:48:50Z larshelg $ + */ +public class AverageIntSingleValueDataElementAggregation + extends AbstractDataElementAggregation +{ + public double getAggregatedValue( DataElement dataElement, DataElementCategoryOptionCombo optionCombo, Date aggregationStartDate, Date aggregationEndDate, + OrganisationUnit organisationUnit ) + { + double[] sums = getSumAndRelevantDays( dataElement.getId(), optionCombo.getId(), aggregationStartDate, aggregationEndDate, + organisationUnit.getId() ); + + if ( sums[1] > 0 ) + { + return sums[0]; + } + else + { + return AggregationService.NO_VALUES_REGISTERED; + } + } + + protected Collection getDataValues( int dataElementId, int optionComboId, int organisationUnitId, + Date startDate, Date endDate ) + { + OrganisationUnitHierarchy hierarchy = aggregationCache.getOrganisationUnitHierarchy(); + + Collection periods = aggregationCache.getIntersectingPeriodIds( startDate, endDate ); + + Collection values = aggregationStore.getDataValues( hierarchy.getChildren( organisationUnitId ), dataElementId, optionComboId, periods ); + + return values; + } + + /** + * The main performance disadvantage of average aggregation operations is that + * the average must be calculated for each organisation unit individually, and + * then summarized, in contrast to sum operations where the sum can be calculated + * directly for all organisation units. Still, in cases where the aggregation + * period duration is shorter than the data element period type duration, there + * can only be one value registered for each organisation unit for that data + * element. This implies that there is no need to calculate the average and + * that the aggregate can be calculated directly, improving performance + * dramatically. This method is performs the described behaviour by taking + * the sum directly using whatever value found. + * + * @param dataValues The datavalues to aggregate + * @param startDate Start date of the period to aggregate over + * @param endDate End date of the period to aggregate over + * @param aggregationStartDate The original start date of the entire + * aggregation period + * @param aggregationEndDate The original end date of the entire aggregation + * period + */ + protected double[] getAggregateOfValues( Collection dataValues, Date startDate, Date endDate, + Date aggregationStartDate, Date aggregationEndDate ) + { + double totalSum = 0; + double totalRelevantDays = 0; + + for ( DataValue dataValue : dataValues ) + { + Period currentPeriod = aggregationCache.getPeriod( dataValue.getPeriod().getId() ); + Date currentStartDate = currentPeriod.getStartDate(); + Date currentEndDate = currentPeriod.getEndDate(); + + double value = 0; + + try + { + value = Double.parseDouble( dataValue.getValue() ); + } + catch ( Exception ex ) + { + } + + double currentPeriodDuration = ( getDays( currentEndDate ) - getDays( currentStartDate ) ); + + if ( currentPeriodDuration > 0 ) + { + long relevantDays = 0; + + if ( currentStartDate.compareTo( endDate ) <= 0 && currentEndDate.compareTo( startDate ) >= 0 ) // Value is intersecting + { + relevantDays = getDays( endDate ) - getDays( startDate ); + totalSum += value; + } + + totalRelevantDays += relevantDays; + } + } + + double[] fraction = { totalSum, totalRelevantDays }; + + return fraction; + } +} === modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/SumBoolDataElementAggregation.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/SumBoolDataElementAggregation.java 2010-06-27 15:34:05 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/SumBoolDataElementAggregation.java 2010-07-04 11:50:16 +0000 @@ -41,7 +41,6 @@ import static org.hisp.dhis.system.util.MathUtils.getFloor; import static org.hisp.dhis.system.util.DateUtils.getDays; - /** * @author Lars Helge Overland * @version $Id: SumBoolDataElementAggregation.java 4753 2008-03-14 12:48:50Z larshelg $ @@ -70,7 +69,7 @@ { OrganisationUnitHierarchy hierarchy = aggregationCache.getOrganisationUnitHierarchy(); - Collection periods = aggregationCache.getPeriodIds( startDate, endDate ); + Collection periods = aggregationCache.getIntersectingPeriodIds( startDate, endDate ); Collection values = aggregationStore.getDataValues( hierarchy.getChildren( organisationUnitId ), dataElementId, optionComboId, periods ); === modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/SumIntDataElementAggregation.java' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/SumIntDataElementAggregation.java 2010-06-08 19:47:40 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/java/org/hisp/dhis/aggregation/impl/dataelement/SumIntDataElementAggregation.java 2010-07-04 11:50:16 +0000 @@ -68,7 +68,7 @@ { OrganisationUnitHierarchy hierarchy = aggregationCache.getOrganisationUnitHierarchy(); - Collection periods = aggregationCache.getPeriodIds( startDate, endDate ); + Collection periods = aggregationCache.getIntersectingPeriodIds( startDate, endDate ); Collection values = aggregationStore.getDataValues( hierarchy.getChildren( organisationUnitId ), dataElementId, optionComboId, periods ); === modified file 'dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/resources/META-INF/dhis/beans.xml 2010-06-27 15:34:05 +0000 +++ dhis-2/dhis-services/dhis-service-aggregationengine-default/src/main/resources/META-INF/dhis/beans.xml 2010-07-04 11:50:16 +0000 @@ -21,6 +21,8 @@ ref="org.hisp.dhis.aggregation.impl.dataelement.SumBoolDataElementAggregation"/> + + + + + + entries = getAggregate( crossTabValues, period.getStartDate(), period.getEndDate(), period.getStartDate(), period.getEndDate(), unitLevel ); // - final Map values = new HashMap(); // + final Map values = new HashMap( entries.size() ); // for ( final Entry entry : entries.entrySet() ) {