0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

递归算法实践--到仓合单助力京东物流提效增收

京东云 来源:京东物流 李硕 作者:京东物流 李硕 2025-01-09 14:57 次阅读

作者:京东物流 李硕

一、背景

京东物流到仓业务「对商家」为了减少商家按照京东采购单分货备货过程,对齐行业直接按照流向交接,提升商家满意度;「对京东」揽收操作APP提效;到仓合单功能应运而生;

二、问题

一次批量采购单(一次50或者100个采购单)需要根据不同的规则合并成多个订单;

每一个采购单可以是不同的来源类型(自营和非自营)、不同的收货类型,每一个采购单会有多个SKU,同一个SKU只有一个等级,一批采购单会有多个SKU,同一个SKU会有多个等级;

合单规则:

1.自营和非自营不能合;

2.实物收货和单据收货的采购单不能合并;

3.相同收获仓和配送中心的采购单可以合并;

4.两个采购单如果合并之后同一个SKU拥有多个等级,则不可以合单;

三、打法

A、思路

1.首先认为这一批单子可以合单,后续就是根据合单规则将不符合规则转换成拆单的过程;

2.根据合单规则1、2、3可以将这一批单子拆成多个需要执行规则4的待合单集合List;

3.举个极端例子,规则1、2、3这些采购单都是相同的,则该List数量为1,这100个单子进行后续根据SKU+等级维度的合单;

4.由于相同SKU不同等级不可以合单,我们可以先找出这100个采购单中包含最多等级的SKU,比如skuA 包含最多的7个等级, 根据skuA进行按等级进行分堆,分成7堆之后,由于并不是所有的采购单都包含skuA, 则这100个采购单可能还会剩下一些单子不在这7堆之内,也就是剩下的这些单子如果只是基于skuA维度进行分堆,可以跟这7堆任何一堆进行合单,这时候需要将这些剩下的单子分别加入到这7堆里面,得到第一次合单后的结果,这里很重要,也是纳入递归算法的基础;

5.得到的7堆再分别进行第四步的操作,直到当前这一堆的sku不包含不同等级为止(这里是递归结束的条件);

6.由于分堆里面包含了重复的订单,所以有些单子组合会被重复计算,这时候需要维护一个列表将计算过的单据进行保存,这样可以将重复的列表进行剪枝,这样可以保证整个算法的时间复杂度不是指数级增长;

7.针对最终全部递归之后的结果将合单的列表进行由多到少进行排序,然后进行排重,这里如果排重之后只有一个采购单了可以先释放,但不要加到排重列表里面,因为后面可能还会出现可合并的集合,很重要,不然得到的合单结果会变少,得到最终的合单后的结果;

B、算法

‌‌递归算法是一种通过重复将问题分解为同类的子问题来解决问题的方法‌; 特点是函数或子程序在运行过程中直接或间接调用自身;常见的递归算法包括‌Fibonacci函数、‌Hanoi问题和‌阶乘计算等;

C、解决方案

1. 递归代码块

/**
 * 指定不同等级不能合单
 *
 * @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;
}

2. 去重代码块

/**
 * 去重 合单之后的采购单号
 *
 * @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和等级的种类增多依然健壮;

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4622

    浏览量

    93058
  • 递归
    +关注

    关注

    0

    文章

    29

    浏览量

    9038
收藏 人收藏

    评论

    相关推荐

    京东双十一“无人”首度曝光 无缝结合全程无人值守

    10月26日消息,双11大促海量订单产生的物流环节巨大压力,不仅是物流行业面临的难题,更会影响消费者的购物体验。今天早些时候,京东X事业部智慧物流实验室第一次揭开神秘的面纱,展现了由机
    发表于 10-27 11:34 1562次阅读

    JD双十一“无人”首度曝光,完全自动化操控全程无人值守,过程太流弊了!

    大载荷量和±0.05mm高精度的特点。名词解析:京东“无人”“无人”是京东自主研发的定制化、系统化整体物流解决方案,掌握了核心智慧
    发表于 10-27 11:31

    2017年京东智慧物流黑科技视频曝光!

    科技范儿的说法,就是京东智慧物流系统收到了你的订单指令,指挥无人各位物流机器人“机不停蹄”的忙碌起来——拣货、贴标签、分拣、集货,再到自动装上无人传站车。无人传站车在智能分拣系统的指
    发表于 02-17 15:38

    LabVIEW中使用递归算法

    LabVIEW中使用递归算法LabVIEW支持递归吗?如何在LabVIEW中创建递归的VI?LabVIEW确实支持递归。按照下面的步骤来创建
    发表于 04-17 20:11

    递归算法的设计模式与调试

    文中提出一种通用递归算法的设计模式,并结合实例说明该模式的应用方法和有效性,为研究递归算法提供了有效的解决方案,可推广性强。同时给出了递归
    发表于 11-03 15:04 24次下载

    不止无人机 京东欲将“物流无人化”演绎极致?

    京东物流业务连续五年的亏损一直令业内浮想联翩,然而京东却一直顶着压力不断地曝出以京东无人机为代表的黑科技来建立独有的物流模式。难道
    发表于 11-26 11:35 788次阅读

    科捷物流联手深圳极智能,打造首个立体高密度机器人智能

    据报道,近日,神州控股旗下科捷物流位于北京平谷的BotHive Systems标杆试验正式启动。科捷物流与深圳极智能有限公司合作,应用BotHive Systems技术,采用“货
    发表于 08-31 15:42 1117次阅读

    京东全国规模最大的机器人群投入使用 不同层级无人数量达到50个

    11月8日,京东物流公布数据显示,今年11.11全球好物节期间,京东全国规模最大的机器人群已经投入使用,不同层级的无人数量达到50个,分
    发表于 11-09 10:26 2103次阅读

    机器人融入正是京东无人的重要特色之一

    京东正着力打造的智慧物流中心里,从入库、在库拣货、分拣、装车的完整过程都无需人力参与,让库房拥有极高的效率和出色的灵活性。负责京东智慧物流
    发表于 11-12 11:50 1355次阅读

    C++的实验教程之函数的递归算法资料免费下载

    函数的递归算法 1.范例:求组合数, 一、实验目的1. 学会解决简单的递归算法。2. 掌握函数的嵌套调用。
    发表于 01-29 10:51 2次下载
    C++的实验教程之函数的<b class='flag-5'>递归</b><b class='flag-5'>算法</b>资料免费下载

    物流业是物联网的最佳应用场景,京东再刷新纪录

    谈到物流行业的物联网应用及京东的物联网发展情况,申元庆表示:“我们知道物流是物联网最佳应用场景之一。今年618购物节,我们京东交出了非常棒的成绩
    的头像 发表于 08-26 15:45 3799次阅读

    从“敲锣人”看京东物流IPO后的“新谋略”

    /股,较发行价40.36港元上涨 14.1%,总市值约为2805亿港元。 京东配一体物流体系从“自给自足”“改革开放”再到“全面开放”,用了10年: 2007年,
    的头像 发表于 05-29 09:27 2349次阅读

    如何求递归算法的时间复杂度

    那么我通过一道简单的面试题,模拟面试的场景,来带大家逐步分析递归算法的时间复杂度,最后找出最优解,来看看同样是递归,怎么就写成了O(n)的代码。
    的头像 发表于 07-13 11:30 2279次阅读

    如何求递归算法的时间复杂度

    相信很多同学对递归算法的时间复杂度都很模糊,那么这篇Carl来给大家通透的讲一讲。
    的头像 发表于 07-13 11:33 1624次阅读

    京东物流与锐捷网络合作再深化,共启智慧物流新纪元

    转型。 基于双方合作的坚实基础,京东物流将在物流领域,依托自身在物流管理上的专业知识和丰富经验,为锐捷网络提供包括物流运输服务、
    的头像 发表于 10-29 16:04 167次阅读
    <b class='flag-5'>京东</b><b class='flag-5'>物流</b>与锐捷网络合作再深化,共启智慧<b class='flag-5'>物流</b>新纪元