在 Envision 中建表


首页 » 资源 » 此处

在 Envision 中最常用的创建表的方式就是读取平面文件中的表。但是,Envision 也提供了创建表的功能。这些表可以在脚本中定义和例示。对于任何一种输入表都不具备特定计算所需属性的情形,创建表非常有用。


语法概述

创建表的常用语法蕴含在 tableextend 声明中,此类声明中附带语法:
table T = extend.range(Orders.42)
此处的关键字 table 不能与 show table 中的磁贴类型相混淆。之后便可以像从文件中加载的任何普通表一样,来在脚本中使用表 T
show table "Number of lines" with sum(T.1)

extend.range()

最简单的创建表的方式是使用范围扩展 extend.range():对于原始表中的每一行,会创建 N 行并进行编号。范围扩展对于在表中引入新行的情况很有用。

语法如下:
table T = extend.range(Orders.K)
T.Quantity = Orders.Quantity // implicit projection
show table "Line numbers" with T.N, T.Quantity

其参数应为整数,原始表中的上一行与下一行的数值是不同的。这样便可以控制所要引入的行数的粒度。

T 作为最初以参数形式传递的表的扩展来键入。因此,从上面的第 2 行可以看出,纯交叉表分配也是可行的,因为 T 中的每一行仍与 Orders 中的原始对应部分相关联。T.N 字段默认为已填充,该字段表示行数,从 1 开始,并按增量 +1 递增。

请注意,函数 extend.range() 可以生成任意多的行数。但首先, 生成大表可能会很慢;其次,根据您 Lokad 帐户中的配额,这个过程可能不会成功。实际上,如果 K 比平均数大 10,那么 extend.range() 可能就不是您所解决的问题的正确方法。

extend.distrib()

Envision 分布提供了强大的代数运算,借助这种运算可以不用对列表进行进行令人费解的概率计算。但是,有时原始概率列表也是可以的并且甚至是很可取的。而分布扩展 extend.distrib() 将分布向量转变成了一个表,语法如下:

table T = extend.distrib(D)
show table "Distribution details" with Id, T.Min, T.Max, T.Probability
参数 D 的预期输入为分布向量,此类向量通常由 Lokad 的概率预测引擎生成。表 T 作为原始表(即上面这段脚本中的隐式 Items 表)的扩展键入。表 T 中填充了这三个字段:

  • T.Min:此段的整数下限(包含在内)
  • T.Max:此段的整数上限(包含在内)
  • T.Probability:所含范围的分布之和

虽然字段的名称为 Probability,但返回的其实是桶范围内的分布之和。

对于相对紧凑的分布,段的长度为 1,因此 T.Min == T.Max。但是,如果分布延续到更大的值,长度为 1 的段可能会产生数百万行,因而变得无法管理。所以,在面对较大值的分布时,Envision 会自动围绕较大的段来聚合分布。相关算法会进行调整,以保持所生成表的大小可以管理。

按照设计,extend.distrib() 总是会选出长度为 0 的段。因此,段 [0;0] 总是在生成的表中得到其自身的行。这种行为对于许多边缘案例中需求为 0 的业务情形(例如无限的存货保证期)其实很有帮助,这种情况下需要采用某些专用的逻辑。

此外还针对 extend.distrib() 提供了三个过度加载,目的是对所生成表的具体粒度进行进一步控制。

差距

第一个过度加载的用意,是在考虑当前库存水平时帮助构建采购优先级列表。其语法如下:
table T = extend.distrib(D, S)
第一个参数 D 的定义如上所示。第二个参数 S 的输入应为整数。在提供有第二个参数的情况下,所生成的表总是包含两行,这两行专门用于 [0;0] 和 [1;S] 这两个段。其他段则是自动生成,并从 S+1 开始,上面进行了详细说明。此参数未指定时的默认值为 0。

参数 S 通常定义为可用存货与订购存货之和。在进行再订货时,实际上只会考虑超出当前库存水平的需求概率。

倍数

第二个过载面向涉及批次倍数的情形。在这些情形中,此表应当对特定大小的段进行迭代。其语法如下:
table T = extend.distrib(D, S, M)
参数 DS 的定义如上所示。第三个参数 L 的输入应为整数。它表示所需的段长。因此,此表包含段 [0;0], [1;S], [S+1;S+M] [S+M+1;S+2M] … 的列表。如果 L 为 0,则此函数会回到自动调整段大小的状态。

强制段长为 1 可能会导致性能问题,因为表的大小可能会任意大。因此,Envision 可以退而求其次,即改为使用一个叫做 M倍数。通过使用倍数,可以确保批次倍数逻辑正常工作;同时又能对所生成的行数施加同样的限制。

根据经验,我们建议不要使用这种过载,除非是涉及到批次倍数;当涉及批次倍数时,建议将所有不具备特定批次倍数的项目的 M} 保持为 0。

达到特定值

第三个过载针对涉及MOQ的情形。在这些情形中,表应当进行足够长的迭代,以便达到所需的特定值。相关语法为:
table T = extend.distrib(D, S, M, R)
上面定义了参数 DSM。第四个参数 R 应为非负整数。它表示网格所要达到的最大值,也即在某一行中,T.Max 要大于或等于 R。未指定此参数时,其默认值为 0。

实际上,此参数用于处理较大的最小订单量 (MOQ) 限制,而这一点只有在生成的表进行足够长的迭代从而覆盖 MOQ 值时才回满足。

根据经验,我们建议不要使用此过载,除非是要达到 MOQ;在涉及 MOQ 时,建议 R 尽量小。较小的 R 值不会阻止表 T 达到较高的值,只会确保达到较大的值。

extend.billOfMaterials()

物料清单涉及到关注点不在所售或所服务的项目上,而在于其部件或组成的情形。对于这些情形,最好将“项目”级别的需求历史记录转换为“部件”级别的需求历史记录。转换过程由指定各个项目组成的物料清单来控制。

调用函数 extend.billOfMaterials() 精准地涵盖了这种使用情况,如下所示:
table T = extend.billOfMaterials(
  Item: J.Id
  Part: B.PartId
  Quantity: B.Quantity
  DemandId: O.OrderId
  DemandValue: O.Quantity)

T.DemandDate by T.DemandId = same(O.Date) by O.OrderId // illustrate how to get the date

show table "Details" with Id, T.DemandDate, T.Quantity
应当有 JBO 这三个表。表 J 通常为项目表,但这一点并非硬性规定。表 B 拟作为物料清单表;其预期输入应为表 J 的扩展,即 J 刚好为项目表时,其类型为 (Id, *)。表 O 预计为需求历史记录,通常为订单表。表 O 也应为表 J 的扩展。

最后得到的表就是表 J 的扩展,其中存在适当的仿射性。表 T 包含两个字段,其中已填充如下值:
  • T.DemandId,用于在表 T 中提供一种识别表 O 中原始行的方式。
  • T.Quantity,此值通过转出物料清单获取。

将日期注入表 T 常常比较有用。这个过程可以通过 left-by 语句来完成,如上文 billOfMaterials() 块下面的行所示。

函数 extend.billOfMaterials() 支持递归部件,即一个项目既可以在表 B 中作为组件出现,也可以作为捆绑包出现。如果在物料清单表中发现循环相关性,该函数自然会失败。

参数 Quantity 表示 B.PartId 的单元数。在销售或维修标示有 {{J.Id
的部件时,会涉及到这一点。