Oracle® Application Server Personalization Programmer's Guide
10g Release 2 (10.1.2) B14051-01 |
|
Previous |
Next |
The sample program for REProxyBatch
consists of a Java program and a property file. The sample program, property file, and the tables required to run it are installed when you install OracleAS Personalization.
The Java program REBatchTest.java
and the property file batchtest.txt
are in the TBS
directory on the system where you have installed OracleAS Personalization.
REBatchTest.java
REProxyBatch
allows you to execute a subset of recommendation functions in bulk. (REProxyRT
scores one user/item at a time.) REProxyBatch
reads a list of items/customers to be scored from an input table and writes the result to a new output table. This program reads its input from the property file batchtest.ini
.
The input item details (for rateItem
and crossSellForItem
) are derived from the OracleAS Personalization demo data. But in OracleAS Personalization, the model built on the same data is not guaranteed to produce the same rules each time that it is run. Therefore, it is possible that the item being rated cannot be rated with the current set of rules. The output tables will either be empty (zero rows) or will contain fewer than expected records (for example, if only some of the items are valid cross-sell candidates.).
Follow these steps to execute the sample program:
Install OracleAS Personalization.
The code and data for the sample program is installed into the following directories when you install OracleAS Personalization:
The following code is installed in ${ORACLE_HOME}/dmt/reapi/batch/
batchtest.txt
README.txt
REBatchTest.java
The following items associated with the data used by the sample program are installed in ${ORACLE_HOME}/dmt/reapi/batch/sampleData
create_batch_demo_input_tables.sql
customer_list_in.ctl
customer_list_in.txt
item_list_in.ctl
item_list_in.txt
load_batch_demo_data.sh
Run the shell script load_batch_demo_data.sh
to load the following tables:
customer_list_in
— Used for loadCustomerProfile
. (The output of loadCustomerProfile
is used by recommendTopItems
and rateItem
.)
item_list_in
— Used by crossSellForItem
.
Compile the sample code. Your CLASSPATH
variable should include the following zip/jar files:
${ORACLE_HOME}/dmt/opreapi-batch.jar
${ORACLE_HOME}/dmt/oputil.jar
It also needs to include JDBC related jar/zip files:
${ORACLE_HOME}/jdbc/lib/classes12.zip
Change the property file to point to the appropriate entities. The comments in the property file and the file README.txt
describes the exact changes that must be made.
Run REBatchTest
, with the property file name as an input parameter.
This section contains the code for the sample program and its property file.
The properties file for the sample program follows. Note that you must replace RE details and input/output table details to reflect your installation.
### ### Input file for REProxyBatch sample program ### Before Running, you will need to replace the following dummy strings with actual information: ### 1. RE* details ( Url,Username,Password) to point to the RE. ### 2. Input and Output (Result) table details for each of the calls. #A unique name for proxy ProxyName=REB_1 #Recommendation Engine details REUrl=jdbc:oracle:thin:@myDBUrl REUsername=REUser REPassword=REPassword #Input customer table location Input.Url=jdbc:oracle:thin:@myDBUrl Input.Alias=myDBAlias Input.Schema=User1 Input.Table=customer_list_in Input.Username=User1 Input.Password=Password1 #Customer profile table # This table is created in RE by loadCustomerProfile. Once created # it is used for recommendTopItems and rateItem CustProfile=MY_CUSTOMER_PROFILE # # Details for recommendTopItems # # Number of items to be recommended per customer TopN.NumberOfItems=10 #TuningSettings details #valid DataSourceTypes are ALL, DEMOGRAPHIC, PURCHASING, RATING, NAVIGATION TopN.DataSourceType=ALL #valid InterestDimension: PURCHASING, RATING, NAVIGATION TopN.InterestDimension=PURCHASING #valid PersonalizationIndex: LOW, MEDIUM, HIGH TopN.PersonalizationIndex=MEDIUM ## ProfileDataBalance needs to be specified as part of the TuningSettings object ## but its value is not used by REProxyBatch #valid ProfileDataBalance: HISTORY, CURRENT, BALANCED TopN.ProfileDataBalance=HISTORY #valid ProfileUsage:INCLUDE, EXCLUDE TopN.ProfileUsage=INCLUDE # FilteringSettings details TopN.Taxonomy=1 #Category list is a series of numbers separated by "-" TopN.CategoryList=1-2-3-4-5 #Valid CategoryMembership: ExcludeItems, ExcludeCategories, IncludeItems, IncludeCategories, # level, SubTreeItems, SubTreeCategories, AllItems, AllCategories TopN.CategoryMember=AllItems # Result table details TopNResult.Url=jdbc:oracle:thin:@myDBUrl TopNResult.Alias=myDBAlias TopNResult.Schema=User2 TopNResult.Table=TopN_RESULTS TopNResult.Username=User2 TopNResult.Password=Password2 # # Details for rateItem # #TuningSettings details RateI.ItemID=417 RateI.ItemType=MOVIE RateI.DataSourceType=RATING RateI.InterestDimension=RATING RateI.PersonalizationIndex=LOW ## ProfileDataBalance needs to be specified as part of the TuningSettings object ## but its value is not used by REProxyBatch RateI.ProfileDataBalance=HISTORY RateI.ProfileUsage=INCLUDE RateI.Taxonomy=1 # Result table details RateIResult.Url=jdbc:oracle:thin:@myDBUrl RateIResult.Alias=myDBAlias RateIResult.Schema=User3 RateIResult.Table=RATEITEM_RESULTS RateIResult.Username=User3 RateIResult.Password=Password3 # # Details for crossSellForItem # #Input items table details ItemTable.Url=jdbc:oracle:thin:@myDBUrl ItemTable.Alias=myDBAlias ItemTable.Schema=User4 ItemTable.Table=item_list_in ItemTable.Username=User4 ItemTable.Password=User4 # Number of items to be recommended per input item XSell.NumberOfItems=10 #TuningSettings details XSell.DataSourceType=NAVIGATION XSell.InterestDimension=NAVIGATION XSell.PersonalizationIndex=HIGH ## ProfileDataBalance needs to be specified as part of the TuningSettings object ## but its value is not used by REProxyBatch XSell.ProfileDataBalance=HISTORY XSell.ProfileUsage=EXCLUDE #FilteringSettings details XSell.Taxonomy=1 XSell.CategoryList=1-3-5-7-9 XSell.CategoryMember=AllItems # Result table details XSellResult.Url=jdbc:oracle:thin:@myDBUrl XSellResult.Alias=myDBAlas XSellResult.Schema=User4 XSellResult.Table=XSELL_RESULTS XSellResult.Username=User5 XSellResult.Password=Password5
The sample program follows. Note that you must replace RE details and input/output table details to reflect your installation.
// Copyright (c) 2001, 2002, Oracle Corporation. All rights reserved. import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.sql.SQLException; import java.util.Enumeration; import java.util.Properties; import java.util.StringTokenizer; import oracle.dmt.op.re.base.Enum; import oracle.dmt.op.re.base.FilteringSettings; import oracle.dmt.op.re.base.Item; import oracle.dmt.op.re.base.TuningSettings; import oracle.dmt.op.re.reapi.batch.Location; import oracle.dmt.op.re.reapi.batch.REProxyBatch; import oracle.dmt.op.re.reexception.BadDBConnectionException; import oracle.dmt.op.re.reexception.InvalidIDException; import oracle.dmt.op.re.reexception.NullParameterException; import oracle.dmt.op.re.reexception.StringTooLargeException; /** * Class REBatchTest * This class demonstrates the use of REProxyBatch API included with Oracle * Personalization. REProxyBatch allows you to execute a subset of * recommendation functions in bulk. (REProxyRT scores one user/item at a time.) * * REProxyBatch reads a list of items/customers to be scored from an input table * and writes the result to a new output table. This program reads its input * from a property file supplied as input. The tags used in the input file are * listed here as static constants in CAPITAL LETTERS. * * Before you execute the program, you must edit the property file batchtest.ini * to reflect your environment. * * @author Oracle Corporation */ public class REBatchTest { static private Properties m_Props; static private boolean m_Verbose; static private final String s_Title = "REBatchTest"; static final boolean debug = true; // These tags appear in the input property file. static String TOPN = "TopN"; static String XSELL = "XSell"; static String RITEM = "RateI"; static String DSTYPE = "DataSourceType"; static String INTDIMENSION = "InterestDimension"; static String PDBALANCE = "ProfileDataBalance"; static String PUSAGE = "ProfileUsage"; static String PINDEX = "PersonalizationIndex"; static String NUMOFITEMS = "NumberOfItems"; static String PROXYNAME = "ProxyName"; static String REURL = "REUrl"; static String REUSERNAME = "REUsername"; static String REPASSWORD = "REPassword"; static String URL = "Url"; static String ALIAS = "Alias"; static String USNAME = "Username"; static String PSWORD = "Password"; static String SCHEMA = "Schema"; static String TABLE = "Table"; static String INPUT = "Input"; static String CUSTPROFILE = "CustProfile"; static String ITEMID = "ItemID"; static String ITEMTYPE = "ItemType"; static String RESULT = "Result"; static String TAXONOMY = "Taxonomy"; static String ITEMTAB = "ItemTable"; static String CATEGORYS = "CategoryList"; static String CATNODE = "CategoryMember"; static String DOT = "."; // These variables are initialized from the property file. static private String m_proxyName; // Name of the REProxyBatch instance // Recommendation Engine Details static private String m_reUrl; static private String m_reUserName; static private String m_rePassword; // Location of the customer table; the customer table must be created before // this program can be run. // Refer to the REProxyBatch document for the expected schema. static private Location m_inCustTable; // Location of the items table; the itemstable must be created before this // program can be run. // Refer to the REProxyBatch document for the expected schema. static private Location m_inItemTable; // Name of the customer profile table created in RE after loadCustomerProfile // is invoked. static private String m_custProfile; /** * main Entry point * @param args **/ public static void main(String[] args) { long lStart; long lTotal = 0; REProxyBatch proxy; // Name of the property file should be passed as an input. if (args.length < 1) { System.out.println("Usage: REBatchTest FullpathToPropfile"); System.exit(-1); } // Initialize class variables using the property file. try { new REBatchTest(args[0]); } catch (Exception ioe) { System.out.println("Error in main(): " + ioe.getMessage()); ioe.printStackTrace(); System.exit(-1); } // Start a timer. lStart = System.currentTimeMillis(); try { // Initialize a REProxyBatch object proxy = new REProxyBatch(m_proxyName, m_reUrl, m_reUserName, m_rePassword); // Invoke loadCustomerProfiles. System.out.println("Loading customer profile."); proxy.loadCustomerProfiles( m_inCustTable, // Name of the input customer IDs table m_custProfile); // Name of the profile table from loadCustomerProfiles System.out.println("Completed loading customer profile, in the table: " + m_custProfile + " in current RE schema."); // Initialize inputs needed for recommendTopItems // Number of items to recommend (per customer) int nRec = getNumOfItems(TOPN); // Initialize TuningSettings object from the property file TuningSettings tuningT = getTuning(TOPN); // Initialize FilteringSettings object from the property file FilteringSettings filterT = getFilter(TOPN); // Location of the result table Location resLocT = getLoc(addStr(TOPN, RESULT)); System.out.println("Recommending top items. Customer profile table name:" + m_custProfile ); // Invoke recommendTopItems proxy.recommendTopItems( m_custProfile, // Customer profile table name, from loadCustomerProfiles nRec, // Number of recommendations per customer. tuningT, // TunningSettings to be used for recommendations filterT, // FilteringSettings to be used for recommendations resLocT); // Location of the result table System.out.println("Completed recommendTopItems."); System.out.println("Result table details: Schema: " + resLocT.getSchemaName() + ", Table Name: " + resLocT.getTableName() + ", Database: " + resLocT.getDBAlias()); // Initialize inputs needed for rateItem // Read the item to be rated. This single item is rated for all the // customers in the customer profiles table. Item item = getItem(RITEM); // Taxonomy to be used for rating int nTaxID = Integer.parseInt(m_Props.getProperty(addStr(RITEM, DOT, TAXONOMY))); // Initialize TuningSettings object from the property file TuningSettings tuningR = getTuning(RITEM); // Location of the result table, Location resLocR = getLoc(addStr(RITEM, RESULT)); System.out.println("Rating item."); System.out.println("Rating item: " + item.getID() + "," + item.getType() + ". Customer profile table name:" + m_custProfile ); // Invoke rateItem proxy.rateItem( m_custProfile, // Customer profile table name, from loadCustomerProfiles item, // Item to be rated nTaxID, // Taxonomy to be used for rating tuningR, // TunningSettings to be used for rating resLocR); // Location of the result table System.out.println("Completed rateItem."); System.out.println("Result table details: Schema: " + resLocR.getSchemaName() + ", Table Name: " + resLocR.getTableName() + ", Database: " + resLocR.getDBAlias()); // Invoke purgeCustomerProfiles // Cross sell is an item based recommendation call. Hence it does not need // the loaded customer profile table. System.out.println("Purging customer profile: " + m_custProfile + " from current RE."); proxy.purgeCustomerProfiles(m_custProfile); // crossSellForItem // Initialize inputs needed for rateItem // Number of cross sell items to be recommended (per input item) nRec = getNumOfItems(XSELL); // Initialize TuningSettings object from the property file TuningSettings tuningX = getTuning(XSELL); // Initialize FilteringSettings object from the property file FilteringSettings filterX = getFilter(XSELL); // Location of the result table Location resLocX = getLoc(addStr(XSELL, RESULT)); System.out.println("Recommending cross sell for item. Input table " + "details: Schema: " + m_inItemTable.getSchemaName() + ", Table Name: " + m_inItemTable.getTableName() + ", Database: " + m_inItemTable.getDBAlias()); // Invoke crossSellForItem proxy.crossSellForItem( m_inItemTable, // Name of the input items table created by the end user nRec, // Number of cross sell items to be recommended per input item tuningX, // Tunning settings to be used for recommendations filterX, // Filtering settings to be used for recommendations resLocX); // Location of the result object System.out.println("Completed crossSellForItem."); System.out.println("Result table details: Schema: " + resLocX.getSchemaName() + ", Table Name: " + resLocX.getTableName() + ", Database: " + resLocX.getDBAlias()); // Destroy the proxy object (to free up the database connections). System.out.println("Completed REProxyBatch operations. " + "Destroying the proxy."); proxy.destroy(); proxy = null; } catch (NullParameterException npe) { System.out.println(npe.getMessage()); npe.printStackTrace(); } catch (BadDBConnectionException bde) { System.out.println(bde.getMessage()); bde.printStackTrace(); } catch (SQLException se) { System.out.println(se.getMessage()); se.printStackTrace(); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } /** * Constructor * Read the property file. */ public REBatchTest(String sProp) throws FileNotFoundException, IOException, StringTooLargeException { getConfig(sProp); } /** ** All the remaining code in this file deals with reading different values ** from the property file and initializing class variables. **/ /* * A helper function returning appended string */ static private String addStr(String s1, String s2) { StringBuffer sb = new StringBuffer(s1); sb.append(s2); return (sb.toString()); } /* * A helper function returning appended string */ static private String addStr(String s1, String s2, String s3) { StringBuffer sb = new StringBuffer(s1); sb.append(s2).append(s3); return (sb.toString()); } /* ** Read recommendation engine details from the property file. ** */ static private void getConfig(String propFile) throws FileNotFoundException, SecurityException, IOException, StringTooLargeException { FileInputStream is = new FileInputStream(propFile); String RE = "RE"; try { m_Props = new Properties(); m_Props.load(is); // RE achema access info m_proxyName = m_Props.getProperty(PROXYNAME); // Recommendation Engine database details m_reUrl = m_Props.getProperty(addStr(RE, URL)); m_reUserName = m_Props.getProperty(addStr(RE, USNAME)); m_rePassword = m_Props.getProperty(addStr(RE, PSWORD)); // Input customer table m_inCustTable = getLoc(INPUT); // Input items table m_inItemTable = getLoc(ITEMTAB); // Customer profile table name m_custProfile = m_Props.getProperty(CUSTPROFILE); } catch (SecurityException se) { System.err.println("Can't read the property file: " + propFile + "!"); m_Props = null; } } /* ** Read number of items from the property file. ** */ static private int getNumOfItems(String sPrix) { return (Integer.parseInt(m_Props.getProperty(addStr(sPrix, DOT, NUMOFITEMS)))); } /* ** Read location object from the property file. ** */ static private Location getLoc(String sPrix)throws StringTooLargeException{ String sUrl = null; String sAlias = null; String sTable = null; String sSchema = null; String sPsword = null; String sUsname = null; Enumeration propNames = m_Props.propertyNames(); boolean bFound = false; while (propNames.hasMoreElements()) { String name = (String)propNames.nextElement(); if (name.startsWith(sPrix)) { // Url if (name.endsWith(URL)) { sUrl = m_Props.getProperty(name); bFound = true; } // Alias if (name.endsWith(ALIAS)) sAlias = m_Props.getProperty(name); // Schema if (name.endsWith(SCHEMA)) sSchema = m_Props.getProperty(name); // Table if (name.endsWith(TABLE)) sTable = m_Props.getProperty(name); // Username if (name.endsWith(USNAME)) sUsname = m_Props.getProperty(name); // Password if (name.endsWith(PSWORD)) sPsword = m_Props.getProperty(name); } } return (bFound ? new Location(sAlias, sUrl, sSchema, sTable, sUsname, sPsword) : null); } /* ** Read item details from the property file. ** */ static private Item getItem(String sPrix) throws StringTooLargeException, InvalidIDException, NullParameterException{ String sType = null; long lID = 0; Enumeration propNames = m_Props.propertyNames(); boolean bFound = false; while (propNames.hasMoreElements()) { String name = (String)propNames.nextElement(); if (name.startsWith(sPrix)) { // ID if (name.endsWith(ITEMID)) { lID = Long.parseLong(m_Props.getProperty(name)); bFound = true; } // Type if (name.endsWith(ITEMTYPE)) sType = m_Props.getProperty(name); } } return (bFound ? new Item(sType, lID) : null); } /* ** Read tuning settings from the property file. ** */ static private TuningSettings getTuning(String sPrix) throws NullParameterException { Enumeration propNames = m_Props.propertyNames(); Enum.DataSourceType dsType = null; Enum.InterestDimensionType iDimension = null; Enum.PersonalizationIndexType pIndex = null; Enum.ProfileDataBalanceType pdBalance = null; Enum.ProfileUsageType pUsage = null; while (propNames.hasMoreElements()) { String name = (String)propNames.nextElement(); if (name.startsWith(sPrix)) { // datasource type if (name.endsWith(DSTYPE)) { String sDsType = m_Props.getProperty(name); dsType = Enum.DataSourceType.getType(sDsType); } // interest dimension if (name.endsWith(INTDIMENSION)) { String sIntDim = m_Props.getProperty(name); iDimension = Enum.InterestDimensionType.getType(sIntDim); } // personalization index if (name.endsWith(PINDEX)) { String spIndex = m_Props.getProperty(name); pIndex = Enum.PersonalizationIndexType.getType(spIndex); } // profiledata balance if (name.endsWith(PDBALANCE)) { String sPdBalans = m_Props.getProperty(name); pdBalance = Enum.ProfileDataBalanceType.getType(sPdBalans); } // profile usage if (name.endsWith(PUSAGE)) { String spUse = m_Props.getProperty(name); pUsage = Enum.ProfileUsageType.getType(spUse); } } } return (new TuningSettings(dsType, iDimension, pIndex, pdBalance, pUsage)); } /* ** Read list of categories from the property file. ** */ static private long [] getCatList(String str) { StringTokenizer stz = new StringTokenizer(str, "-"); int nE = stz.countTokens(); if (nE < 1) return null; long [] lAry = new long [nE]; int n = 0; while (stz.hasMoreTokens()) { String tmp = stz.nextToken(); tmp.trim(); lAry[n++] = Long.parseLong(tmp); } return lAry; } /* ** Read filtering settings from the property file. ** */ static private FilteringSettings getFilter(String sPrix) throws Exception { boolean bFound = false; Enumeration propNames = m_Props.propertyNames(); int nTaxoID = 0; long [] catList = null; Enum.CategoryMembershipType cmType = null; while (propNames.hasMoreElements()) { String name = (String)propNames.nextElement(); if (name.startsWith(sPrix)) { // Taxonomy if (name.endsWith(TAXONOMY)) nTaxoID = Integer.parseInt(m_Props.getProperty(name)); if (name.endsWith(CATEGORYS)) { String sCList = m_Props.getProperty(name); catList = getCatList(sCList); } if (name.endsWith(CATNODE)) { bFound = true; String sCmType = m_Props.getProperty(name); cmType = Enum.CategoryMembershipType.getType(sCmType); } } } return bFound ? FilteringSettings.setFilteringSettings(nTaxoID, catList, cmType) : null; } protected static String getFunctionName(String trace) { // now go through the string to find what you want trace = trace.substring(trace.indexOf('\n')).trim(); trace = trace.substring(trace.indexOf(' ') + 1); //trace = trace.substring(0, trace.indexOf(')')); return (trace); } }