bestchoice
Version:
Self Learning Weighted Multivariate Testing Module
223 lines (172 loc) • 6.89 kB
JavaScript
;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var EpsilonGreedy = require('./lib/epsilon-greedy.js');
var UCB1 = require('./lib/ucb1.js');
var campaigns = [];
var Campaign = function () {
function Campaign(campaignID, targetURL, variants, epsilon, frequency) {
_classCallCheck(this, Campaign);
this.campaignID = campaignID;
this.targetURL = targetURL;
this.variants = variants;
this.stats = [];
this.visitsQueue = [];
this.epsilon = epsilon;
this.frequency = frequency;
}
_createClass(Campaign, [{
key: 'init',
value: function init() {
var counts = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
var values = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
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;
}
}]);
return Campaign;
}();
;
// Get running campaign
var getCampaignByID = function getCampaignByID(campaignID) {
var findId = function findId(campaign) {
return campaign.campaignID === campaignID;
};
return campaigns.find(findId);
};
// Find a page by cookie name
var findCookie = function findCookie(cookie) {
var campaign = getCampaignByID(campaignID);
var cookiePosition = campaign.visitsQueue.map(function (e) {
return e.cookie;
}).indexOf(cookie);
};
// Get unconverted visit
var getVisit = function getVisit(campaignID, cookie, variant) {
var campaign = getCampaignByID(campaignID);
var variantID = campaign.variants.indexOf(variant);
var cookie = cookie;
var findCookie = function findCookie(visit) {
return visit.cookie === cookie;
};
return campaign.variants[campaign.stats.selectArm()];
};
// Register variant visit
var addToVisitQueue = function addToVisitQueue(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 updateExpiredVisits(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 addCampaign(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 removeCampaign(campaignID) {
return campaigns.splice(campaigns.indexOf(getCampaignByID(campaignID)), 1);
},
// Return all availible campaigns
getCampaigns: function getCampaigns() {
return campaigns;
},
// Return all availible campaigns as JSON
saveCampaigns: function saveCampaigns() {
return JSON.stringify(campaigns);
},
// Load campaigns from JSON file
loadCampaigns: function loadCampaigns(data) {
campaigns = JSON.parse(data);
return true;
},
// Register visit
getPage: function getPage(campaignID, targetURL) {
var cookie = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2];
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 registerConversion(campaignID, targetURL, cookie) {
var reward = arguments.length <= 3 || arguments[3] === undefined ? 1 : arguments[3];
var campaign = getCampaignByID(campaignID);
var variantID = campaign.variants.indexOf(targetURL);
var findCookie = function findCookie(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
};