class VWO::Core::Bucketer
Constants
- FILE
- MAX_HASH_VALUE
- U_MAX_32_BIT
Took reference from StackOverflow(stackoverflow.com/) to: convert signed to unsigned integer in python from StackOverflow Author - Duncan (stackoverflow.com/users/107660/duncan) Source - stackoverflow.com/a/20766900/2494535
Public Class Methods
# File lib/vwo/core/bucketer.rb, line 36 def initialize @logger = VWO::Logger.get_instance end
Public Instance Methods
Validates the User ID and Generates Variation into which the User is bucketed to
@param :user_id The unique ID assigned to User @param :campaign The Campaign of which User is a part of
@return[Hash|nil} Variation data into which user is bucketed to
or nil if not
# File lib/vwo/core/bucketer.rb, line 80 def bucket_user_to_variation(user_id, campaign) unless valid_value?(user_id) @logger.log( LogLevelEnum::ERROR, format(LogMessageEnum::ErrorMessages::INVALID_USER_ID, file: FILE, user_id: user_id, method: 'bucket_user_to_variation') ) return end unless campaign @logger.log( LogLevelEnum::ERROR, format(LogMessageEnum::ErrorMessages::INVALID_CAMPAIGN, file: FILE, method: 'is_user_part_of_campaign') ) return end user_id_for_hash_value = user_id if campaign[:isBucketingSeedEnabled] user_id_for_hash_value = campaign[:id].to_s + "_" + user_id end hash_value = MurmurHash3::V32.str_hash(user_id_for_hash_value, SEED_VALUE) & U_MAX_32_BIT normalize = MAX_TRAFFIC_VALUE.to_f / campaign['percentTraffic'] multiplier = normalize / 100 bucket_value = get_bucket_value( hash_value, MAX_TRAFFIC_VALUE, multiplier ) @logger.log( LogLevelEnum::DEBUG, format( LogMessageEnum::DebugMessages::VARIATION_HASH_BUCKET_VALUE, file: FILE, user_id: user_id, campaign_key: campaign['key'], percent_traffic: campaign['percentTraffic'], bucket_value: bucket_value, hash_value: hash_value ) ) get_variation(campaign['variations'], bucket_value) end
Generates Bucket Value of the User by hashing the User ID by murmurHash And scaling it down.
@param :hash_value HashValue generated after hashing @param :max_value The value up-to which hashValue needs to be scaled @param :multiplier @return Bucket Value of the User
# File lib/vwo/core/bucketer.rb, line 178 def get_bucket_value(hash_value, max_value, multiplier = 1) ratio = hash_value.to_f / MAX_HASH_VALUE multiplied_value = (max_value * ratio + 1) * multiplier multiplied_value.to_i end
Validates the User ID and generates Bucket Value of the User by hashing the userId by murmurHash and scaling it down.
@param :user_id The unique ID assigned to User @param :campaign Campaign data @return The bucket Value allotted to User
(between 1 to $this->$MAX_TRAFFIC_PERCENT)
# File lib/vwo/core/bucketer.rb, line 146 def get_bucket_value_for_user(user_id, campaign = {}, group_id = nil, disable_logs = false) user_id_for_hash_value = user_id if group_id user_id_for_hash_value = group_id.to_s + "_" + user_id elsif campaign[:isBucketingSeedEnabled] user_id_for_hash_value = campaign[:id].to_s + "_" + user_id end hash_value = MurmurHash3::V32.str_hash(user_id_for_hash_value, SEED_VALUE) & U_MAX_32_BIT bucket_value = get_bucket_value(hash_value, MAX_TRAFFIC_PERCENT) @logger.log( LogLevelEnum::DEBUG, format( LogMessageEnum::DebugMessages::USER_HASH_BUCKET_VALUE, file: FILE, hash_value: hash_value, bucket_value: bucket_value, user_id: user_id ), disable_logs ) bucket_value end
Returns a campaign by checking the Start and End Bucket Allocations of each campaign.
@param :range_for_campaigns the bucket value of the user @param :campaigns The bucket Value of the user @return
# File lib/vwo/core/bucketer.rb, line 190 def get_campaign_using_range(range_for_campaigns, campaigns) range_for_campaigns = range_for_campaigns * 100 campaigns.each do |campaign| if campaign["max_range"] && campaign["max_range"] >= range_for_campaigns && campaign["min_range"] <= range_for_campaigns return campaign end end nil end
Returns the Variation by checking the Start and End Bucket Allocations of each Variation
@param :campaign Which contains the variations @param :bucket_value The bucket Value of the user @return Variation data allotted to the user or None if not
# File lib/vwo/core/bucketer.rb, line 133 def get_variation(variations, bucket_value) variations.find do |variation| (variation['start_variation_allocation']..variation['end_variation_allocation']).cover?(bucket_value) end end
Calculate if this user should become part of the campaign or not @param :user_id The unique ID assigned to a user @param :campaign For getting traffic allotted to the campaign @return If User is a part of Campaign or not
# File lib/vwo/core/bucketer.rb, line 45 def user_part_of_campaign?(user_id, campaign) unless valid_value?(user_id) @logger.log( LogLevelEnum::ERROR, format(LogMessageEnum::ErrorMessages::INVALID_USER_ID, file: FILE, user_id: user_id, method: 'is_user_part_of_campaign') ) return false end if campaign.nil? @logger.log( LogLevelEnum::ERROR, format(LogMessageEnum::ErrorMessages::INVALID_CAMPAIGN, file: FILE, method: 'is_user_part_of_campaign') ) return false end traffic_allocation = campaign['percentTraffic'] value_assigned_to_user = get_bucket_value_for_user(user_id, campaign) is_user_part = (value_assigned_to_user != 0) && value_assigned_to_user <= traffic_allocation @logger.log( LogLevelEnum::INFO, format(LogMessageEnum::InfoMessages::USER_ELIGIBILITY_FOR_CAMPAIGN, file: FILE, user_id: user_id, is_user_part: is_user_part) ) is_user_part end