/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.easyrec.plugin.arm; import gnu.trove.map.hash.TObjectIntHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.easyrec.model.core.ItemAssocVO; import org.easyrec.model.core.ItemVO; import org.easyrec.plugin.arm.model.ARMConfiguration; import org.easyrec.plugin.arm.model.ARMConfigurationInt; import org.easyrec.plugin.arm.model.ARMStatistics; import org.easyrec.plugin.arm.model.TupleVO; import org.easyrec.plugin.arm.store.dao.RuleminingItemAssocDAO; import org.easyrec.plugin.model.Version; import org.easyrec.plugin.support.GeneratorPluginSupport; import java.net.URI; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.SortedSet; /** * * @author szavrel */ public class ARMGenerator extends GeneratorPluginSupport<ARMConfiguration, ARMStatistics> { public static final String DISPLAY_NAME = "ARM"; public static final Version VERSION = new Version("0.98"); public static final URI ID = URI.create("http://www.easyrec.org/plugins/ARM"); private static final Log logger = LogFactory.getLog(ARMGenerator.class); private AssocRuleMiningService assocRuleMiningService; private TupleCounter tupleCounter; private RuleminingItemAssocDAO ruleminingItemAssocDAO; //private TenantService tenantService; public ARMGenerator() { super(DISPLAY_NAME, ID, VERSION, ARMConfiguration.class, ARMStatistics.class); } @Override public ARMConfiguration newConfiguration() { return new ARMConfiguration(); } @Override protected void doExecute(ExecutionControl control, ARMStatistics stats) throws Exception { control.updateProgress(1, 1, "Calculating # of baskets."); ARMConfiguration configuration = getConfiguration(); ARMConfigurationInt intConfiguration; Date start = new Date(); stats.setStartDate(start); try { intConfiguration = assocRuleMiningService.mapTypesToConfiguration(configuration); logger.info("TenantId:" + intConfiguration.getTenantId()); } catch (Exception e) { stats.setException(e.getMessage()); intConfiguration = null; } if (intConfiguration != null) { tupleCounter.init(); if (control.isAbortRequested()) throw new Exception("ARM was manually aborted!"); control.updateProgress(1, 6, "Calculating # of baskets."); Integer nrBaskets = assocRuleMiningService.getNumberOfBaskets(intConfiguration); stats.setNrBaskets(nrBaskets); if (control.isAbortRequested()) throw new Exception("ARM was manually aborted!"); control.updateProgress(2, 6, "Calculating # of products."); Integer nrProducts = assocRuleMiningService.getNumberOfProducts(intConfiguration); stats.setNrProducts(nrProducts); Integer support = (int) (nrBaskets * (configuration.getSupportPrcnt() / 100)); intConfiguration.setSupport(Math.max(support, configuration.getSupportMinAbs())); if (control.isAbortRequested()) throw new Exception("ARM was manually aborted!"); control.updateProgress(3, 6, "Defining set L1."); TObjectIntHashMap<ItemVO<Integer, Integer>> L1 = assocRuleMiningService.defineL1(intConfiguration); stats.setSizeL1(L1.size()); stats.setLastSupport(intConfiguration.getSupport()); if (control.isAbortRequested()) throw new Exception("ARM was manually aborted!"); control.updateProgress(4, 6, "Defining set L2."); List<TupleVO> L2 = assocRuleMiningService.defineL2(L1, tupleCounter, intConfiguration, stats); stats.setSizeL2(L2.size()); if (control.isAbortRequested()) throw new Exception("ARM was manually aborted!"); control.updateProgress(5, 6, "Generating rules."); if (configuration.getMaxRulesPerItem() == null) { List<ItemAssocVO<Integer,Integer>> rules = assocRuleMiningService.createRules(L2, L1, intConfiguration, stats, configuration.getConfidencePrcnt()); stats.setSizeRules(rules.size()); for (ItemAssocVO<Integer,Integer> itemAssocVO : rules) { // try { // ruleminingItemAssocDAO.insertItemAssoc(itemAssocVO); // } catch (DataIntegrityViolationException e) { // ruleminingItemAssocDAO.updateItemAssocUsingUniqueKey(itemAssocVO); // } ruleminingItemAssocDAO.insertOrUpdateItemAssoc(itemAssocVO); } } else { int count = 0; Collection<SortedSet<ItemAssocVO<Integer,Integer>>> rules = assocRuleMiningService.createBestRules( L2, L1, intConfiguration, stats, configuration.getConfidencePrcnt()); for (SortedSet<ItemAssocVO<Integer,Integer>> sortedSet : rules) { count += sortedSet.size(); for (ItemAssocVO<Integer,Integer> itemAssocVO : sortedSet) { // try { // ruleminingItemAssocDAO.insertItemAssoc(itemAssocVO); // } catch (DataIntegrityViolationException e) { // ruleminingItemAssocDAO.updateItemAssocUsingUniqueKey(itemAssocVO); // } ruleminingItemAssocDAO.insertOrUpdateItemAssoc(itemAssocVO); } } stats.setSizeRules(count); stats.setNumberOfRulesCreated(count); } stats.setLastConf(configuration.getConfidencePrcnt()); stats.setNumberOfActionsConsidered(assocRuleMiningService.getNumberOfActions(intConfiguration)); // remove old Rules assocRuleMiningService.removeOldRules(intConfiguration, stats); //assocRuleMiningService.perform(configuration.getTenantId()); control.updateProgress(6, 6, "Finished"); } // TODO: else write logoutput stats.setEndDate(new Date()); stats.setDuration((stats.getEndDate().getTime() - stats.getStartDate().getTime())/1000); } @Override public String getPluginDescription() { return "This plugin provides a simple algorithm for shopping basket analysis. " + "It generates rules of the type 'items that where frequently viewed/bought/good rated together.'"; } // ----------------------------- GETTER / SETTER METHODS ------------------------------------- public void setAssocRuleMiningService(AssocRuleMiningService assocRuleMiningService) { this.assocRuleMiningService = assocRuleMiningService; } public void setTupleCounter(TupleCounter tupleCounter) { this.tupleCounter = tupleCounter; } public void setRuleminingItemAssocDAO(RuleminingItemAssocDAO ruleminingItemAssocDAO) { this.ruleminingItemAssocDAO = ruleminingItemAssocDAO; } }