共计 4180 个字符,预计需要花费 11 分钟才能阅读完成。
作者:京东物流 柳宏
1. 前置常识
1.1 基本概念
1.1.1 配载
- 配载代表着某条线路是否具备发往某个方向(区域、省市县、分拣等)的能力,也能够说是网点(分拣核心)是否具备承载配载所指方向货物的能力。个别网络规划者,在平衡线路间货量时,会通过调整配载来实现。
- 线路上可容许配载货物的“产品类型、最终妥投目的地”,通过线路的配载,计算 以后网点 到 目标网点 的 下一个网点,线路 绑定的配载代表通过以后线路最终能够达到的目的地。以下图为例
- 示意:如果搁置在整个路由网络资源中,一个标记 T1 的货物要从北京发往福建,可选的路由有①北京站 - 北京 - 武汉 - 福建 - 福建站;②北京站 - 北京 - 广州 - 福建 - 福建站;之所以剔除了北京站 - 北京 - 上海 - 福建 - 福建站以及北京站 - 北京 - 武汉 - 上海 - 福建 - 福建站,正是因为后两条线路中未蕴含 T1 的配载代码,只标记了 T2 , 阐明这条线路只有配载航空的货物,而没有一般陆运的带货能力。
- 下图就是用于形容配载的树形构造
1.1.2 班期与生生效日期
- 班期:指的是发运频率,1234567 代表着每周七天中,这个班次的“上线工夫”,一般来讲,保护时缺失某个值,会造成路由中断的景象。
- 生生效日期:指的是该配载无效工夫范畴
1.1.3 配载合并逻辑
- 网点四级地址的关系以配载树的模式展示,勾选节点增加的配载在右侧的配载列表中展现
- 当某个节点的子节点没有全副勾选时,展现以后勾选的节点到配载列表中
- 当某个节点的子节点全副勾选时(在合乎相干条件时,这里波及到的算法逻辑前面详述),展现相应的父节点到配载列表中,这个逻辑是递归的
1.2 现有实现技术
•目前的线路配载前端基于 zTree+FixedHeaderTable+JQuery 实现,通过 zTree 监听节点被选中和勾销选中,计算该操作后是否触发节点的合并或开展,进而从新渲染配载列表中的数据
2. 现状问题
2.1 节点合并算法逻辑有误
- 如果一个父节点下的所有子节点都被保护,即便子节点下的 班期 不同、生生效日期 不重叠,零碎都会主动合并到父节点。合并的展现成果为:
- 班期:对于纯新增配载显示 1234567;对于父节点下有一个子节点,班期显示为已存在配载的班期
- 生生效工夫:对立为该切段线路的生生效日期
- 例如:X 线路被切割成两段,2022-11-02~2023-01-25 以及 2022-01-26~ 短暂无效两段,在线路视图点击 2022-11-02~2023-01-25 这段的配载保护,X 下有 A1(配载工夫为 2022-11-02~ 短暂无效、班期 12),其父节点为 A,A 下还有子节点 A2、A3。明天是 11.17 日,将 A2、A3 都勾选上(工夫任意,班期为 12345),配载会立即合并为 A(失效工夫 2022-11-02~2023-01-25,配载 1234567)
线路 X
失效工夫 生效工夫
2022-11-02 2023-01-25
A(父节点):蕴含 A1、A2、A3 三个子节点,以后只存在 A1 的配载如下:失效工夫 生效工夫 班期
A1 2022-11-02 2099-12-31 12
参考日期为 11.17 日,此时勾选 A2+A3 后触发 A 的合并,此时配载列表展现 A 节点
失效工夫 生效工夫 班期
A 2022-11-02 2023-01-25 1234567
2.2 配载保留和显示的值不统一
- 下面操作触发合并,提交后库中保留的配载记录为:
失效工夫 生效工夫 班期
A1 2022-11-02 2022-11-16 12
A 2022-11-17 2023-01-25 1234567
2.3 实质起因
- 原有依据 zTree 节点触发合并的算法有问题,不思考以后节点下其余子节点的配载的班期和生生效日期,而是依据是否同一个父节点间接合并。导致合并逻辑谬误,保留与展现的数据不统一。
3. 预期成果
3.1 配载合并班期逻辑
- 条件:同一个父节点 + 各个子节点班期统一
A(父节点):蕴含 A1、A2、A3 三个子节点,其中任意节点的班期不统一都无奈合并
3.2 配载生生效日期切断逻辑
- 新增加节点,失效日期 为 参考日期,生效日期 为 线路生效日期
- 参考日期抉择 大于 以后 同级子节点的某天,当触发合并时
- 合并后的父节点:失效日期取 参考日期 ,生效工夫取 同级子节点列表中生效工夫最小的
- 合并后的子节点:
1)如果 原始失效日期 小于 合并后 父节点的失效日期,则切断 原始失效日期 ~ 父节点的失效日期 - 1 天(相当于保留切断前的失效日期那一段)
2)如果 原始生效日期 大于 合并后 父节点的生效日期,则切断 父节点的生效日期 +1 ~ 原始生效日期(相当于保留切断前的生效日期那一段)
- 针对同一个节点的配载生生效日期切断的逻辑,举例
1. 配载 A 的原始生生效工夫为 20221103 - 20221110
2. 配载 A 在通过同级子节点合并后,生生效工夫为 20221105-20221108
3. 那么对于配载 A 来说,在合并后依然须要保留两段配载记录
3.1 生生效工夫为 20221103-20221104
3.2 生生效工夫为 20221109-20221110
3.3 配载合并后保留逻辑
•采纳所见即所的形式保留数据,用户在前端实现切断操作后,保留到数据库的记录与前端展现统一
4. 实现逻辑
4.1 整体逻辑
4.2 定义数据结构及初始化
zTree:配载树
treeNode:配载树中的节点
nodeId:节点 id
childrenNodes:蕴含以后节点的所有子节点汇合
stowageList:配载列表的 Dom 构造
originStowageMapTI:原始配载:{key:节点;value:配载数据的 dom 构造}
newStowageMapTI:新增节点配载:{key:节点 id;value:节点}
stowageFrequencyMap:配载节点和班期关系:{key:节点 id;value:班期}
stowageTimeMap:配载节点和生生效日期关系:{key:节点 id;value:[失效工夫,生效工夫]}
frequencyTreeMap:班期和节点的关系:{key:班期;value:节点数组}
node.pid:节点的父 id
node.id:节点的 id
在配载树上监听事件,当触发选中 / 勾销选中时,递归的获取 childrenNodes
保护配载与班期、配载与生生效日期的关系
将已有配载列表中的数据保护到 stowageFrequencyMap、stowageTimeMap、originStowageMapTI 中
4.3 配载合并班期逻辑
1)如果以后节点非禁用 && 勾选 执行 合并逻辑;否则递归遍历节点;最终返回后果集
2)如果以后节点非半选 && 非父节点,向父节点中查找班期,保护节点属性,退出后果集并返回
3)依据节点的 pid 查找 stowageFrequencyMap 中是否存在班期
配载树中的网点关系次要是四级,举例说明 C(快递全国) 上面某些节点的 level 与 pid 的关系
level=1
pid:C 示意全国
level=2
pid:C-10 示意华南
level=3
pid:C-10-16 示意福建
level=4
pid:C-10-16-1303 示意泉州
算法逻辑:依据 pid 截取相应的字符串为 key,查找是否存在父节点的班期
1. 如果是父节点则遍历,依照每个子节点去 stowageFrequencyMap 中获取班期,分为两种状况如下;找到班期后保护 frequencyTreeMap,将同班期的节点保护到 list 中保留,即造成 班期 - 节点 list 的数据结构
2. 向父节点中获取班期,同上
3. 向子节点中递归获取班期,并将后果保留到新的数据结构 frequencyChildMap 中,而后合并到 frequencyTreeMap 中
对 frequencyTreeMap 汇合进行判断,如果数量为 1 示意 与该节点同级的节点班期雷同,触发了合并,将节点退出后果集返回;否则 阐明以后节点的同级节点存在不同班期,不能进行节点向上合并,间接遍历 frequencyTreeMap 中的 value 汇合,退出后果集返回
对于触发了合并的后果集 frequencyTreeMap 中的每个节点遍历 同 以后线路的生生效日期比拟,取出同级节点中的 最大失效工夫 , 最小生效工夫 , 作为该同级节点中的最大公共工夫范畴 设置到每个节点属性中
4.4 配载生生效日期切断逻辑
定义变量
1. queryTime:参考日期
2. maxDisableTime:最大生效工夫
3. enableTime:线路失效工夫
4. disableTime:线路生效工夫
5. originEnableTime:记录原始失效工夫
6. originDisableTime:记录原始生效工夫
7. newDisableTime:enableTime - 24 * 60 * 60 * 1000
8. newEnableTime:disableTime + 24 * 60 * 60 * 1000
循环遍历每个后果集中的节点,判断是否渲染到配载列表中
依据以后节点 id 判断是否存在于 stowageList 中,如果存在间接显示;依据节点 id 删除 originStowageMapTI 汇合
更新生生效日期,别离判断 原始配载中是否存在须要切断的日期,新增加配载中是否存在须要切断的日期;而后将以后节点增加到配载列表中
- 遍历 originStowageMapTI,判断历史的配载节点是否须要进行日期切断,分为以下两种状况;而后依据节点 id 删除 originStowageMapTI
- 如果 originEnableTime < enableTime:增加新的配载记录,失效工夫取 originEnableTime,生效工夫取 newDisableTime
- 如果 originDisableTime > disableTime:增加新的配载记录,失效工夫取 newEnableTime,生效工夫取 originDisableTime
- 遍历 newStowageMapTI,判断新增加的节点是否须要进行日期切断;而后依据节点 id 删除 newStowageMapTI
- 如果 originDisableTime > disableTime:增加新的配载记录,失效工夫取 newEnableTime,生效工夫取 originDisableTime
5. 总结
•路由线路配载保护业务外围且频繁应用性能,为了实现业务述求,将齐全没有关联的 树形构造 和Dom 列表 联合在一起。采纳了 多种数据模型 + 数据结构的组合 模式,结构两者之间的关系,联合 遍历、深度优先搜寻、字符串查找 等算法进行实现,在春节串点优化专项上线后获得了预期的收益。