// Copyright (c) 2001, 2003, Oracle Corporation.  All rights reserved.  
// File: AIDemo.java

/**
 * This sample program describes how to use the ODM Java API to build
 * an AttributeImportance (AI) model and how to use the AI model to choose a
 * important attributes from the AI model.
 * This program also demonstrate how an NB Model can be more or equally
 * accurate by using 90% of important attributes derived from the
 * AI model.
 * 
 * This program uses the "MINING_DATA_BUILD_V" dataset for building an AI model.
 * Two NB models are built subsequently; one using all attributes present
 * in the dataset and the other using the selected subset of important 
 * attributes from AI Model, and the accuracies of the two models are compared 
 * after the two models are tested using the "MINING_DATA_TEST_V" dataset.
 * The target attribute for the NB models is "AFFINITY_CARD".
 * 
 * NOTE:
 *   Before executing this program you need to provide DB URL, username 
 *   and password in login method and a valid data schema name
 *   by changing the DATA_SCHEMA_NAME constant value in the program.
 */

// Generic Java Imports
import java.io.*;
import java.util.*;
import java.sql.SQLException;

// ODM Imports
import oracle.dmt.odm.*;
import oracle.dmt.odm.data.*;
import oracle.dmt.odm.settings.function.*;
import oracle.dmt.odm.settings.algorithm.*;
import oracle.dmt.odm.task.*;
import oracle.dmt.odm.model.*;
import oracle.dmt.odm.result.*;

public class AIDemo extends Object
{
  private static DataMiningServer m_dms = null;
  private static oracle.dmt.odm.Connection m_dmsConn = null;
  private static final String DATA_SCHEMA_NAME = "schema name";
  
  public static void main( String args[] ) { 
    try { 
      //1. Login to the Data Mining Server
      //Create a DMS object
          m_dms = new DataMiningServer(
            "put DB URL here", //JDBC URL jdbc:oracle:thin:@<Host name>:<Port>:<SID>
            "user name", //User Name
            "password" //Password 
          ); 

      //Login to the DMS and create a DMS Connection
      m_dmsConn = m_dms.login();
      //Remove the objects to avoid name conflicts
      cleanup();
      //2. Build an AI model
      buildAIModel();
      //3. Get the top 90% important attributes from the AI Model      
      String[] impAttrs = AttributeImportanceModel.getAttributesByPercentage(
                      m_dmsConn, "AIDemo_Model", 0.9f, true );
      //4. Compare an NB Model built using all attributes available in
      // the input dataset with the NB Model built using 90% important
      // attributes
      compareNBModels(impAttrs);
    }
    catch(Exception anyExp) {
      anyExp.printStackTrace(System.out);
    } finally {
      try {
      //6. Logout from the Data Mining Server
        m_dms.logout(m_dmsConn);
      } catch(Exception anyExp1) { }//Ignore
    }
  }

  /**
   * Build operation is performed by a task that requires the location of
   * the dataset, a mining function settings and the model name.
   * In this example, an AttributeImportance (AI) model "AIDemo_Model" is built
   * using the dataset "MINING_DATA_BUILD_V" by the default AI algorithm.
   * This model will be used to obtain a subset of attributes based on their
   * importance values.
   */
  public static void buildAIModel()
  throws ODMException, SQLException, IOException 
  {
    //1. Create PhysicalDataSpecification for build
    LocationAccessData buildDataLocn = new LocationAccessData( 
                  "MINING_DATA_BUILD_V", //Data Table Name
                  DATA_SCHEMA_NAME  //Schema Name
                  );
    NonTransactionalDataSpecification buildPDS = 
      new NonTransactionalDataSpecification(buildDataLocn);
    //2. Create & Store Mining Function Settings
    AttributeImportanceFunctionSettings aimfs =
          AttributeImportanceFunctionSettings.create(
                  m_dmsConn,       //DMS Connection
                  null,            //default AI algorithm settings
                  buildPDS,             //Build data specification
                  "AFFINITY_CARD", //Target column
                  AttributeType.categorical, //Default attribute type
                  DataPreparationStatus.unprepared //Default preparation status
          );
    //3. Prevent private information (customer identifier) from being used
    //   in model building
    aimfs.adjustAttributeUsage(
                  new String[] {"CUST_ID"}, AttributeUsage.inactive);
    aimfs.store(m_dmsConn, "AIDemo_MFS");
    //4. Create a task to build an AI model
    MiningBuildTask aiBuildTask = new MiningBuildTask(
                  buildPDS,                  //Build data specification
                  "AIDemo_MFS",   //Mining function settings name
                  "AIDemo_Model"        //Mining model name
                  );
    //5. Store and execute the task
    executeTask(aiBuildTask, "AIDemo_BuildTask");
  }

  /**
   * This method stores the given task with the specified name in the DMS 
   * and submits the task for asynchronous execution in the DMS. After 
   * completing the task successfully it returns true. If there is a task 
   * failure, then it prints error description and returns false.
   * 
   * @param taskObj task object
   * @param taskName name of the task
   * 
   * @return boolean returns true when the task is successful
   */
  public static boolean executeTask(MiningTask taskObj, String taskName)
    throws ODMException, SQLException
  {
    boolean isTaskSuccess = false;
    taskObj.store(m_dmsConn, taskName); //Store the task
    taskObj.execute(m_dmsConn); //Submit the task for asynchronous execution
    System.out.print(taskName + " is started, please wait. ");
    //Wait for completion of the task
    MiningTaskStatus taskStatus = taskObj.waitForCompletion(m_dmsConn);
    //Check the status of the task after completion
    isTaskSuccess = taskStatus.getTaskState().equals(MiningTaskState.success);
    if( isTaskSuccess ) {
      //Task completed successfully
      System.out.println("It completed successfully.");
    } else {//Task failed
      throw new ODMException("It failed.\nFailure description: " + 
        taskStatus.getStateDescription() );
    }
    return isTaskSuccess;
  }

  public static void compareNBModels(String[] impAttrs)
  throws ODMException, SQLException, IOException 
  {
    //1. Create PhysicalDataSpecification for build
    LocationAccessData buildDataLocn = new LocationAccessData( 
                  "MINING_DATA_BUILD_V", //Data Table Name
                  DATA_SCHEMA_NAME  //Schema Name
                  );
    NonTransactionalDataSpecification buildPDS = 
      new NonTransactionalDataSpecification(buildDataLocn);
    //2. Create classification Mining Function Settings
    NaiveBayesSettings nbAlgo = new NaiveBayesSettings(0.01f, 0.01f);
    ClassificationFunctionSettings clmfs =
          ClassificationFunctionSettings.create(
                  m_dmsConn,       //DMS Connection
                  nbAlgo,          //NB algorithm settings
                  buildPDS,        //Build data specification
                  "AFFINITY_CARD", //Target column
                  AttributeType.categorical, //Default attribute type
                  DataPreparationStatus.unprepared //Default preparation status
          );
    //3. Prevent private information (customer identifier) from being used
    //   in model building
    clmfs.adjustAttributeUsage(
                  new String[] {"CUST_ID"}, AttributeUsage.inactive);
    //4. Store function settings which defines all the attributes as active, 
    //   except "CUST_ID" attribute to build NB model
    clmfs.store( m_dmsConn, "AIDemo_NBAll_MFS");
    //5. Modify the function settings to use only important attributes 
    //  as active attributes
    clmfs.adjustAttributeUsage(impAttrs, UsageAdjustment.activateOnly);
    //6. Store function settings which uses only important attributes as
    //   active attributes to build NB Model
    clmfs.store( m_dmsConn, "AIDemo_NBImp_MFS");
    //7. Build an NB Model using "AIDemo_NBAll_MFS" settings
    MiningBuildTask nbAllBuildTask = new MiningBuildTask(
                  buildPDS, //Build data specification
                  "AIDemo_NBAll_MFS", //Mining function settings name
                  "AIDemo_NBAll_Model" //Mining model name
                  );
    executeTask(nbAllBuildTask, "AIDemo_NBAll_BuildTask");
    //8. Build an NB Model using "AIDemo_NBImp_MFS" settings
    MiningBuildTask nbImpBuildTask = new MiningBuildTask(
                  buildPDS,              //Build data specification
                  "AIDemo_NBImp_MFS", //Mining function settings name
                  "AIDemo_NBImp_Model" //Mining model name
                  );
    executeTask(nbImpBuildTask, "AIDemo_NBImp_BuildTask");
    //9. Compute accuracy of the NB model built using all attributes
    LocationAccessData testDataLocn = new LocationAccessData( 
                  "MINING_DATA_TEST_V", //Data Table Name
                  DATA_SCHEMA_NAME  //Schema Name
                  );
    NonTransactionalDataSpecification testPDS = 
      new NonTransactionalDataSpecification(buildDataLocn);
    ClassificationTestTask nbAllTestTask = new ClassificationTestTask(
                   testPDS,           //test data specification
                   "AIDemo_NBAll_Model",     //Name of the model to be tested
                   "AIDemo_NBAll_TestResults" ); //Test results name
    executeTask(nbAllTestTask, "AIDemo_NBAll_TestTask");
    //10. Compute accuracy of the NB model built using important attributes
    ClassificationTestTask nbImpTestTask = new ClassificationTestTask(
                   testPDS,           //test data specification
                   "AIDemo_NBImp_Model", //Name of the model to be tested
                   "AIDemo_NBImp_TestResults" ); //Test results name
    executeTask(nbImpTestTask, "AIDemo_NBImp_TestTask");
    //11. Compare accuracies      
    ClassificationTestResult nbAllTestResult = 
        ClassificationTestResult.restore(m_dmsConn, "AIDemo_NBAll_TestResults");
    ClassificationTestResult nbImpTestResult = 
        ClassificationTestResult.restore(m_dmsConn, "AIDemo_NBImp_TestResults");
    System.out.println("Accuracy for the NB Model built using all attributes: " 
      + nbAllTestResult.getAccuracy());
    System.out.println(
      "Accuracy for the NB Model built using 90% important attributes: " 
      + nbImpTestResult.getAccuracy());
  }    


  /**
   * Cleanup the previously created objects if any. 
   */
  private static void cleanup() throws ODMException, SQLException
  {
    //Remove the function settings
    try {
      AttributeImportanceFunctionSettings.remove(m_dmsConn, "AIDemo_MFS");
    }catch(Exception anyExp1) { }//Ignore
    try {
      ClassificationFunctionSettings.remove(m_dmsConn, "AIDemo_NBAll_MFS");
    }catch(Exception anyExp1) { }//Ignore
    try {
      ClassificationFunctionSettings.remove(m_dmsConn, "AIDemo_NBImp_MFS");
    }catch(Exception anyExp1) { }//Ignore
    //Remove the build tasks
    try {
      MiningBuildTask.remove(m_dmsConn, "AIDemo_BuildTask");
    }catch(Exception anyExp1) { }//Ignore
    try {
      MiningBuildTask.remove(m_dmsConn, "AIDemo_NBAll_BuildTask");
    }catch(Exception anyExp1) { }//Ignore
    try {
      MiningBuildTask.remove(m_dmsConn, "AIDemo_NBImp_BuildTask");
    }catch(Exception anyExp1) { }//Ignore
    //Remove the models
    try {
      MiningModel.remove(m_dmsConn, "AIDemo_Model");
    }catch(Exception anyExp1) { }//Ignore
    try {
      MiningModel.remove(m_dmsConn, "AIDemo_NBAll_Model");
    }catch(Exception anyExp1) { }//Ignore
    try {
      MiningModel.remove(m_dmsConn, "AIDemo_NBImp_Model");
    }catch(Exception anyExp3) { }//Ignore
    //Remove the test tasks
    try {
      ClassificationTestTask.remove(m_dmsConn, "AIDemo_NBAll_TestTask");
    }catch(Exception anyExp1) { }//Ignore
    try {
      ClassificationTestTask.remove(m_dmsConn, "AIDemo_NBImp_TestTask");
    }catch(Exception anyExp4) { }//Ignore
    //Remove the test results
    try {
      ClassificationTestResult.remove(m_dmsConn, "AIDemo_NBAll_TestResults");
    }catch(Exception anyExp1) { }//Ignore
    try {
      ClassificationTestResult.remove(m_dmsConn, "AIDemo_NBImp_TestResults");
    }catch(Exception anyExp5) { }//Ignore
  }
}
