InstanceQuery.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 13k
Category:

Windows Develop

Development Platform:

Java

  1. /*
  2.  *    This program is free software; you can redistribute it and/or modify
  3.  *    it under the terms of the GNU General Public License as published by
  4.  *    the Free Software Foundation; either version 2 of the License, or
  5.  *    (at your option) any later version.
  6.  *
  7.  *    This program is distributed in the hope that it will be useful,
  8.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *    GNU General Public License for more details.
  11.  *
  12.  *    You should have received a copy of the GNU General Public License
  13.  *    along with this program; if not, write to the Free Software
  14.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  */
  16. /*
  17.  *    InstanceQuery.java
  18.  *    Copyright (C) 1999 Len Trigg
  19.  *
  20.  */
  21. package weka.experiment;
  22. import java.sql.*;
  23. import java.net.InetAddress;
  24. import java.util.*;
  25. import java.math.*;
  26. import java.io.*;
  27. import weka.core.*;
  28. /**
  29.  * Convert the results of a database query into instances. The jdbc
  30.  * driver and database to be used default to "jdbc.idbDriver" and
  31.  * "jdbc:idb=experiments.prp". These may be changed by creating
  32.  * a java properties file called .weka.experimentrc in user.home. eg:<p>
  33.  *
  34.  * <code><pre>
  35.  * jdbcDriver=jdbc.idbDriver
  36.  * jdbcURL=jdbc:idb=experiments.prp
  37.  * </pre></code><p>
  38.  *
  39.  * Command line use just outputs the instances to System.out.
  40.  *
  41.  * @author Len Trigg (trigg@cs.waikato.ac.nz)
  42.  * @version $Revision: 1.11 $
  43.  */
  44. public class InstanceQuery extends DatabaseUtils implements OptionHandler {
  45.   /** Determines whether sparse data is created */
  46.   boolean m_CreateSparseData = false;
  47.   
  48.   /** Query to execute */
  49.   String m_Query = "SELECT * from ?";
  50.   /**
  51.    * Sets up the database drivers
  52.    *
  53.    * @exception Exception if an error occurs
  54.    */
  55.   public InstanceQuery() throws Exception {
  56.     super();
  57.   }
  58.   /**
  59.    * Returns an enumeration describing the available options <p>
  60.    *
  61.    */
  62.    public Enumeration listOptions () {
  63.      Vector newVector = new Vector(2);
  64.      newVector.addElement(new Option("tSQL query to execute.",
  65.      "Q",1,"-Q <query>"));
  66.      newVector.addElement(new Option("tReturn sparse rather than normal "
  67.     +"instances." 
  68.     , "S", 0, "-S"));
  69.      return  newVector.elements();
  70.    }
  71.   /**
  72.    * Parses a given list of options.
  73.    *
  74.    * Valid options are:<p>
  75.    * 
  76.    * -S <br>
  77.    * Return a set of sparse instances rather than normal instances.<p>
  78.    *
  79.    * @param options the list of options as an array of strings
  80.    * @exception Exception if an option is not supported
  81.    */
  82.   public void setOptions (String[] options)
  83.     throws Exception
  84.   {
  85.     setSparseData(Utils.getFlag('S',options));
  86.     String optionString;
  87.     
  88.     optionString = Utils.getOption('Q',options);
  89.     if (optionString.length() != 0) {
  90.       setQuery(optionString);
  91.     } 
  92.   }
  93.   /**
  94.    * Returns the tip text for this property
  95.    * @return tip text for this property suitable for
  96.    * displaying in the explorer/experimenter gui
  97.    */
  98.   public String queryTipText() {
  99.     return "The SQL query to execute against the database.";
  100.   }
  101.   
  102.   /**
  103.    * Set the query to execute against the database
  104.    * @param q the query to execute
  105.    */
  106.   public void setQuery(String q) {
  107.     m_Query = q;
  108.   }
  109.   /**
  110.    * Get the query to execute against the database
  111.    * @return the query
  112.    */
  113.   public String getQuery() {
  114.     return m_Query;
  115.   }
  116.   /**
  117.    * Returns the tip text for this property
  118.    * @return tip text for this property suitable for
  119.    * displaying in the explorer/experimenter gui
  120.    */
  121.   public String sparseDataTipText() {
  122.     return "Encode data as sparse instances.";
  123.   }
  124.   /**
  125.    * Sets whether data should be encoded as sparse instances
  126.    * @param s true if data should be encoded as a set of sparse instances
  127.    */
  128.   public void setSparseData(boolean s) {
  129.     m_CreateSparseData = s;
  130.   }
  131.   /**
  132.    * Gets whether data is to be returned as a set of sparse instances
  133.    * @return true if data is to be encoded as sparse instances
  134.    */
  135.   public boolean getSparseData() {
  136.     return m_CreateSparseData;
  137.   }
  138.   /**
  139.    * Gets the current settings of InstanceQuery
  140.    *
  141.    * @return an array of strings suitable for passing to setOptions()
  142.    */
  143.   public String[] getOptions () {
  144.     String[] options = new String[3];
  145.     int current = 0;
  146.     options[current] = "-Q"; options[current++] = getQuery();
  147.  
  148.     if (getSparseData()) {
  149.       options[current++] = "-S";
  150.     }
  151.     while (current < options.length) {
  152.       options[current++] = "";
  153.     }
  154.     
  155.     return  options;
  156.   }
  157.   /**
  158.    * Makes a database query using the query set through the -Q option 
  159.    * to convert a table into a set of instances
  160.    *
  161.    * @return the instances contained in the result of the query
  162.    * @exception Exception if an error occurs
  163.    */
  164.   public Instances retrieveInstances() throws Exception {
  165.     return retrieveInstances(m_Query);
  166.   }
  167.   /**
  168.    * Makes a database query to convert a table into a set of instances
  169.    *
  170.    * @param query the query to convert to instances
  171.    * @return the instances contained in the result of the query
  172.    * @exception Exception if an error occurs
  173.    */
  174.   public Instances retrieveInstances(String query) throws Exception {
  175.     System.err.println("Executing query: " + query);
  176.     connectToDatabase();
  177.     if (execute(query) == false) {
  178.       throw new Exception("Query didn't produce results");
  179.     }
  180.     ResultSet rs = getResultSet();
  181.     System.err.println("Getting metadata...");
  182.     ResultSetMetaData md = rs.getMetaData();
  183.     // Determine structure of the instances
  184.     int numAttributes = md.getColumnCount();
  185.     int [] attributeTypes = new int [numAttributes];
  186.     Hashtable [] nominalIndexes = new Hashtable [numAttributes];
  187.     FastVector [] nominalStrings = new FastVector [numAttributes];
  188.     for (int i = 1; i <= numAttributes; i++) {
  189.       switch (md.getColumnType(i)) {
  190.       case Types.CHAR:
  191.       case Types.VARCHAR:
  192.       case Types.LONGVARCHAR:
  193.       case Types.BINARY:
  194.       case Types.VARBINARY:
  195.       case Types.LONGVARBINARY:
  196. //System.err.println("String --> nominal");
  197. attributeTypes[i - 1] = Attribute.NOMINAL;
  198. nominalIndexes[i - 1] = new Hashtable();
  199. nominalStrings[i - 1] = new FastVector();
  200. break;
  201.       case Types.BIT:
  202. ////System.err.println("boolean --> nominal");
  203. attributeTypes[i - 1] = Attribute.NOMINAL;
  204. nominalIndexes[i - 1] = new Hashtable();
  205. nominalIndexes[i - 1].put("false", new Double(0));
  206. nominalIndexes[i - 1].put("true", new Double(1));
  207. nominalStrings[i - 1] = new FastVector();
  208. nominalStrings[i - 1].addElement("false");
  209. nominalStrings[i - 1].addElement("true");
  210. break;
  211.       case Types.NUMERIC:
  212.       case Types.DECIMAL:
  213. //System.err.println("BigDecimal --> numeric");
  214. attributeTypes[i - 1] = Attribute.NUMERIC;
  215. break;
  216.       case Types.TINYINT:
  217. //System.err.println("byte --> numeric");
  218. attributeTypes[i - 1] = Attribute.NUMERIC;
  219. break;
  220.       case Types.SMALLINT:
  221. //System.err.println("short --> numeric");
  222. attributeTypes[i - 1] = Attribute.NUMERIC;
  223. break;
  224.       case Types.INTEGER:
  225. //System.err.println("int --> numeric");
  226. attributeTypes[i - 1] = Attribute.NUMERIC;
  227. break;
  228.       case Types.BIGINT:
  229. //System.err.println("long --> numeric");
  230. attributeTypes[i - 1] = Attribute.NUMERIC;
  231. break;
  232.       case Types.REAL:
  233. //System.err.println("float --> numeric");
  234. attributeTypes[i - 1] = Attribute.NUMERIC;
  235. break;
  236.       case Types.FLOAT:
  237.       case Types.DOUBLE:
  238. //System.err.println("double --> numeric");
  239. attributeTypes[i - 1] = Attribute.NUMERIC;
  240. break;
  241. /*case Types.BINARY:
  242.       case Types.VARBINARY:
  243.       case Types.LONGVARBINARY:
  244. //System.err.println("byte[] --> unsupported");
  245. attributeTypes[i - 1] = Attribute.STRING;
  246. break; */
  247.       case Types.DATE:
  248. //System.err.println("Date --> unsupported");
  249. attributeTypes[i - 1] = Attribute.STRING;
  250. break;
  251.       case Types.TIME:
  252. //System.err.println("Time --> unsupported");
  253. attributeTypes[i - 1] = Attribute.STRING;
  254. break;
  255.       case Types.TIMESTAMP:
  256. //System.err.println("Time --> unsupported");
  257. attributeTypes[i - 1] = Attribute.STRING;
  258. break;
  259.       default:
  260. //System.err.println("Unknown column type");
  261. attributeTypes[i - 1] = Attribute.STRING;
  262.       }
  263.     }
  264.     // Step through the tuples
  265.     System.err.println("Creating instances...");
  266.     FastVector instances = new FastVector();
  267.     int rowCount = 0;
  268.     while(rs.next()) {
  269.       if (rowCount % 100 == 0) {
  270. System.err.print("read " + rowCount + " instances r");
  271. System.err.flush();
  272.       }
  273.       double[] vals = new double[numAttributes];
  274.       for(int i = 1; i <= numAttributes; i++) {
  275. switch (md.getColumnType(i)) {
  276. case Types.CHAR:
  277. case Types.VARCHAR:
  278. case Types.LONGVARCHAR:
  279. case Types.BINARY:
  280. case Types.VARBINARY:
  281. case Types.LONGVARBINARY:
  282.   String str = rs.getString(i);
  283.   
  284.   if (rs.wasNull()) {
  285.     vals[i - 1] = Instance.missingValue();
  286.   } else {
  287.     Double index = (Double)nominalIndexes[i - 1].get(str);
  288.     if (index == null) {
  289.       index = new Double(nominalStrings[i - 1].size());
  290.       nominalIndexes[i - 1].put(str, index);
  291.       nominalStrings[i - 1].addElement(str);
  292.     }
  293.     vals[i - 1] = index.doubleValue();
  294.   }
  295.   break;
  296. case Types.BIT:
  297.   boolean boo = rs.getBoolean(i);
  298.   if (rs.wasNull()) {
  299.     vals[i - 1] = Instance.missingValue();
  300.   } else {
  301.     vals[i - 1] = (boo ? 1.0 : 0.0);
  302.   }
  303.   break;
  304. case Types.NUMERIC:
  305. case Types.DECIMAL:
  306.   //   BigDecimal bd = rs.getBigDecimal(i, 4); 
  307.   double dd = rs.getDouble(i);
  308.   // Use the column precision instead of 4?
  309.   if (rs.wasNull()) {
  310.     vals[i - 1] = Instance.missingValue();
  311.   } else {
  312.     //     newInst.setValue(i - 1, bd.doubleValue());
  313.     vals[i - 1] =  dd;
  314.   }
  315.   break;
  316. case Types.TINYINT:
  317.   byte by = rs.getByte(i);
  318.   if (rs.wasNull()) {
  319.     vals[i - 1] = Instance.missingValue();
  320.   } else {
  321.     vals[i - 1] = (double)by;
  322.   }
  323.   break;
  324. case Types.SMALLINT:
  325.   short sh = rs.getByte(i);
  326.   if (rs.wasNull()) {
  327.     vals[i - 1] = Instance.missingValue();
  328.   } else {
  329.     vals[i - 1] = (double)sh;
  330.   }
  331.   break;
  332. case Types.INTEGER:
  333.   int in = rs.getInt(i);
  334.   if (rs.wasNull()) {
  335.     vals[i - 1] = Instance.missingValue();
  336.   } else {
  337.     vals[i - 1] = (double)in;
  338.   }
  339.   break;
  340. case Types.BIGINT:
  341.   long lo = rs.getLong(i);
  342.   if (rs.wasNull()) {
  343.     vals[i - 1] = Instance.missingValue();
  344.   } else {
  345.     vals[i - 1] = (double)lo;
  346.   }
  347.   break;
  348. case Types.REAL:
  349.   float fl = rs.getFloat(i);
  350.   if (rs.wasNull()) {
  351.     vals[i - 1] = Instance.missingValue();
  352.   } else {
  353.     vals[i - 1] = (double)fl;
  354.   }
  355.   break;
  356. case Types.FLOAT:
  357. case Types.DOUBLE:
  358.   double dou = rs.getDouble(i);
  359.   if (rs.wasNull()) {
  360.     vals[i - 1] = Instance.missingValue();
  361.   } else {
  362.     vals[i - 1] = (double)dou;
  363.   }
  364.   break;
  365.   /*case Types.BINARY:
  366. case Types.VARBINARY:
  367. case Types.LONGVARBINARY: */
  368. case Types.DATE:
  369. case Types.TIME:
  370. case Types.TIMESTAMP:
  371. default:
  372.   vals[i - 1] = Instance.missingValue();
  373. }
  374.       }
  375.       Instance newInst;
  376.       if (m_CreateSparseData) {
  377. newInst = new SparseInstance(1.0, vals);
  378.       } else {
  379. newInst = new Instance(1.0, vals);
  380.       }
  381.       instances.addElement(newInst);
  382.       rowCount++;
  383.     }
  384.     //disconnectFromDatabase();  (perhaps other queries might be made)
  385.     
  386.     // Create the header and add the instances to the dataset
  387.     System.err.println("Creating header...");
  388.     FastVector attribInfo = new FastVector();
  389.     for (int i = 0; i < numAttributes; i++) {
  390.       String attribName = md.getColumnName(i + 1);
  391.       switch (attributeTypes[i]) {
  392.       case Attribute.NOMINAL:
  393. attribInfo.addElement(new Attribute(attribName, nominalStrings[i]));
  394. break;
  395.       case Attribute.NUMERIC:
  396. attribInfo.addElement(new Attribute(attribName));
  397. break;
  398.       case Attribute.STRING:
  399. attribInfo.addElement(new Attribute(attribName, null));
  400. break;
  401.       default:
  402. throw new Exception("Unknown attribute type");
  403.       }
  404.     }
  405.     Instances result = new Instances("QueryResult", attribInfo, 
  406.      instances.size());
  407.     for (int i = 0; i < instances.size(); i++) {
  408.       result.add((Instance)instances.elementAt(i));
  409.     }
  410.     rs.close();
  411.     return result;
  412.   }
  413.   /**
  414.    * Test the class from the command line. The instance
  415.    * query should be specified with -Q sql_query
  416.    *
  417.    * @param args contains options for the instance query
  418.    */
  419.   public static void main(String args[]) {
  420.     try {
  421.       InstanceQuery iq = new InstanceQuery();
  422.       String query = Utils.getOption('Q', args);
  423.       if (query.length() == 0) {
  424. iq.setQuery("select * from Experiment_index");
  425.       } else {
  426. iq.setQuery(query);
  427.       }
  428.       iq.setOptions(args);
  429.       try {
  430. Utils.checkForRemainingOptions(args);
  431.       } catch (Exception e) {
  432. System.err.println("Options for weka.experiment.InstanceQuery:n");
  433. Enumeration en = iq.listOptions();
  434. while (en.hasMoreElements()) {
  435.   Option o = (Option)en.nextElement();
  436.   System.err.println(o.synopsis()+"n"+o.description());
  437. }
  438. System.exit(1);
  439.       }
  440.      
  441.       Instances aha = iq.retrieveInstances();
  442.       iq.disconnectFromDatabase();
  443.       // The dataset may be large, so to make things easier we'll
  444.       // output an instance at a time (rather than having to convert
  445.       // the entire dataset to one large string)
  446.       System.out.println(new Instances(aha, 0));
  447.       for (int i = 0; i < aha.numInstances(); i++) {
  448. System.out.println(aha.instance(i));
  449.       }
  450.     } catch(Exception e) {
  451.       e.printStackTrace();
  452.       System.err.println(e.getMessage());
  453.     }
  454.   }
  455. }