学习 API 示例
本节包含 ILearning 接口的实现样本。 请注意,此实现只是一个样本,并非设计为用于生产环境。
此示例跟踪接受计数和联系计数,并使用某一特定要约的接受与联系之比来作为此要约的接受可能性等级。未显示的要约将获得较高的推荐优先级。至少具有一次联系的要约将根据递减的接受可能性评级来进行排序。
在此示例中,所有计数均保存在内存中。这是一种不现实的方案,因为运行时服务器将耗尽内存。在实际生产方案中,计数应保存在数据库中。
package com.unicacorp.interact.samples.learning.v2;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.unicacorp.interact.samples.learning.SampleOptimizer.MyOfferSorter;
import com.unicacorp.interact.treatment.optimization.IClientArgs;
import com.unicacorp.interact.treatment.optimization.IInteractSession;
import com.unicacorp.interact.treatment.optimization.ILearningConfig;
import com.unicacorp.interact.treatment.optimization.ILearningContext;
import com.unicacorp.interact.treatment.optimization.IOffer;
import com.unicacorp.interact.treatment.optimization.LearningException;
import com.unicacorp.interact.treatment.optimization.v2.ILearning;
import com.unicacorp.interact.treatment.optimization.v2.ITreatment;

/**
* This is a sample implementation of the learning optimizer.
* The interface ILearning may be found in the interact.jar library.
*
* To actually use this implementation, select ExternalLearning as the optimizationType in the offerServing node
* of the Interact application within the Platform configuration. Within the offerserving node there is also
* an External Learning config category - within there you must set the name of the class to this:
* com.unicacorp.interact.samples.learning.v2.SampleLearning. Please note however, this implementation is just a sample
* and was not designed to be used in a production environment.
*
*
* This example keeps track of accept and contact counts and uses the ratio of accept to contacts
* for a particular offer as the acceptance probability rate for the offer.
*
*
* Offers not presented will get higher priority for recommending.
* Offers with at least one contact will be ordered based on descending acceptance probability rate.
*
* Note: all counts are kept in memory. This is not a realistic scenario since you would run out of memory sooner or
* later. In a real production scenario, the counts should be persisted into a database.
*
*/

public class SampleLearning implements ILearning
{

// A map of offer ids to contact count for the offer id
private Map<Long,Integer> _offerToContactCount = new HashMap<Long, Integer>();

// A map of offer ids to contact count for the offer id
private Map<Long,Integer> _offerToAcceptCount = new HashMap<Long, Integer>();


/* (non-Javadoc)
* @see com.unicacorp.interact.treatment.optimization.v2.ILearning#initialize
* (com.unicacorp.interact.treatment.optimization.v2.ILearningConfig, boolean)
*/
public void initialize(ILearningConfig config, boolean debug) throws LearningException
{
// If any remote connections are required, this is a good place to initialize those connections as this
// method is called once at the start of the interact runtime webapp.
// This example does not have any remote connections and prints for debugging purposes that this method will
// be called
System.out.println("Calling initialize for SampleLearning");
}

/* (non-Javadoc)
* @see com.unicacorp.interact.treatment.optimization.v2.ILearning#reinitialize
* (com.unicacorp.interact.treatment.optimization.v2.ILearningConfig, boolean)
*/
public void reinitialize(ILearningConfig config, boolean debug) throws LearningException
{
// If an IC is deployed, this reinitialize method is called to allow the implementation to
// refresh any updated configuration settings
System.out.println("Calling reinitialize for SampleLearning");
}


/* (non-Javadoc)
* @see com.unicacorp.interact.treatment.optimization.v2.ILearning#logEvent
* (com.unicacorp.interact.treatment.optimization.v2.ILearningContext,
* com.unicacorp.interact.treatment.optimization.v2.IOffer,
* com.unicacorp.interact.treatment.optimization.v2.IClientArgs,
* com.unicacorp.interact.treatment.optimization.IInteractSession, boolean)
*/
public void logEvent(ILearningContext context, IOffer offer, IClientArgs clientArgs,
IInteractSession session, boolean debug) throws LearningException
{
System.out.println("Calling logEvent for SampleLearning");


if(context.getLearningContext()==ILearningContext.LOG_AS_CONTACT)
{
System.out.println("adding contact");

// Keep track of all contacts in memory
synchronized(_offerToAcceptCount)
{
Integer count = _offerToAcceptCount.get(offer.getOfferId());
if(count == null)
count = new Integer(1);
else
count++;
_offerToAcceptCount.put(offer.getOfferId(), ++count);
}

}
else if(context.getLearningContext()==ILearningContext.LOG_AS_ACCEPT)
{
System.out.println("adding accept");
// Keep track of all accept counts in memory by adding to the map
synchronized(_offerToAcceptCount)
{
Integer count = _offerToAcceptCount.get(offer.getOfferId());
if(count == null)
count = new Integer(1);
else
count++;
_offerToAcceptCount.put(offer.getOfferId(), ++count);
}
}

}

/* (non-Javadoc)
* @see com.unicacorp.interact.treatment.optimization.v2.ILearning#optimizeRecommendList
* (java.util.List, com.unicacorp.interact.treatment.optimization.v2.IClientArgs,
* com.unicacorp.interact.treatment.optimization.IInteractSession, boolean)
*/
public List<ITreatment> optimizeRecommendList(List<ITreatment> recList,
IClientArgs clientArgs, IInteractSession session, boolean debug)
throws LearningException
{
System.out.println("Calling optimizeRecommendList for SampleLearning");

// Sort the candidate treatments by calling the sorter defined in this class and return the sorted list
Collections.sort(recList,new MyOfferSorter());

// now just return what was asked for via "numberRequested" variable
List<ITreatment> result = new ArrayList<ITreatment>();

for(int x=0;x<(Integer)clientArgs.getValue(IClientArgs.NUMBER_OF_OFFERS_REQUESTED) && x<recList.size();x++)
{
result.add(recList.get(x));
}
return result;
}

/* (non-Javadoc)
* @see com.unicacorp.interact.treatment.optimization.v2.ILearning#shutdown
* (com.unicacorp.interact.treatment.optimization.v2.ILearningConfig, boolean)
*/
public void shutdown(ILearningConfig config, boolean debug) throws LearningException
{
// If any remote connections exist, this would be a good place to gracefully
// disconnect from them as this method is called at the shutdown of the Interact runtime
// webapp. For this example, there is nothing really to do
// except print out a statement for debugging.
System.out.println("Calling shutdown for SampleLearning");

}
// Sort by:
// 1. offers with zero contacts - for ties, order is based on original input
// 2. descending accept probability rate - for ties, order is based on original input

public class MyOfferSorter implements Comparator<ITreatment>
{
private static final long serialVersionUID = 1L;

/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compare(ITreatment treatment1, ITreatment treatment2)
{

// get contact count for both treatments
Integer contactCount1 = _offerToContactCount.get(treatment1.getOffer().getOfferId());
Integer contactCount2 = _offerToContactCount.get(treatment2.getOffer().getOfferId());

// if treatment hasn't been contacted, then that wins
if(contactCount1 == null || contactCount1 == 0)
return -1;

if(contactCount2 == null || contactCount2 == 0)
return 1;

// get accept counts
Integer acceptCount1 = _offerToAcceptCount.get(treatment1.getOffer().getOfferId());
Integer acceptCount2 = _offerToAcceptCount.get(treatment2.getOffer().getOfferId());

float acceptProbability1 = (float) acceptCount1 / (float) contactCount1;
float acceptProbability2 = (float) acceptCount2 / (float) contactCount2;

// descending order
return (int) (acceptProbability2 - acceptProbability1);

}
}

}