首页 > 应用开发 > IT综合 > 递归算法实践--到仓合单助力京东物流提效增收
京东物流到仓业务「 对商家」为了减少商家按照京东采购单分货备货过程,对齐行业直接按照流向交接,提升商家满意度;「 对京东」揽收操作APP提效;到仓合单功能应运而生;
一次批量采购单(一次50或者100个采购单)需要根据不同的规则合并成多个订单;
每一个采购单可以是不同的来源类型(自营和非自营)、不同的收货类型,每一个采购单会有多个SKU,同一个SKU只有一个等级,一批采购单会有多个SKU,同一个SKU会有多个等级;
递归算法是一种通过重复将问题分解为同类的子问题来解决问题的方法; 特点是函数或子程序在运行过程中直接或间接调用自身;常见的递归算法包括Fibonacci函数、Hanoi问题和阶乘计算等;
/**
* 指定不同等级不能合单
*
* @param poNoSet 采购单号Set
* @param poMainInfoMap 采购单详情
* @param calculatedSet 计算过的采购单据列表的集合
* @return
*/
private List<Set<String>> doMergeClassDifferent(Set<String> poNoSet, Map<String, PoOrderFacadeResponse.PoMainInfo> poMainInfoMap, Set<String> calculatedSet) {
// 如果该set已经计算过则不重复计算
List<Set<String>> resultList = new ArrayList<>();
String calculatedPoNoKey = buildCalculatedPoNoKey(poNoSet);
if (calculatedSet.contains(calculatedPoNoKey)) {
return resultList;
} else {
calculatedSet.add(calculatedPoNoKey);
resultValue.incrementAndGet();
}
// 以sku为key的集合
Set<String> skuSet = new HashSet<>();
// 以sku 为key, 值为poNos
Map<String, Set<String>> skuMap = new HashMap<>();
// 存放同一个sku下有多少个不同等级的集合
Map<String, Set<String>> skuToskuLevelMap = new HashMap<>();
// 以sku+level 为key的集合
Set<String> skuLevelSet = new HashSet<>();
// 以sku+level 为key, 值为poNos
Map<String, Set<String>> skuLevelMap = new HashMap<>();
for (String poNo : poNoSet) {
PoOrderFacadeResponse.PoMainInfo poMainInfo = poMainInfoMap.get(poNo);
// 采购单条目
List<PoOrderFacadeResponse.PoItemInfo> poItemInfos = poMainInfo.getPoItemInfos();
for (PoOrderFacadeResponse.PoItemInfo poItemInfo : poItemInfos) {
String skuKey = poItemInfo.getGoodsNo();
String skuLevelKey = buildSkuLevelKey(poItemInfo);
skuSet.add(skuKey);
setKeyMap(skuKey, skuMap, poNo);
// 存放同一个sku下有多少个不同等级的集合
Set<String> stringSet = skuToskuLevelMap.get(skuKey);
if (CollectionUtils.isEmpty(stringSet)) {
stringSet = new HashSet<>();
skuToskuLevelMap.put(skuKey, stringSet);
}
stringSet.add(skuLevelKey);
skuLevelSet.add(skuLevelKey);
setKeyMap(skuLevelKey, skuLevelMap, poNo);
}
}
if (skuSet.size() == skuLevelSet.size()) {
// 此处sku的数量和sku+level的数量相同,不需要再进行递归运算
// 方法结束的出口
resultList.add(poNoSet);
return resultList;
} else {
// 同一个sku下最多等级个数
int high = MagicCommonConstants.NUM_1;
// 最多等级个数的对应sku
String maxLevelSku = "";
for (String sku : skuToskuLevelMap.keySet()) {
Set<String> strings = skuToskuLevelMap.get(sku);
if (strings.size() > high) {
high = strings.size();
maxLevelSku = sku;
}
}
if (high > MagicCommonConstants.NUM_1) {
// 获取该sku下的poNos
Set<String> strings = skuMap.get(maxLevelSku);
// 差集
Set<String> chaJiSet = poNoSet;
chaJiSet.removeAll(strings);
Set<String> skuLevels = skuToskuLevelMap.get(maxLevelSku);
for (String skuLevel : skuLevels) {
Set<String> poNoTempSet = skuLevelMap.get(skuLevel);
poNoTempSet.addAll(chaJiSet);
// 递归计算
List<Set<String>> clist = doMergeClassDifferent(poNoTempSet, poMainInfoMap, calculatedSet);
if (CollectionUtils.isNotEmpty(clist)) {
resultList.addAll(clist);
}
}
}
}
return resultList;
}
/**
* 去重 合单之后的采购单号
*
* @param sets
* @param dooModel
*/
private List<Set<String>> uniqueRepeatPoNo(List<Set<String>> sets, DooModel dooModel) {
sets.sort(new Comparator<Set<String>>() {
@Override
public int compare(Set<String> o1, Set<String> o2) {
return o2.size() - o1.size();
}
});
List<Set<String>> resultList = new ArrayList<>();
Set<String> allMergedSet = new HashSet<>();
Set<String> allSet = new HashSet<>();
for (Set<String> set : sets) {
Set<String> tempSet = new HashSet<>();
for (String poNo : set) {
if (!allSet.contains(poNo)) {
tempSet.add(poNo);
allMergedSet.add(poNo);
}
}
if (!tempSet.isEmpty()) {
if (tempSet.size() > 1) {
allSet.addAll(tempSet);
resultList.add(tempSet);
}
// 此处的单条后面不一定不能合单
}
}
// 差集
allMergedSet.removeAll(allSet);
if (allMergedSet.size() > 0) {
for (String poNo: allMergedSet) {
putPoNoToSet(dooModel, poNo);
}
}
return resultList;
}
目前上线之后刚推广,功能上线45天,已经在浙江、 河南、上海、江苏、安徽、天津、四川、北京22个客户使用,增收500万整体运营平稳,且在大促期间合单收货功能优势更加凸显:「对商家」减少商家按照京东采购单分货备货过程,对齐行业直接按照流向交接,商家满意度提升。「对京东」 揽收操作APP提效30%,分货、入库交仓效率提升10%,整体TC转运效率更快;
难点:将根据SKU分堆之后剩下的采购单分别加到不同的分堆中,这个方案也是思考了好久之后想到的,然后构造成递归进行计算,最终进行去重;
性能:递归算法中大部分计算都是重复的,但是经过记录中间计算结果,将计算过的采购单集合直接剪枝,计算时间就不会随着采购单的数量增长而指数增长,真实情况也是随着单据数量的增加、SKU和等级的种类增多依然健壮;
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70037994/viewspace-3098915/ ,如需转载,请注明出处,否则将追究法律责任。