Envision 偏技术性概述


首页 » 资源 » 此处

Envision 是一门特定于领域、专为定量的预测性供应链分析量身定制的语言。其语法与 SQL 和 Python 有若干相似之处。Lokad 提供基于云的开发环境和基于 Web 的执行环境。输入数据应以托管在 Lokad 中的表格文件形式提供,文件可为纯文本文件或 Excel 工作表。Envision 脚本输出仪表盘,也可以输出脚本中计算得出的一个或多个表格输出文件。

领域特定语言的起源

Envision 是 Lokad 多年以来与数百位零售商合作的结晶。早在 2008 年创立 Lokad 时,Envision 还未纳入我们的技术路线图。创建一门新的编程语言是一项巨大的工作,在 2008 年至 2013 年间,我们还只使用主流编程语言。随着我们的经验越来越丰富,我们意识到开发一种专门为供应链定制的语言会帮助我们大大加快定制型客户任务的开发和执行。

2014 年间,Lokad 对我们的部分内部项目使用 Envision,开始了“产品内部测试及反馈”过程。结果显而易见,使用 Envision 的计划其性能优于使用一般编程语言的替代计划,即便对顶尖的软件开发人员而言也是如此。我们并非声称 Envision 的性能更胜 C#/Java/Python/SQL/ 等一筹。但就一般情况(只是供应商中极其特殊的案例)而言,这些语言虽然很出色,但并不表明就能实现很高的商业生产力。

一门设计精良的语言的特质

我们来直面这样一个事实:绝大多数企业编程语言只勉强够称得上“垃圾级”品质。我们在设计 Envision时,决定将它设计成一门只专注于供应链的卓越语言。

语言:

  • 无循环,无分支(这的确是一项功能)
  • 键入性能出色
  • 函数调用无负效应
  • 本地代码编译
  • 借助特殊算法,执行快如闪电

开发环境:

  • 代码着色和代码自动完成
  • 智能编译器可提供有用的错误消息
  • 提供过往编辑和运行的完整版本
  • 提供输入数据的上下文浏览

在编码风格方面,Envision 的灵感主要来自语法简明的 Python,但我们也借鉴了 C# 等其他语言的一些精髓。

SQL 与 Envision 的比较

SQL 和 Envision 都具有很强的数据亲和力。SQL 侧重于查询事务处理数据模型,非常重视ACID(原子性、一致性、独立性和持久性),Envision 仅查询一组纯表格文件。实际上,就大多数商业优化挑战而言,我们并不需要“实时”数据,只需截至昨天的数据。此类数据属于“过去”的数据并且不可更改。由于不需要支持 INSERT、UPDATE 或 DELETE,只需要支持 READ,因此这类文件的处理速度比关系表快几个数量级 (1)。

在 Envision 中,可以使用与 SQL 中的 SELECT 极其相似的语句来显示表。
show table "Product List" with
Id
Name
Supplier
经验丰富的 SQL 开发人员一眼便可看出这条语句缺少 SELECT 后面常见的 FROM 部分。在供应链中,我们注意到几乎所有数据都与产品(或 SKU)息息相关,并且几乎所有数据历史记录可以作为事件描述并附加到产品上。因此,Envision 没有到处编写 JOIN 来无限重复相同模式,而是采用了"自然"联接。举个例子,下面这段脚本显示了如何在没有任何显式联接的情况下根据销售历史记录来生成畅销产品列表。
end := max(date)
// O is for Orders
LastYearQty = sum(O.Qty) when date > end - 365
show table "Top Sellers" with
Id
Name
LastYearQty
order by LastYearQty desc
在商业中我们还发现周期日历聚合非常频繁。管理员需要每天、每周或每月掌控数据;虽然这是一项基本需求,但即便是显示一个简单的每周线形图,SQL 都弄的非常复杂,而在 Envision 中只需要编写短短两行代码。
Week.quantity := sum(O.Qty)
show linechart "Weekly quantities sold" with
Week.quantity
最后,围绕 SQL 的工具强调“一次查询一项”的思维模式。但根据我们的结论,要想获得一个优良的仪表盘,通常需要结合很多特定的商业指标才能实现高效率。相比之下,Envision 脚本直截了当地“一次性”生成一个复杂仪表盘。

(1) 通过调整 SQL 数据库,确实可以实现与单纯处理平面文件相当的性能水平;但我们发现,这其中所涉及的工作几乎盖过在第一时间就引入 SQL 数据库所带来的好处。

Excel 与 Envision 的比较

Envision 虽然是一门编程语言,但高级 Excel 用户同样可以访问。我们决然未看轻 Excel:很难在性能上超越这些拥有几十年历史的表格,我们这个团队中的数据科学家和开发人员也都会频繁使用 Excel,例如使用 Excel 来整合一系列实验的结果。

Excel 的一大亮点是能够快速对整行或整列执行运算,这就是矢量计算,受复制和粘贴驱动。矢量计算非常有用,但剪切-粘贴逻辑不怎么有用。比方说我们要根据过去的交易计算过去一年中的产品均价,使用 Envision 只需编写几行代码。
O.UnitPrice = O.NetAmount / O.Qty
end := max(date)
UnitPrice = mode(O.UnitPrice) when date > end - 365
show table "Median Price" with median(UnitPrice)
第一行是矢量计算,相当于在 O(针对订单)表中引入一个名称为 UnitPrice 的新列。第三行同样也是矢量计算,其中 mode(常用观察值)表示针对每种产品进行计算。在引入中间计算以及随后构成计算式时,使用 Envision与使用 Excel 一样简明。

Envision 同样重视仪表盘的紧凑性,这与 Excel 中的合成表非常相似。Envision 中的每条 show 语句定义了一个将显示在仪表盘中的“磁贴”,这些磁贴根据类似于 Excel 的网格进行对齐。
show label "Hello World" a1d1 tomato
show table "Product Lines" a2b2 royalblue with
sum(1)
show table "Order Lines" c2b2 darkorange with
sum(O.1)
上面的脚本按照 Excel 惯例 - 即列使用字母、行使用数字,分别在 A1:D1、A2:B2 和 C2:D2 中定义了三个磁贴。

拥有无循环、无分支等诸多功能

Envision 提供的是简洁的功能性语法。没有循环、分支或 null ;您可能会好奇,Envision 并非图灵完备 的语言。实际上,这些功能统统可以忽略。Envision 只提供内置结构来实现同样的结果,但麻烦会少得多。由于 Envision 中没有此类功能,我们不仅消除了所有难以调试的问题,还大大提高了生产力。

我们不妨按照今年的每个星期来对前 10 款畅销产品的总销售量进行绘图,并将这前 10 款产品今年的每周总销售量与去年的每周总销售量进行对比。这个过程只需要编写几行代码便可以实现。
end := max(date)
Vol = sum(O.Qty) when date > end - 365
Week.amt := sum(O.Qty) where rank() sort [Vol] <= 10
show linechart "Top 10" a1f3 tomato unit: "$" with 
Week.amt as "Sold this year"
Week.amt[-52] as "Sold last year"
此外,Envision 的速度非常快,简直快如闪电。这是因为我们想方设法不但运用了许多特定于领域的算法 (2),而且还高速缓存 Envision 脚本(几乎)每个计算节点。因此,在重新执行稍微更改过的脚本时,仅重新计算计算图中更改过的节点。实际上,一旦您体验过在 5 秒之内处理 20GB 数据的感觉后,您肯定不会再想用慢得像蜗牛一样的 SQL 查询了。

(2) 我们采用桶式排序算法,其性能经常比使用一般的快速排序快 500 倍。尽管排序算法的理论最佳界限是 O(n.log(n)),但如果情况有利(例如对日期排序),将排序算法加快 500 倍是可能的。而在商业中,这方面的情形往往非常有利。