dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #20640
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 9548: Analytics, impl generation of completeness tables
------------------------------------------------------------
revno: 9548
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2013-01-17 18:49:13 +0100
message:
Analytics, impl generation of completeness tables
added:
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractJdbcTableManager.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcCompletenessTableManager.java
modified:
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTableManager.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcAnalyticsTableManager.java
dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/PartitionUtils.java
dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml
dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java
dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/PartitionUtilsTest.java
dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ResourceTableController.java
--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk
Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTableManager.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTableManager.java 2012-12-22 18:09:46 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTableManager.java 2013-01-17 17:49:13 +0000
@@ -34,10 +34,20 @@
public interface AnalyticsTableManager
{
- public static final String TABLE_NAME = "analytics";
public static final String TABLE_TEMP_SUFFIX = "_temp";
- public static final String TABLE_NAME_TEMP = TABLE_NAME + TABLE_TEMP_SUFFIX;
-
+ public static final String ANALYTICS_TABLE_NAME = "analytics";
+ public static final String COMPLETENESS_TABLE_NAME = "completeness";
+
+ /**
+ * Returns the base table name.
+ */
+ String getTableName();
+
+ /**
+ * Returns the temporary table name.
+ */
+ String getTempTableName();
+
/**
* Attempts to drop and then create analytics table.
*
@@ -74,8 +84,12 @@
/**
* Returns a list of string arrays in where the first index holds the database
- * column name, the second index holds the database column type and the third
- * column holds a table alias.
+ * column name, the second index holds the database column data type and the
+ * third column holds a table alias and name, i.e.:
+ *
+ * 0 = database column name
+ * 1 = database column data type
+ * 2 = column alias and name
*/
List<String[]> getDimensionColumns();
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java 2012-12-18 00:49:03 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java 2013-01-17 17:49:13 +0000
@@ -45,7 +45,8 @@
*
* @param params the data query params.
* @param optimalQueries the number of optimal queries for the planner to return.
+ * @param tableName the base table name.
* @return list of data query params.
*/
- List<DataQueryParams> planQuery( DataQueryParams params, int optimalQueries );
+ List<DataQueryParams> planQuery( DataQueryParams params, int optimalQueries, String tableName );
}
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2013-01-17 14:59:00 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java 2013-01-17 17:49:13 +0000
@@ -46,6 +46,7 @@
import org.hisp.dhis.analytics.AnalyticsManager;
import org.hisp.dhis.analytics.AnalyticsService;
+import org.hisp.dhis.analytics.AnalyticsTableManager;
import org.hisp.dhis.analytics.DataQueryParams;
import org.hisp.dhis.analytics.DimensionOption;
import org.hisp.dhis.analytics.QueryPlanner;
@@ -201,7 +202,7 @@
int optimalQueries = MathUtils.getWithin( SystemUtils.getCpuCores(), 1, 6 );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, optimalQueries );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, optimalQueries, AnalyticsTableManager.ANALYTICS_TABLE_NAME );
t.getTime( "Planned query for optimal: " + optimalQueries + ", got: " + queries.size() );
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2013-01-13 13:49:33 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java 2013-01-17 17:49:13 +0000
@@ -63,7 +63,7 @@
// DefaultQueryPlanner implementation
// -------------------------------------------------------------------------
- public List<DataQueryParams> planQuery( DataQueryParams params, int optimalQueries )
+ public List<DataQueryParams> planQuery( DataQueryParams params, int optimalQueries, String tableName )
{
Assert.isTrue( !params.getDimensions().isEmpty() );
Assert.isTrue( params.dimensionsAsFilters().isEmpty() );
@@ -77,7 +77,7 @@
List<DataQueryParams> queries = new ArrayList<DataQueryParams>();
- List<DataQueryParams> groupedByPartition = groupByPartition( params );
+ List<DataQueryParams> groupedByPartition = groupByPartition( params, tableName );
for ( DataQueryParams byPartition : groupedByPartition )
{
@@ -196,31 +196,31 @@
* partition it should be executed against. Sets the partition table name on
* each query. Queries are grouped based on both dimensions and filters.
*/
- private List<DataQueryParams> groupByPartition( DataQueryParams params )
+ private List<DataQueryParams> groupByPartition( DataQueryParams params, String tableName )
{
List<DataQueryParams> queries = new ArrayList<DataQueryParams>();
if ( params.getPeriods() != null && !params.getPeriods().isEmpty() )
{
- ListMap<String, IdentifiableObject> tablePeriodMap = PartitionUtils.getTablePeriodMap( params.getPeriods() );
+ ListMap<String, IdentifiableObject> tablePeriodMap = PartitionUtils.getTablePeriodMap( params.getPeriods(), tableName );
- for ( String tableName : tablePeriodMap.keySet() )
+ for ( String table : tablePeriodMap.keySet() )
{
DataQueryParams query = new DataQueryParams( params );
- query.setPeriods( tablePeriodMap.get( tableName ) );
- query.setTableName( tableName );
+ query.setPeriods( tablePeriodMap.get( table ) );
+ query.setTableName( table );
queries.add( query );
}
}
else
{
- ListMap<String, IdentifiableObject> tablePeriodMap = PartitionUtils.getTablePeriodMap( params.getFilterPeriods() );
+ ListMap<String, IdentifiableObject> tablePeriodMap = PartitionUtils.getTablePeriodMap( params.getFilterPeriods(), tableName );
- for ( String tableName : tablePeriodMap.keySet() )
+ for ( String table : tablePeriodMap.keySet() )
{
DataQueryParams query = new DataQueryParams( params );
- query.setFilterPeriods( tablePeriodMap.get( tableName ) );
- query.setTableName( tableName );
+ query.setFilterPeriods( tablePeriodMap.get( table ) );
+ query.setTableName( table );
queries.add( query );
}
}
=== added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractJdbcTableManager.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractJdbcTableManager.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractJdbcTableManager.java 2013-01-17 17:49:13 +0000
@@ -0,0 +1,189 @@
+package org.hisp.dhis.analytics.table;
+
+/*
+ * Copyright (c) 2004-2012, 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 java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.analytics.AnalyticsTableManager;
+import org.hisp.dhis.common.CodeGenerator;
+import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.jdbc.StatementBuilder;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.BadSqlGrammarException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.scheduling.annotation.Async;
+
+public abstract class AbstractJdbcTableManager
+ implements AnalyticsTableManager
+{
+ protected static final Log log = LogFactory.getLog( JdbcAnalyticsTableManager.class );
+
+ public static final String PREFIX_ORGUNITGROUPSET = "ougs_";
+ public static final String PREFIX_ORGUNITLEVEL = "uidlevel";
+ public static final String PREFIX_INDEX = "in_";
+
+ private static final String TABLE_TEMP_SUFFIX = "_temp";
+
+ @Autowired
+ protected OrganisationUnitService organisationUnitService;
+
+ @Autowired
+ protected DataElementService dataElementService;
+
+ @Autowired
+ protected OrganisationUnitGroupService organisationUnitGroupService;
+
+ @Autowired
+ protected StatementBuilder statementBuilder;
+
+ @Autowired
+ protected JdbcTemplate jdbcTemplate;
+
+ // -------------------------------------------------------------------------
+ // Implementation
+ // -------------------------------------------------------------------------
+
+ public String getTempTableName()
+ {
+ return getTableName() + TABLE_TEMP_SUFFIX;
+ }
+
+ @Async
+ public Future<?> createIndexesAsync( String tableName, List<String> columns )
+ {
+ for ( String column : columns )
+ {
+ final String index = PREFIX_INDEX + column + "_" + tableName + "_" + CodeGenerator.generateCode();
+
+ final String sql = "create index " + index + " on " + tableName + " (" + column + ")";
+
+ executeSilently( sql );
+
+ log.info( "Created index: " + index );
+ }
+
+ log.info( "Indexes created" );
+
+ return null;
+ }
+
+ public void swapTable( String tableName )
+ {
+ final String realTable = tableName.replaceFirst( TABLE_TEMP_SUFFIX, "" );
+
+ final String sqlDrop = "drop table " + realTable;
+
+ executeSilently( sqlDrop );
+
+ final String sqlAlter = "alter table " + tableName + " rename to " + realTable;
+
+ executeSilently( sqlAlter );
+ }
+
+ public List<String> getDimensionColumnNames()
+ {
+ List<String[]> columns = getDimensionColumns();
+
+ List<String> columnNames = new ArrayList<String>();
+
+ for ( String[] column : columns )
+ {
+ columnNames.add( column[0] );
+ }
+
+ return columnNames;
+ }
+
+ public boolean pruneTable( String tableName )
+ {
+ final String sqlCount = "select count(*) from " + tableName;
+
+ log.info( "Count SQL: " + sqlCount );
+
+ final boolean empty = jdbcTemplate.queryForInt( sqlCount ) == 0;
+
+ if ( empty )
+ {
+ final String sqlDrop = "drop table " + tableName;
+
+ executeSilently( sqlDrop );
+
+ log.info( "Drop SQL: " + sqlDrop );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Async
+ public Future<?> vacuumTableAsync( String tableName )
+ {
+ final String sql = statementBuilder.getVacuum( tableName );
+
+ log.info( "Vacuum SQL:" + sql );
+
+ jdbcTemplate.execute( sql );
+
+ return null;
+ }
+
+ public void dropTable( String tableName )
+ {
+ final String realTable = tableName.replaceFirst( TABLE_TEMP_SUFFIX, "" );
+
+ executeSilently( "drop table " + tableName );
+ executeSilently( "drop table " + realTable );
+ }
+
+ // -------------------------------------------------------------------------
+ // Supportive methods
+ // -------------------------------------------------------------------------
+
+ /**
+ * Executes a SQL statement. Ignores existing tables/indexes when attempting
+ * to create new.
+ */
+ protected void executeSilently( String sql )
+ {
+ try
+ {
+ jdbcTemplate.execute( sql );
+ }
+ catch ( BadSqlGrammarException ex )
+ {
+ log.warn( ex.getMessage() );
+ }
+ }
+}
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java 2012-12-22 18:09:46 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java 2013-01-17 17:49:13 +0000
@@ -54,9 +54,13 @@
{
private static final Log log = LogFactory.getLog( DefaultAnalyticsTableService.class );
- @Autowired
private AnalyticsTableManager tableManager;
+ public void setTableManager( AnalyticsTableManager tableManager )
+ {
+ this.tableManager = tableManager;
+ }
+
@Autowired
private OrganisationUnitService organisationUnitService;
@@ -78,7 +82,8 @@
final Date earliest = tableManager.getEarliestData();
final Date latest = tableManager.getLatestData();
- final List<String> tables = PartitionUtils.getTempTableNames( earliest, latest );
+ final String tableName = tableManager.getTableName();
+ final List<String> tables = PartitionUtils.getTempTableNames( earliest, latest, tableName );
clock.logTime( "Checked data timespan and got tables: " + tables );
//dropTables( tables );
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcAnalyticsTableManager.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcAnalyticsTableManager.java 2012-12-27 18:15:23 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcAnalyticsTableManager.java 2013-01-17 17:49:13 +0000
@@ -27,6 +27,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import static org.hisp.dhis.system.util.TextUtils.getQuotedCommaDelimitedString;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -34,27 +36,14 @@
import java.util.List;
import java.util.concurrent.Future;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.hisp.dhis.analytics.AnalyticsTableManager;
import org.hisp.dhis.analytics.DataQueryParams;
-import org.hisp.dhis.common.CodeGenerator;
import org.hisp.dhis.dataelement.DataElementGroupSet;
-import org.hisp.dhis.dataelement.DataElementService;
-import org.hisp.dhis.jdbc.StatementBuilder;
-import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet;
import org.hisp.dhis.organisationunit.OrganisationUnitLevel;
-import org.hisp.dhis.organisationunit.OrganisationUnitService;
import org.hisp.dhis.period.PeriodType;
import org.hisp.dhis.system.util.DateUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.jdbc.BadSqlGrammarException;
-import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
-import static org.hisp.dhis.system.util.TextUtils.getQuotedCommaDelimitedString;
-
/**
* This class manages the analytics table. The analytics table is a denormalized
* table designed for analysis which contains raw data values. It has columns for
@@ -72,35 +61,17 @@
* @author Lars Helge Overland
*/
public class JdbcAnalyticsTableManager
- implements AnalyticsTableManager
+ extends AbstractJdbcTableManager
{
- private static final Log log = LogFactory.getLog( JdbcAnalyticsTableManager.class );
-
- public static final String PREFIX_ORGUNITGROUPSET = "ougs_";
- public static final String PREFIX_ORGUNITLEVEL = "uidlevel";
- public static final String PREFIX_INDEX = "in_";
-
- @Autowired
- private OrganisationUnitService organisationUnitService;
-
- @Autowired
- private DataElementService dataElementService;
-
- @Autowired
- private OrganisationUnitGroupService organisationUnitGroupService;
-
- @Autowired
- private StatementBuilder statementBuilder;
-
- @Autowired
- private JdbcTemplate jdbcTemplate;
-
// -------------------------------------------------------------------------
// Implementation
// -------------------------------------------------------------------------
-
- //TODO average aggregation operator data, pre-aggregate in time dimension, not in org unit dimension
+ public String getTableName()
+ {
+ return "analytics";
+ }
+
public void createTable( String tableName )
{
final String sqlDrop = "drop table " + tableName;
@@ -122,38 +93,6 @@
}
@Async
- public Future<?> createIndexesAsync( String tableName, List<String> columns )
- {
- for ( String column : columns )
- {
- final String index = PREFIX_INDEX + column + "_" + tableName + "_" + CodeGenerator.generateCode();
-
- final String sql = "create index " + index + " on " + tableName + " (" + column + ")";
-
- executeSilently( sql );
-
- log.info( "Created index: " + index );
- }
-
- log.info( "Indexes created" );
-
- return null;
- }
-
- public void swapTable( String tableName )
- {
- final String realTable = tableName.replaceFirst( TABLE_TEMP_SUFFIX, "" );
-
- final String sqlDrop = "drop table " + realTable;
-
- executeSilently( sqlDrop );
-
- final String sqlAlter = "alter table " + tableName + " rename to " + realTable;
-
- executeSilently( sqlAlter );
- }
-
- @Async
public Future<?> populateTableAsync( String tableName, Date startDate, Date endDate )
{
populateTable( tableName, startDate, endDate, "cast(dv.value as double precision)", "int" );
@@ -210,13 +149,6 @@
jdbcTemplate.execute( sql );
}
- /**
- * Returns a list of dimension columns. Each entry is an array with:
- *
- * 0 = column name
- * 1 = data type
- * 2 = column alias and name
- */
public List<String[]> getDimensionColumns()
{
List<String[]> columns = new ArrayList<String[]>();
@@ -265,20 +197,6 @@
return columns;
}
- public List<String> getDimensionColumnNames()
- {
- List<String[]> columns = getDimensionColumns();
-
- List<String> columnNames = new ArrayList<String>();
-
- for ( String[] column : columns )
- {
- columnNames.add( column[0] );
- }
-
- return columnNames;
- }
-
public Date getEarliestData()
{
final String sql = "select min(pe.startdate) from datavalue dv " +
@@ -295,36 +213,6 @@
return jdbcTemplate.queryForObject( sql, Date.class );
}
- public boolean pruneTable( String tableName )
- {
- final String sqlCount = "select count(*) from " + tableName;
-
- log.info( "Count SQL: " + sqlCount );
-
- final boolean empty = jdbcTemplate.queryForInt( sqlCount ) == 0;
-
- if ( empty )
- {
- final String sqlDrop = "drop table " + tableName;
-
- executeSilently( sqlDrop );
-
- log.info( "Drop SQL: " + sqlDrop );
-
- return true;
- }
-
- return false;
- }
-
- public void dropTable( String tableName )
- {
- final String realTable = tableName.replaceFirst( TABLE_TEMP_SUFFIX, "" );
-
- executeSilently( "drop table " + tableName );
- executeSilently( "drop table " + realTable );
- }
-
public void applyAggregationLevels( String tableName, Collection<String> dataElements, int aggregationLevel )
{
StringBuilder sql = new StringBuilder( "update " + tableName + " set " );
@@ -347,36 +235,4 @@
jdbcTemplate.execute( sql.toString() );
}
-
- @Async
- public Future<?> vacuumTableAsync( String tableName )
- {
- final String sql = statementBuilder.getVacuum( tableName );
-
- log.info( "Vacuum SQL:" + sql );
-
- jdbcTemplate.execute( sql );
-
- return null;
- }
-
- // -------------------------------------------------------------------------
- // Supportive methods
- // -------------------------------------------------------------------------
-
- /**
- * Executes a SQL statement. Ignores existing tables/indexes when attempting
- * to create new.
- */
- private void executeSilently( String sql )
- {
- try
- {
- jdbcTemplate.execute( sql );
- }
- catch ( BadSqlGrammarException ex )
- {
- log.warn( ex.getMessage() );
- }
- }
}
=== added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcCompletenessTableManager.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcCompletenessTableManager.java 1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcCompletenessTableManager.java 2013-01-17 17:49:13 +0000
@@ -0,0 +1,172 @@
+package org.hisp.dhis.analytics.table;
+
+/*
+ * Copyright (c) 2004-2012, 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet;
+import org.hisp.dhis.organisationunit.OrganisationUnitLevel;
+import org.hisp.dhis.period.PeriodType;
+import org.hisp.dhis.system.util.DateUtils;
+import org.springframework.scheduling.annotation.Async;
+
+public class JdbcCompletenessTableManager
+ extends AbstractJdbcTableManager
+{
+ public String getTableName()
+ {
+ return "completeness";
+ }
+
+ public void createTable( String tableName )
+ {
+ final String sqlDrop = "drop table " + tableName;
+
+ executeSilently( sqlDrop );
+
+ String sqlCreate = "create table " + tableName + " (";
+
+ for ( String[] col : getDimensionColumns() )
+ {
+ sqlCreate += col[0] + " " + col[1] + ",";
+ }
+
+ sqlCreate += "date date)";
+
+ log.info( "Create SQL: " + sqlCreate );
+
+ executeSilently( sqlCreate );
+ }
+
+ @Async
+ public Future<?> populateTableAsync( String tableName, Date startDate, Date endDate )
+ {
+ final String start = DateUtils.getMediumDateString( startDate );
+ final String end = DateUtils.getMediumDateString( endDate );
+
+ String insert = "insert into " + tableName + " (";
+
+ for ( String[] col : getDimensionColumns() )
+ {
+ insert += col[0] + ",";
+ }
+
+ insert += "date) ";
+
+ String select = "select ";
+
+ for ( String[] col : getDimensionColumns() )
+ {
+ select += col[2] + ",";
+ }
+
+ select = select.replace( "organisationunitid", "sourceid" ); // Legacy fix
+
+ select +=
+ "cdr.date as date " +
+ "from completedatasetregistration cdr " +
+ "left join _organisationunitgroupsetstructure ougs on cdr.sourceid=ougs.organisationunitid " +
+ "left join _orgunitstructure ous on cdr.sourceid=ous.organisationunitid " +
+ "left join _periodstructure ps on cdr.periodid=ps.periodid " +
+ "left join period pe on cdr.periodid=pe.periodid " +
+ "left join dataset ds on cdr.datasetid=ds.datasetid " +
+ "where pe.startdate >= '" + start + "' " +
+ "and pe.startdate <= '" + end + "'" +
+ "and cdr.date is not null";
+
+ final String sql = insert + select;
+
+ log.info( "Populate SQL: "+ sql );
+
+ jdbcTemplate.execute( sql );
+
+ return null;
+ }
+
+ public List<String[]> getDimensionColumns()
+ {
+ List<String[]> columns = new ArrayList<String[]>();
+
+ Collection<OrganisationUnitGroupSet> orgUnitGroupSets =
+ organisationUnitGroupService.getCompulsoryOrganisationUnitGroupSets();
+
+ Collection<OrganisationUnitLevel> levels =
+ organisationUnitService.getOrganisationUnitLevels();
+
+ for ( OrganisationUnitGroupSet groupSet : orgUnitGroupSets )
+ {
+ String[] col = { groupSet.getUid(), "character(11)", "ougs." + groupSet.getUid() };
+ columns.add( col );
+ }
+
+ for ( OrganisationUnitLevel level : levels )
+ {
+ String column = PREFIX_ORGUNITLEVEL + level.getLevel();
+ String[] col = { column, "character(11)", "ous." + column };
+ columns.add( col );
+ }
+
+ for ( PeriodType periodType : PeriodType.getAvailablePeriodTypes().subList( 0, 7 ) )
+ {
+ String column = periodType.getName().toLowerCase();
+ String[] col = { column, "character varying(10)", "ps." + column };
+ columns.add( col );
+ }
+
+ String[] de = { "ds", "character(11) not null", "ds.uid" };
+
+ columns.add( de );
+
+ return columns;
+ }
+
+ public Date getEarliestData()
+ {
+ final String sql = "select min(pe.startdate) from completedatasetregistration cdr " +
+ "join period pe on cdr.periodid=pe.periodid";
+
+ return jdbcTemplate.queryForObject( sql, Date.class );
+ }
+
+ public Date getLatestData()
+ {
+ final String sql = "select max(pe.startdate) from completedatasetregistration cdr " +
+ "join period pe on cdr.periodid=pe.periodid";
+
+ return jdbcTemplate.queryForObject( sql, Date.class );
+ }
+
+ public void applyAggregationLevels( String tableName, Collection<String> dataElements, int aggregationLevel )
+ {
+ // Not relevant
+ }
+}
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/PartitionUtils.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/PartitionUtils.java 2013-01-07 14:31:20 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/PartitionUtils.java 2013-01-17 17:49:13 +0000
@@ -27,14 +27,12 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-import static org.hisp.dhis.analytics.AnalyticsTableManager.TABLE_NAME;
-import static org.hisp.dhis.analytics.AnalyticsTableManager.TABLE_NAME_TEMP;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
+import org.hisp.dhis.analytics.AnalyticsTableManager;
import org.hisp.dhis.common.IdentifiableObject;
import org.hisp.dhis.period.Period;
import org.hisp.dhis.period.PeriodType;
@@ -47,7 +45,7 @@
private static final String SEP = "_";
- public static List<String> getTempTableNames( Date earliest, Date latest )
+ public static List<String> getTempTableNames( Date earliest, Date latest, String tableName )
{
if ( earliest == null || latest == null || earliest.after( latest ) )
{
@@ -60,7 +58,7 @@
while ( period != null && period.getStartDate().before( latest ) )
{
- String table = TABLE_NAME_TEMP + SEP + period.getIsoDate();
+ String table = tableName + AnalyticsTableManager.TABLE_TEMP_SUFFIX + SEP + period.getIsoDate();
tables.add( table );
@@ -70,11 +68,11 @@
return tables;
}
- public static String getTable( Period period )
+ public static String getTable( Period period, String tableName )
{
Period quarter = PERIODTYPE.createPeriod( period.getStartDate() );
- return TABLE_NAME + SEP + quarter.getIsoDate();
+ return tableName + SEP + quarter.getIsoDate();
}
public static Period getPeriod( String tableName )
@@ -90,13 +88,13 @@
return PeriodType.getPeriodFromIsoString( isoPeriod );
}
- public static ListMap<String, IdentifiableObject> getTablePeriodMap( Collection<IdentifiableObject> periods )
+ public static ListMap<String, IdentifiableObject> getTablePeriodMap( Collection<IdentifiableObject> periods, String tableName )
{
ListMap<String, IdentifiableObject> map = new ListMap<String, IdentifiableObject>();
for ( IdentifiableObject period : periods )
{
- map.putValue( getTable( (Period) period ), period );
+ map.putValue( getTable( (Period) period, tableName ), period );
}
return map;
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2012-12-17 16:58:29 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2013-01-17 17:49:13 +0000
@@ -3,9 +3,21 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="org.hisp.dhis.analytics.AnalyticsTableManager" class="org.hisp.dhis.analytics.table.JdbcAnalyticsTableManager" />
- <bean id="org.hisp.dhis.analytics.AnalyticsTableService" class="org.hisp.dhis.analytics.table.DefaultAnalyticsTableService" />
+
+ <bean id="org.hisp.dhis.analytics.CompletenessTableManager" class="org.hisp.dhis.analytics.table.JdbcCompletenessTableManager" />
+
+ <bean id="org.hisp.dhis.analytics.AnalyticsTableService" class="org.hisp.dhis.analytics.table.DefaultAnalyticsTableService">
+ <property name="tableManager" ref="org.hisp.dhis.analytics.AnalyticsTableManager" />
+ </bean>
+
+ <bean id="org.hisp.dhis.analytics.CompletenessTableService" class="org.hisp.dhis.analytics.table.DefaultAnalyticsTableService">
+ <property name="tableManager" ref="org.hisp.dhis.analytics.CompletenessTableManager" />
+ </bean>
+
<bean id="org.hisp.dhis.analytics.AnalyticsManager" class="org.hisp.dhis.analytics.data.JdbcAnalyticsManager" />
+
<bean id="org.hisp.dhis.analytics.AnalyticsService" class="org.hisp.dhis.analytics.data.DefaultAnalyticsService" />
+
<bean id="org.hisp.dhis.analytics.QueryPlanner" class="org.hisp.dhis.analytics.data.DefaultQueryPlanner" />
</beans>
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java 2013-01-17 11:02:22 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java 2013-01-17 17:49:13 +0000
@@ -31,6 +31,7 @@
import static org.hisp.dhis.analytics.DataQueryParams.ORGUNIT_DIM_ID;
import static org.hisp.dhis.analytics.DataQueryParams.PERIOD_DIM_ID;
import static org.hisp.dhis.common.IdentifiableObjectUtils.getList;
+import static org.hisp.dhis.analytics.AnalyticsTableManager.ANALYTICS_TABLE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -257,7 +258,7 @@
params.setOrganisationUnits( getList( ouA, ouB, ouC, ouD, ouE ) );
params.setPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ), createPeriod( "2000Q3" ), createPeriod( "2000Q4" ), createPeriod( "2001Q1" ), createPeriod( "2001Q2" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 4, queries.size() );
@@ -281,7 +282,7 @@
params.setOrganisationUnits( getList( ouA, ouB, ouC, ouD, ouE ) );
params.setPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ), createPeriod( "2000" ), createPeriod( "200002" ), createPeriod( "200003" ), createPeriod( "200004" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 6, queries.size() );
@@ -319,7 +320,7 @@
params.setOrganisationUnits( getList( ouA, ouB, ouC, ouD, ouE ) );
params.setPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ), createPeriod( "2000Q3" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 5, queries.size() );
@@ -342,7 +343,7 @@
params.setPeriods( getList( createPeriod( "200001" ), createPeriod( "200002" ), createPeriod( "200003" ), createPeriod( "200004" ),
createPeriod( "200005" ), createPeriod( "200006" ), createPeriod( "200007" ), createPeriod( "200008" ), createPeriod( "200009" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 3, queries.size() );
@@ -364,7 +365,7 @@
params.setPeriods( getList( createPeriod( "200001" ), createPeriod( "200002" ), createPeriod( "200003" ), createPeriod( "200004" ),
createPeriod( "200005" ), createPeriod( "200006" ), createPeriod( "200007" ), createPeriod( "200008" ), createPeriod( "200009" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 3, queries.size() );
@@ -386,7 +387,7 @@
params.setPeriods( getList( createPeriod( "200001" ), createPeriod( "200002" ), createPeriod( "200003" ), createPeriod( "200004" ),
createPeriod( "200005" ), createPeriod( "200006" ), createPeriod( "200007" ), createPeriod( "200008" ), createPeriod( "200009" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 3, queries.size() );
@@ -407,7 +408,7 @@
params.setDataElements( getList( deA, deB, deC ) );
params.setOrganisationUnits( getList( ouA, ouB, ouC, ouD, ouE ) );
- queryPlanner.planQuery( params, 4 );
+ queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
}
/**
@@ -423,7 +424,7 @@
params.setOrganisationUnits( getList( ouA, ouB, ouC, ouD, ouE ) );
params.setFilterPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ), createPeriod( "2000Q3" ), createPeriod( "2000Q4" ), createPeriod( "2001Q1" ), createPeriod( "2001Q2" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 4, queries.size() );
}
@@ -441,7 +442,7 @@
params.setOrganisationUnits( getList( ouA, ouB, ouC, ouD, ouE ) );
params.setPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ), createPeriod( "2000" ), createPeriod( "200002" ), createPeriod( "200003" ), createPeriod( "200004" ) ) );
- List<DataQueryParams> queries = queryPlanner.planQuery( params, 4 );
+ List<DataQueryParams> queries = queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
assertEquals( 6, queries.size() );
}
=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/PartitionUtilsTest.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/PartitionUtilsTest.java 2013-01-07 14:31:20 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/PartitionUtilsTest.java 2013-01-17 17:49:13 +0000
@@ -28,8 +28,7 @@
*/
import static org.hisp.dhis.DhisConvenienceTest.createPeriod;
-import static org.hisp.dhis.analytics.AnalyticsTableManager.TABLE_NAME;
-import static org.hisp.dhis.analytics.AnalyticsTableManager.TABLE_NAME_TEMP;
+import static org.hisp.dhis.analytics.AnalyticsTableManager.*;
import static org.hisp.dhis.common.IdentifiableObjectUtils.getList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -46,6 +45,9 @@
public class PartitionUtilsTest
{
+ private static final String TABLE_NAME_TEMP = ANALYTICS_TABLE_NAME + TABLE_TEMP_SUFFIX;
+ private static final String TABLE_NAME = ANALYTICS_TABLE_NAME;
+
@Test
public void testGetTableNames()
{
@@ -53,7 +55,7 @@
Date earliest = cal.set( 2000, 5, 4 ).time();
Date latest = cal.set( 2003, 2, 10 ).time();
- List<String> tables = PartitionUtils.getTempTableNames( earliest, latest );
+ List<String> tables = PartitionUtils.getTempTableNames( earliest, latest, TABLE_NAME );
assertEquals( 4, tables.size() );
assertTrue( tables.contains( TABLE_NAME_TEMP + "_2000" ) );
@@ -65,10 +67,10 @@
@Test
public void testGetTable()
{
- assertEquals( TABLE_NAME + "_2000", PartitionUtils.getTable( createPeriod( "200011" ) ) );
- assertEquals( TABLE_NAME + "_2001", PartitionUtils.getTable( createPeriod( "2001W02" ) ) );
- assertEquals( TABLE_NAME + "_2002", PartitionUtils.getTable( createPeriod( "2002Q2" ) ) );
- assertEquals( TABLE_NAME + "_2003", PartitionUtils.getTable( createPeriod( "2003S2" ) ) );
+ assertEquals( TABLE_NAME + "_2000", PartitionUtils.getTable( createPeriod( "200011" ), TABLE_NAME ) );
+ assertEquals( TABLE_NAME + "_2001", PartitionUtils.getTable( createPeriod( "2001W02" ), TABLE_NAME ) );
+ assertEquals( TABLE_NAME + "_2002", PartitionUtils.getTable( createPeriod( "2002Q2" ), TABLE_NAME ) );
+ assertEquals( TABLE_NAME + "_2003", PartitionUtils.getTable( createPeriod( "2003S2" ), TABLE_NAME ) );
}
@Test
@@ -87,7 +89,7 @@
public void testGetTablePeriodMap()
{
ListMap<String, IdentifiableObject> map = PartitionUtils.getTablePeriodMap( getList(
- createPeriod( "2000S1" ), createPeriod( "2000S2" ), createPeriod( "2001S1" ), createPeriod( "2001S2" ), createPeriod( "2002S1" ) ) );
+ createPeriod( "2000S1" ), createPeriod( "2000S2" ), createPeriod( "2001S1" ), createPeriod( "2001S2" ), createPeriod( "2002S1" ) ), TABLE_NAME );
assertEquals( 3, map.size() );
=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ResourceTableController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ResourceTableController.java 2012-12-27 18:15:23 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ResourceTableController.java 2013-01-17 17:49:13 +0000
@@ -27,6 +27,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import org.hisp.dhis.analytics.AnalyticsTableService;
@@ -48,8 +49,11 @@
{
public static final String RESOURCE_PATH = "/resourceTables";
- @Autowired
+ @Resource(name="org.hisp.dhis.analytics.AnalyticsTableService")
private AnalyticsTableService analyticsTableService;
+
+ @Resource(name="org.hisp.dhis.analytics.CompletenessTableService")
+ private AnalyticsTableService completenessTableService;
@Autowired
private ResourceTableService resourceTableService;
@@ -65,6 +69,15 @@
ContextUtils.okResponse( response, "Initiated analytics table update" );
}
+
+ @RequestMapping( value = "/completeness", method = RequestMethod.PUT )
+ @PreAuthorize( "hasRole('ALL') or hasRole('F_DATA_MART_ADMIN')" )
+ public void completeness( HttpServletResponse response )
+ {
+ completenessTableService.update();
+
+ ContextUtils.okResponse( response, "Initiated completeness table update" );
+ }
@RequestMapping( method = RequestMethod.PUT )
@PreAuthorize( "hasRole('ALL') or hasRole('F_PERFORM_MAINTENANCE')" )