UNPKG

bestchoice

Version:

Self Learning Weighted Multivariate Testing Module

214 lines (159 loc) 5.64 kB
var EpsilonGreedy = require('./lib/epsilon-greedy.js'); var UCB1 = require('./lib/ucb1.js'); var campaigns = []; class Campaign { constructor(campaignID, targetURL, variants, epsilon, frequency) { this.campaignID = campaignID; this.targetURL = targetURL; this.variants = variants; this.stats = []; this.visitsQueue = []; this.epsilon = epsilon; this.frequency = frequency; }; init(counts = 0, values = 0) { var len = this.variants.length; var counts = new Array(len).fill(0); var values = new Array(len).fill(0); this.stats = new EpsilonGreedy(this.epsilon, counts, values); return true; }; }; // Get running campaign var getCampaignByID = function(campaignID) { var findId = function(campaign) { return campaign.campaignID === campaignID; } return campaigns.find(findId); }; // Find a page by cookie name var findCookie = function(cookie) { var campaign = getCampaignByID(campaignID); var cookiePosition = campaign.visitsQueue.map(function(e) { return e.cookie; }).indexOf(cookie); } // Get unconverted visit var getVisit = function(campaignID, cookie, variant) { var campaign = getCampaignByID(campaignID); var variantID = campaign.variants.indexOf(variant); var cookie = cookie; var findCookie = function(visit) { return visit.cookie === cookie; } return campaign.variants[campaign.stats.selectArm()]; }; // Register variant visit var addToVisitQueue = function(campaignID, targetURL, cookie) { var time = new Date().getTime(); var campaignID = getCampaignByID(campaignID); var variant = campaignID.variants.indexOf(targetURL); campaignID.visitsQueue.push({ time: time, cookie: cookie, variant: variant }) return cookie; }; var updateExpiredVisits = function(campaignID) { var timeNow = new Date().getTime(); var campaign = getCampaignByID(campaignID); var campaignIndex = campaigns.map(function(e) { return e.campaignID; }).indexOf(campaignID); var queue = campaigns[campaignIndex].visitsQueue; //check every item in campaigns visits queue and remove the expired ones while adjusting the weights queue.filter(function(e) { var minutesPassed = Math.round(((timeNow - e.time) / 1000) / 60); // check if if (minutesPassed > campaign.frequency) { var expiredItem = campaigns[campaignIndex].visitsQueue.splice(queue.indexOf(e), 1); //console.log(campaignIndex + " is the index"); var variant = e.variant; //console.log(e.variant + "variant to delete"); var reward = 0; campaigns[campaignIndex].stats.update(variant, reward); console.log('removed expired'); return true; } else { return false; } }); //campaigns[campaignIndex].visitsQueue = cleanList.slice(0); } module.exports = { // Add page to the Campaign addCampaign: function(campaignID, targetURL, variants, epsilon, frequency) { var _campaignID = campaignID; campaigns.push(campaignID = new Campaign(campaignID, targetURL, variants, epsilon, frequency)); getCampaignByID(_campaignID).init(); return true; }, // Remove page from the Campaign removeCampaign: function(campaignID) { return campaigns.splice(campaigns.indexOf(getCampaignByID(campaignID)), 1); }, // Return all availible campaigns getCampaigns: function() { return campaigns; }, // Return all availible campaigns as JSON saveCampaigns: function() { return JSON.stringify(campaigns); }, // Load campaigns from JSON file loadCampaigns: function(data) { campaigns = JSON.parse(data); return true; }, // Register visit getPage: function(campaignID, targetURL, cookie = 0) { var campaign = getCampaignByID(campaignID); // get current campaign object // if cookie is not set if (cookie === 0) { // select the page by using the decision algorythm from availible variants //console.log(campaign.stats.selectArm() + "is variant to show"); var variantToShow = campaign.variants[campaign.stats.selectArm()]; // create a random string var cookie = Math.random().toString(36).slice(2); // add to the unconverted visits queue addToVisitQueue(campaignID, variantToShow, cookie); return { // variant URL to show pageVariant: getVisit(campaignID, cookie, variantToShow), // newly generated cookie cookie: cookie, // campaign ID campaignID: campaignID } } // if cookie already exists return the existing information else { // TODO reset cookie time in the visit queue return { pageVariant: getVisit(campaignID, cookie, targetURL), cookie: cookie, campaignID: campaignID } } }, // Register variant conversion registerConversion: function(campaignID, targetURL, cookie, reward = 1) { var campaign = getCampaignByID(campaignID); var variantID = campaign.variants.indexOf(targetURL); var findCookie = function(visit) { return visit.cookie === cookie; } var cookiePosition = campaign.visitsQueue.map(function(e) { return e.cookie; }).indexOf(cookie); if (cookiePosition === -1) { return } var variant = campaign.variants.indexOf(targetURL); campaign.stats.update(variant, reward); campaign.visitsQueue.splice(cookiePosition, 1); return true; }, updateExpiredVisits: updateExpiredVisits };