当前位置:   article > 正文

比例分成算法--java_派单根据比例算法代码实现

派单根据比例算法代码实现

关于业绩分配,常常会出现几家公司或者几个人合作的情况,那么合作之后创造出来的业绩价值如何分配的呢?有可能是1:1或者3:7.或者是3:3:4等等。那么我们针对这种情况就设计出来了一套比例分成系统。

代码如下所示:

主代码:

  1. package com.handler.mark.cardperformance;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.dataplatform.dto.base.IBaseOrgDTO;
  5. import com.dataplatform.enums.DimensionChannelGroupEnum;
  6. import com.dataplatform.model.ApplyDetailInfo;
  7. import com.dataplatform.util.MarkByProportionUtil;
  8. import org.apache.commons.lang3.StringUtils;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import redis.clients.jedis.ShardedJedis;
  12. import redis.clients.jedis.ShardedJedisPool;
  13. import java.math.BigInteger;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. /**
  17. * Created by on 2018/7/20.
  18. */
  19. /**
  20. * 比例分成算法
  21. * @author
  22. * @date 2018-07-26
  23. * @version 1.0
  24. *
  25. */
  26. public class WeightRoundRobinBo {
  27. private static final int DEF_CURRENT_INDEX = -1;
  28. private static final int DEF_CURRENT_WEIGHT = 0;
  29. private static final String KEY_CURRENT_INDEX = "currentIndex";
  30. private static final String KEY_CURRENT_WEIGHT = "currentWeight";
  31. private Logger LOG = LoggerFactory.getLogger(WeightRoundRobinBo.class);
  32. private ShardedJedisPool shardedJedisPool;
  33. @SuppressWarnings("unused")
  34. private WeightRoundRobinBo() {
  35. }
  36. /**
  37. * 自定义构造方法
  38. * @param orgListOfChannel 渠道所对应机构列表
  39. * @param currentEnum
  40. * @param applyDetailInfo 当前进件信息
  41. * @param shardedJedisPool
  42. */
  43. public WeightRoundRobinBo(List<? extends IBaseOrgDTO> orgListOfChannel, DimensionChannelGroupEnum currentEnum, ApplyDetailInfo applyDetailInfo, ShardedJedisPool shardedJedisPool) {
  44. this.orgListOfChannel = orgListOfChannel;
  45. this.shardedJedisPool = shardedJedisPool;
  46. try(ShardedJedis jedis = shardedJedisPool.getResource()){
  47. /** 持卡用户进件与新用户进件分开打标*/
  48. this.redisKey = MarkByProportionUtil.getRedisKeyOfCurrentWight(
  49. currentEnum.getDimensionCode(),
  50. currentEnum.getChannelGroupCode(),
  51. applyDetailInfo.getSource(),
  52. applyDetailInfo.getIsCardHolder()
  53. );
  54. if(StringUtils.isBlank(redisKey)){
  55. throw new RuntimeException("illegal parameters: redisKey is null");
  56. }
  57. JSONObject json = JSON.parseObject(jedis.get(this.redisKey));
  58. String currentIndexStr = json == null ? null : json.getString(KEY_CURRENT_INDEX);
  59. String currentWeightStr = json == null ? null : json.getString(KEY_CURRENT_WEIGHT);
  60. this.currentIndex = StringUtils.isNumeric(currentIndexStr) ? Integer.parseInt(currentIndexStr) : DEF_CURRENT_INDEX;
  61. this.currentWeight = StringUtils.isNumeric(currentWeightStr) ? Integer.parseInt(currentWeightStr) : DEF_CURRENT_WEIGHT;
  62. this.orgCount = orgListOfChannel.size();
  63. this.maxWeight = greatestWeight();
  64. this.gcdWeight = greatestCommonDivisor();
  65. this.initStatus = true;
  66. }catch (Exception e){
  67. LOG.error("WeightRoundRobin init error: ", e);
  68. }
  69. }
  70. /**
  71. * 上次选择机构
  72. */
  73. private int currentIndex = DEF_CURRENT_INDEX;
  74. /**
  75. * 当前调度的权值
  76. */
  77. private int currentWeight = DEF_CURRENT_WEIGHT;
  78. /**
  79. * 最大权重
  80. */
  81. private int maxWeight;
  82. /**
  83. * 权重的最大公约数
  84. */
  85. private int gcdWeight;
  86. /**
  87. * 机构数量
  88. */
  89. private int orgCount;
  90. private List<? extends IBaseOrgDTO> orgListOfChannel = new ArrayList<>();
  91. /**
  92. * redis上保存当前index和weight的key
  93. */
  94. private String redisKey;
  95. /**
  96. * 是否初始化
  97. */
  98. private boolean initStatus = false;
  99. /**
  100. * 获取两个数的最大公约数
  101. */
  102. private int greaterCommonDivisor(int a, int b) {
  103. BigInteger aBig = new BigInteger(String.valueOf(a));
  104. BigInteger bBig = new BigInteger(String.valueOf(b));
  105. return aBig.gcd(bBig).intValue();
  106. }
  107. /**
  108. * 遍历获取所有机构比例的最大公约数
  109. */
  110. private int greatestCommonDivisor() {
  111. int divisor = 0;
  112. for (int index = 0, len = orgListOfChannel.size(); index < len - 1; index++) {
  113. if (index == 0) {
  114. divisor = greaterCommonDivisor(
  115. orgListOfChannel.get(index).getProportion(), orgListOfChannel.get(index + 1).getProportion());
  116. } else {
  117. divisor = greaterCommonDivisor(divisor, orgListOfChannel.get(index).getProportion());
  118. }
  119. }
  120. return divisor;
  121. }
  122. /**
  123. * 遍历获取最大的机构占比(权重)
  124. */
  125. private int greatestWeight() {
  126. int weight = 0;
  127. for (IBaseOrgDTO orgObj : orgListOfChannel) {
  128. if (weight < orgObj.getProportion()) {
  129. weight = orgObj.getProportion();
  130. }
  131. }
  132. return weight;
  133. }
  134. /**
  135. * 根据权重轮询获取当前org
  136. *
  137. * @gcdWeight 权重的最大公约数
  138. * @currentIndex 用于记录当前轮询链表的位置
  139. * @currentWeight 用于记录当前权重值
  140. * @orgListOfChannel 用于当前进件的渠道所对应的分成机构列表
  141. *
  142. *
  143. * 初始从最大的权重(占比)进行分配 currentWeight = maxWeight
  144. *
  145. * 非初始情况,根据redis缓存中保存的位置currentIndex和currentWeight继续分配
  146. *
  147. * 遍历机构列表,每次遍历输出大于等于currentWeight的机构对象
  148. *
  149. * 每次遍历完,将currentWeight减去 所有机构权重值的最大公约数,再次遍历输出
  150. *
  151. * 直到currentWeight小于等于零,即完成了一遍权重轮询,每一个权重值都输出了对应比例的次数
  152. *
  153. *
  154. */
  155. private IBaseOrgDTO getOrgInfo() {
  156. while (true) {
  157. currentIndex = (currentIndex + 1) % orgCount;
  158. if (currentIndex == 0) {
  159. currentWeight = currentWeight - gcdWeight;
  160. if (currentWeight <= 0) {
  161. currentWeight = maxWeight;
  162. if (currentWeight == 0) {
  163. return null;
  164. }
  165. }
  166. }
  167. if (orgListOfChannel.get(currentIndex).getProportion() >= currentWeight) {
  168. return orgListOfChannel.get(currentIndex);
  169. }
  170. }
  171. }
  172. /**
  173. * 输出org后,将currentIndex和currentWeight更新到redis上
  174. */
  175. private void updateRedis(){
  176. JSONObject json = new JSONObject();
  177. json.put(KEY_CURRENT_INDEX, currentIndex);
  178. json.put(KEY_CURRENT_WEIGHT, currentWeight);
  179. try(ShardedJedis jedis = shardedJedisPool.getResource()){
  180. jedis.set(this.redisKey, json.toJSONString());
  181. }catch (Exception e){
  182. LOG.error("updateRedis error: ", e);
  183. }
  184. }
  185. public IBaseOrgDTO execute(){
  186. IBaseOrgDTO org = null;
  187. if(initStatus) {
  188. org = getOrgInfo();
  189. updateRedis();
  190. }
  191. return org;
  192. }
  193. }
  1. package com.cmbc.util;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. /**
  6. * Created by on 2018/8/13.
  7. */
  8. public class MarkByProportionUtil {
  9. private static Logger LOG = LoggerFactory.getLogger(MarkByProportionUtil.class);
  10. /**
  11. * 比例打标redis key前缀
  12. */
  13. public static final String REDIS_KEY_PREFIX = "WSDP_index&weight";
  14. /**
  15. * 比例打标redis key分隔符
  16. */
  17. public static final String REDIS_KEY_SEPARATOR = ":";
  18. public static String getRedisKeyOfCurrentWight(String dimensionCode, String channelGroupCode, String channel, int isCardHolder) {
  19. if (StringUtils.isAnyBlank(dimensionCode, channelGroupCode, channel)) {
  20. LOG.error("illegal parameters: dimensionCode:{}, channelGroupCode:{}, channel:{}", dimensionCode, channelGroupCode, channel);
  21. }
  22. /** 固定前缀 + 维度code + 渠道组code + 渠道代码 + 是否持卡人 */
  23. String key = new StringBuffer()
  24. .append(REDIS_KEY_PREFIX)
  25. .append(REDIS_KEY_SEPARATOR)
  26. .append(dimensionCode)
  27. .append(REDIS_KEY_SEPARATOR)
  28. .append(channelGroupCode)
  29. .append(REDIS_KEY_SEPARATOR)
  30. .append(channel)
  31. .append("_")
  32. .append(isCardHolder)
  33. .toString();
  34. return key;
  35. }
  36. }
  1. package com.cmbc.dto.base;
  2. /**
  3. * Created by on 2018/7/22.
  4. */
  5. public interface IBaseOrgDTO {
  6. /**
  7. * 获取机构id
  8. * @return
  9. */
  10. public abstract Integer getOrgId();
  11. /**
  12. * 获取比例
  13. * @return
  14. */
  15. public abstract Integer getProportion();
  16. /**
  17. * 获取机构类型
  18. * @return
  19. */
  20. public abstract String getOrgType();
  21. }

调用方法:

  1. /** 按比例分成 */
  2. WeightRoundRobinBo wrr = new WeightRoundRobinBo(orgList, rule, applyDetailInfo,
  3. cacheService.getShardedJedisPool());
  4. org = wrr.execute();
  5. if (null == org) {
  6. LOG.error(ErrorEnums.ERR_10013.getMsg());
  7. return ErrorEnums.ERR_10013.getMsg();
  8. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/289218
推荐阅读
相关标签
  

闽ICP备14008679号