All Downloads are FREE. Search and download functionalities are using the official Maven repository.

weka.experiment.DatabaseResultListener Maven / Gradle / Ivy

Go to download

The Waikato Environment for Knowledge Analysis (WEKA), a machine learning workbench. This version represents the developer version, the "bleeding edge" of development, you could say. New functionality gets added to this version.

There is a newer version: 3.9.6
Show newest version
/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see .
 */

/*
 *    DatabaseResultListener.java
 *    Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand
 *
 */

package weka.experiment;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;

import weka.core.RevisionUtils;

/**
 *  Takes results from a result producer and sends them
 * to a database.
 * 

* * * @author Len Trigg ([email protected]) * @version $Revision: 11247 $ */ public class DatabaseResultListener extends DatabaseUtils implements ResultListener { /** for serialization */ static final long serialVersionUID = 7388014746954652818L; /** The ResultProducer to listen to */ protected ResultProducer m_ResultProducer; /** The name of the current results table */ protected String m_ResultsTableName; /** Holds the name of the key field to cache upon, or null if no caching */ protected String m_CacheKeyName = ""; /** Stores the index of the key column holding the cache key data */ protected int m_CacheKeyIndex; /** Stores the key for which the cache is valid */ protected Object[] m_CacheKey; /** Stores the cached values */ protected ArrayList m_Cache = new ArrayList(); /** * Returns a string describing this result listener * * @return a description of the result listener suitable for displaying in the * explorer/experimenter gui */ public String globalInfo() { return "Takes results from a result producer and sends them to a " + "database."; } /** * Sets up the database drivers * * @throws Exception if an error occurs */ public DatabaseResultListener() throws Exception { super(); } /** * Prepare for the results to be received. * * @param rp the ResultProducer that will generate the results * @throws Exception if an error occurs during preprocessing. */ @Override public void preProcess(ResultProducer rp) throws Exception { m_ResultProducer = rp; // Connect to the database and find out what table corresponds to this // ResultProducer updateResultsTableName(m_ResultProducer); } /** * Perform any postprocessing. When this method is called, it indicates that * no more results will be sent that need to be grouped together in any way. * * @param rp the ResultProducer that generated the results * @throws Exception if an error occurs */ @Override public void postProcess(ResultProducer rp) throws Exception { if (m_ResultProducer != rp) { throw new Error("Unrecognized ResultProducer calling postProcess!!"); } disconnectFromDatabase(); } /** * Determines if there are any constraints (imposed by the destination) on any * additional measures produced by resultProducers. Null should be returned if * there are NO constraints, otherwise a list of column names should be * returned as an array of Strings. In the case of DatabaseResultListener, the * structure of an existing database will impose constraints. * * @param rp the ResultProducer to which the constraints will apply * @return an array of column names to which resutltProducer's results will be * restricted. * @throws Exception if an error occurs. */ @Override public String[] determineColumnConstraints(ResultProducer rp) throws Exception { ArrayList cNames = new ArrayList(); updateResultsTableName(rp); DatabaseMetaData dbmd = m_Connection.getMetaData(); ResultSet rs; // gets a result set where each row is info on a column if (m_checkForUpperCaseNames) { rs = dbmd.getColumns(null, null, m_ResultsTableName.toUpperCase(), null); } else { rs = dbmd.getColumns(null, null, m_ResultsTableName, null); } boolean tableExists = false; int numColumns = 0; while (rs.next()) { tableExists = true; // column four contains the column name String name = rs.getString(4); if (name.toLowerCase().startsWith("measure")) { numColumns++; cNames.add(name); } } // no constraints on any additional measures if the table does not exist if (!tableExists) { return null; } // a zero element array indicates maximum constraint String[] columnNames = new String[numColumns]; for (int i = 0; i < numColumns; i++) { columnNames[i] = (cNames.get(i)); } return columnNames; } /** * Submit the result to the appropriate table of the database * * @param rp the ResultProducer that generated the result * @param key The key for the results. * @param result The actual results. * @throws Exception if the result couldn't be sent to the database */ @Override public void acceptResult(ResultProducer rp, Object[] key, Object[] result) throws Exception { if (m_ResultProducer != rp) { throw new Error("Unrecognized ResultProducer calling acceptResult!!"); } // null result could occur from a chain of doRunKeys calls if (result != null) { putResultInTable(m_ResultsTableName, rp, key, result); } } /** * Always says a result is required. If this is the first call, prints out the * header for the Database output. * * @param rp the ResultProducer wanting to generate the result * @param key The key for which a result may be needed. * @return true if the result should be calculated. * @throws Exception if the database couldn't be queried */ @Override public boolean isResultRequired(ResultProducer rp, Object[] key) throws Exception { if (m_ResultProducer != rp) { throw new Error("Unrecognized ResultProducer calling isResultRequired!"); } if (m_Debug) { System.err.print("Is result required..."); for (Object element : key) { System.err.print(" " + element); } System.err.flush(); } boolean retval = false; // Check the key cache first if (!m_CacheKeyName.equals("")) { if (!isCacheValid(key)) { loadCache(rp, key); } retval = !isKeyInCache(rp, key); } else { // Ask whether the results are needed retval = !isKeyInTable(m_ResultsTableName, rp, key); } if (m_Debug) { System.err.println(" ..." + (retval ? "required" : "not required") + (m_CacheKeyName.equals("") ? "" : " (cache)")); System.err.flush(); } return retval; } /** * Determines the table name that results will be inserted into. If required: * a connection will be opened, an experiment index table created, and the * results table created. * * @param rp the ResultProducer * @throws Exception if an error occurs */ protected void updateResultsTableName(ResultProducer rp) throws Exception { if (!isConnected()) { connectToDatabase(); } if (!experimentIndexExists()) { createExperimentIndex(); } String tableName = getResultsTableName(rp); if (tableName == null) { tableName = createExperimentIndexEntry(rp); } if (!tableExists(tableName)) { createResultsTable(rp, tableName); } m_ResultsTableName = tableName; } /** * Returns the tip text for this property * * @return tip text for this property suitable for displaying in the * explorer/experimenter gui */ public String cacheKeyNameTipText() { return "Set the name of the key field by which to cache."; } /** * Get the value of CacheKeyName. * * @return Value of CacheKeyName. */ public String getCacheKeyName() { return m_CacheKeyName; } /** * Set the value of CacheKeyName. * * @param newCacheKeyName Value to assign to CacheKeyName. */ public void setCacheKeyName(String newCacheKeyName) { m_CacheKeyName = newCacheKeyName; } /** * Checks whether the current cache contents are valid for the supplied key. * * @param key the results key * @return true if the cache contents are valid for the key given */ protected boolean isCacheValid(Object[] key) { if (m_CacheKey == null) { return false; } if (m_CacheKey.length != key.length) { return false; } for (int i = 0; i < key.length; i++) { if ((i != m_CacheKeyIndex) && (!m_CacheKey[i].equals(key[i]))) { return false; } } return true; } /** * Returns true if the supplied key is in the key cache (and thus we do not * need to execute a database query). * * @param rp the ResultProducer the key belongs to. * @param key the result key * @return true if the key is in the key cache * @throws Exception if an error occurs */ protected boolean isKeyInCache(ResultProducer rp, Object[] key) throws Exception { for (int i = 0; i < m_Cache.size(); i++) { if (m_Cache.get(i).equals(key[m_CacheKeyIndex])) { return true; } } return false; } /** * Executes a database query to fill the key cache * * @param rp the ResultProducer the key belongs to * @param key the key * @throws Exception if an error occurs */ protected void loadCache(ResultProducer rp, Object[] key) throws Exception { System.err.print(" (updating cache)"); System.err.flush(); m_Cache.clear(); m_CacheKey = null; String query = "SELECT Key_" + m_CacheKeyName + " FROM " + m_ResultsTableName; String[] keyNames = rp.getKeyNames(); if (keyNames.length != key.length) { throw new Exception("Key names and key values of different lengths"); } m_CacheKeyIndex = -1; for (int i = 0; i < keyNames.length; i++) { if (keyNames[i].equalsIgnoreCase(m_CacheKeyName)) { m_CacheKeyIndex = i; break; } } if (m_CacheKeyIndex == -1) { throw new Exception("No key field named " + m_CacheKeyName + " (as specified for caching)"); } boolean first = true; for (int i = 0; i < key.length; i++) { if ((key[i] != null) && (i != m_CacheKeyIndex)) { if (first) { query += " WHERE "; first = false; } else { query += " AND "; } query += "Key_" + keyNames[i] + '='; if (key[i] instanceof String) { query += "'" + DatabaseUtils.processKeyString(key[i].toString()) + "'"; } else { query += key[i].toString(); } } } ResultSet rs = select(query); while (rs.next()) { String keyVal = rs.getString(1); if (!rs.wasNull()) { m_Cache.add(keyVal); } } close(rs); m_CacheKey = key.clone(); } /** * Returns the revision string. * * @return the revision */ @Override public String getRevision() { return RevisionUtils.extract("$Revision: 11247 $"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy