Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

Assignment probabilities based on segment sizes #6

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/classes/batchSegmentCreator.cls
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ gglobal class batchSegmentCreator implements Database.Batchable<SObject>,Databas
global List<Id> segmentCampaignIds;
global List<Integer> segmentSizes;
global List<Integer> membersAdded;
global List<Double> sizesCDF;
global String errorTxt = '';
global boolean keepOriginal;

Expand All @@ -57,7 +58,18 @@ gglobal class batchSegmentCreator implements Database.Batchable<SObject>,Databas
Boolean assigned = false;

while(assigned == false){
Integer assignedList = Math.floor(segmentCampaignIds.size() * Math.Random()).intValue();
Integer assignedList;
Double prob = Math.Random();

// iterate through sizesCDF to find correct bucket
// note that sizesCDF must be sorted from smallest to largest
// probability (and should be given the generation process above)
for (Integer i=0; i<sizesCDF.size(); i++) {
if (sizesCDF[i] >= prob) {
assignedList = i;
break;
}
}

if((membersAdded[assignedList] < segmentSizes[assignedList])){
newCampaignMembers.add(
Expand Down Expand Up @@ -202,4 +214,4 @@ gglobal class batchSegmentCreator implements Database.Batchable<SObject>,Databas
System.AssertEquals(database.countquery('SELECT count()' +' FROM CampaignMember WHERE campaignId=\'' + mySegmentIds[1] + '\''), 100);
}

}
}
47 changes: 39 additions & 8 deletions src/classes/memberAssignment.cls
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public with sharing class memberAssignment {
static List<Integer> members;
static List<CampaignMember> newCampaignMembers;
static Boolean keep;
static Integer totalSize;
static List<Double> sizesCDF;

public static boolean assignMembersNow(Id parentCampaignId, List<Id> segmentCampaignIds, List<Integer> segmentSizes, List<Integer> membersAdded, Boolean keepOriginal){
campId = parentCampaignId;
Expand All @@ -44,11 +46,31 @@ public with sharing class memberAssignment {
newCampaignMembers = new List<CampaignMember>();

List<CampaignMember> oldMembers = [select id,campaignId, leadId, contactid from campaignMember where CampaignId = :campId];

// Figure out the fraction that should go into each list,
// then generate a cumulative distribution function to
// use in making the assignments
totalSize = 0;
for (Integer s : sizes) {
totalSize += s;
}

// Generate the CDF
sizesCDF = new List<Double>();
sizesCDF.add(1.0*sizes[0]/totalSize);
for (Integer i=1; i<sizes.size(); i++) {
sizesCDF.add(sizesCDF[i-1] + (1.0*sizes[i]/totalSize));
}
// be sure final value is 1.0, regardless of rounding issues:
sizesCDF[sizesCDF.size()-1] = 1.0;


for(CampaignMember thisMember : oldMembers){
assignMember(thisMember);
}
system.debug('******newCampaignMembers = '+newCampaignMembers);
// This may be millions of records long in prod, probably not
// worth spitting out to the console every time.
// system.debug('******newCampaignMembers = '+newCampaignMembers);
if(!newCampaignMembers.isEmpty()){
try {
insert newCampaignMembers;
Expand All @@ -66,19 +88,28 @@ public with sharing class memberAssignment {
}

private static void assignMember(CampaignMember thisCampaignMember){
Integer assignedList = Math.floor(semgmentIds.size() * Math.Random()).intValue();

if((members[assignedList] < sizes[assignedList])){
Integer assignedList;
Double prob = Math.Random();

// iterate through sizesCDF to find first correct bucket
// note that sizesCDF must be sorted from smallest to largest
// probability (and should be given the generation process above)
for (Integer i=0; i<sizesCDF.size(); i++) {
if (sizesCDF[i] >= prob) {
assignedList = i;
break;
}
}

if(members[assignedList] < sizes[assignedList]){
newCampaignMembers.add(
new CampaignMember(
CampaignId = semgmentIds[assignedList],
LeadId = thisCampaignMember.LeadId,
ContactId = thisCampaignMember.ContactId
)
);
if(members[assignedList] < sizes[assignedList]){
members[assignedList]++;
}
members[assignedList]++;
} else {
assignMember(thisCampaignMember);
}
Expand All @@ -89,4 +120,4 @@ public with sharing class memberAssignment {



}
}
22 changes: 21 additions & 1 deletion src/classes/segmentsController.cls
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,26 @@ public with sharing class segmentsController {
batchSegments.segmentCampaignIds = newCampaignIds;
batchSegments.segmentSizes = segmentSizes;
batchSegments.membersAdded = membersAdded;

// Figure out the fraction that should go into each list,
// then generate a cumulative distribution function to
// use in making the assignments
Integer totalSize = 0;
for (Integer s : segmentSizes) {
totalSize += s;
}

// Generate the CDF
List<Double> segmentSizesCDF = new List<Double>();
segmentSizesCDF.add(1.0*segmentSizes[0]/totalSize);
for (Integer i=1; i<segmentSizes.size(); i++) {
segmentSizesCDF.add(segmentSizesCDF[i-1] + (1.0*segmentSizes[i]/totalSize));
}
// be sure final value is 1.0, regardless of rounding issues:
segmentSizesCDF[segmentSizesCDF.size()-1] = 1.0;

batchSegments.sizesCDF = segmentSizesCDF;

batchSegments.keepOriginal = keepOriginal;
batchSegments.email = batchEmailNotification;
ID batchprocessid = Database.executeBatch(batchSegments);
Expand Down Expand Up @@ -565,4 +585,4 @@ public with sharing class segmentsController {

}

}
}