mercredi 8 novembre 2023

Random selection based on weightage and previous history

I have a spring boot application for a notification system. Consider sms notifications for which I have n vendors to select from. Every vendor has been promised a certain percentage of our business, say their weightage.

During a time duration say 24 hours, a particular vendor is selected based on their weightage percentage. Due to some reason if a vendor's services are down, our system selects the next highest priority vendor for delivering the notification or if a particular sms is to be sent by a particular vendor only then that is chosen.

Currently I am generating a random number between 0 to 100 and then using its value for selecting a vendor. What I want it to do is to use last window of sms notifications and then balance the percentage of sms sent in the current time window.

Example :

Vendor 1: 20% W, Vendor 2: 30% W and Vendor 3: 50% W.

In first 24 hours I send 10 sms.

  1. Vendor 1 sent 3 sms -> 30%
  2. Vendor 2 sent 4 sms -> 40%
  3. Vendor 3 sent 3 sms -> 30%

So what I would like is if I send 20 sms by the end next time window Then

  1. Vendor 1 should have sent 3 sms -> 15%
  2. Vendor 2 should have sent 5 sms -> 25%
  3. Vendor 3 should have sent 12 sms -> 60%

Averaging over 30 sms for 2 time windows, vendor 1: 20%, vendor 2: 30% and vendor 3: 50%

The same balancing/averaging is to be done over all time windows.

My issue is how to implement this when I don't know the number of sms I will send in a day. The range is generally around a hundred thousands, but sometimes much more.

My current implementation:

if (Objects.nonNull(templateEntity.getSmsVendor())) {
      // case 1 - when vendor is specified in notification template, use that vendor
      smsNotifier.get(templateEntity.getSmsVendor()).send(notificationRequestDTO);
    } else {
      // case 2 - when vendor is NOT specified in notification template. Choose weightage wise vendor
      int totalProbability = 0;
      for (SmsNotifier notifier : smsNotifierList) {
        totalProbability += notifier.getWeightage();
      }
    
      int randomNumber = RandomUtils.nextInt(0, totalProbability);
      int currentProbability = 0;
    
      // vendor1 = 60, vendor2 = 40, Mock = 0
      for (SmsNotifier notifier : smsNotifierList) {
        if (randomNumber >= currentProbability && randomNumber < currentProbability + notifier.getWeightage()) {
          log.error("Selected vendor for sms {} is {} weightage {} current probability {}", notificationRequestDTO, notifier.getId(), notifier.getWeightage(), currentProbability);
          notifier.send(notificationRequestDTO);
          break;
        }
        currentProbability += notifier.getWeightage();
      }
    }



Aucun commentaire:

Enregistrer un commentaire