逻辑数仓如何搞?试试 SPL!
逻辑数据仓库技术允许用户在不搬迁原始数据的前提下将多种异构数据源进行逻辑上的融合,对外表现成数据仓库。逻辑数仓可以解决传统数仓数据搬迁导致的数据链路过长无法响应实时数据处理需求的问题,能够很好满足业务迭代较快的场景。逻辑数仓具备跨源计算的能力,但本身通常无物理存储,在实现时需要将各个数据源数据映射成SQL表,从而实现多数据源混合计算。
逻辑数仓的概念和使用场景没什么问题,但实现方式有待商榷。目前大多数逻辑数仓对外接口仍然是 SQL,这是因为传统数仓本身几乎都是 SQL 的,逻辑数仓自然也是如此。这样的好处在于通用,可以降低学习和应用门槛。
但是,SQL 会造成逻辑能力偏弱,也就是多样性数据源支持不足。
和物理数仓不同,逻辑数仓要面对更多样的数据源,很多数据源由于不满足数据仓库(SQL)的约束,并不合适映射成 SQL 表,也没有一个入库动作将数据规整到满足约束(物理数仓有这个过程就可以不用面对多样性数据源,而逻辑数仓需)。这会导致逻辑数仓对多样性数据源支持不足。一般来讲,如果是 RDB 类数据源还好,但像 NoSQL、Webservice、JSON 等多层数据结构,支持起来就比较费劲了,还有文件系统等五花八门的数据源种类就更差一些。事实上,现在的逻辑数仓大部分只能对 RDB 支持得较好(仍然有较多限制),其他类型的数据源支持力度很弱。
多样性数据的支持不足还表现在功能方面。我们之所以使用多种数据源,是因为不同数据源有不同的能力可以适应不同的应用场景。我们知道,即使是 RDB,不同数据库还会存在一些语法差异,也就是数据库各自的方言,这些方言并不是凭空捏造,而是为了发挥自身的特殊能力。逻辑数仓在基于这些数据库运算时除非能够兼顾所有方言(显然不太现实),否则就会出现很多数据库的(方言才能体现的)能力用不上的情况。非 SQL 数据库这种问题就更严重,像 Mongodb 如何过滤,语法跟 SQL 相差就太大了。正常来讲,除了自动翻译机制,还应该提供直接使用数据源语法的能力,但 SQL 显然做不到。
另一方面,逻辑数仓的物理能力普遍也比较差。
从各类数据源读取数据还会面临性能问题。数据量小的时候还可以临时读取,数据量大了,IO 成本就很高,临时读取的性能会低到无法容忍。为了保证计算性能,逻辑数仓通常会提供一定的物理计算能力(物化存储),但由于历史积累等因素,逻辑数仓在适应性存储以及相关的计算性能上与传统物理数仓还有很大差距。
逻辑数仓本质上应该是物理数仓增加逻辑能力,物理计算能力是根本,单纯的逻辑数仓可用性很差(只适合小数据低性能场景)。同时,逻辑数仓还应该具备更加开放灵活的能力,除了可以连接数据源进行混合计算,还可以根据计算场景充分利用(发挥)不同数据源自身的优势。
而现在的尴尬是:逻辑数仓的物理计算能力差,而物理数仓的逻辑数据源能力差。我们需要二者的有机结合。
基于这些因素,使用 SPL 实现逻辑数仓是更好的选择。
SPL 实现逻辑数仓
SPL 是一个开源计算引擎,具备足够开放的计算能力,能够融合多种类型的数据源进行混合计算,由于本身提供了强大的物理计算能力,以及高性能保障机制,加上逻辑跨源计算能力就完全实现了逻辑数仓。
逻辑数据源能力
SPL 目前可以对接几十种数据源,而且不仅限于 RDB,还有 NoSQL,CSV、Excel 文件,JSON、XML 数据,HDFS、Elasticsearch、Kafka 等统统支持。
SPL 对接这些数据源时,不把数据源映射成数据库表,而是把数据源看成序表(小数据)和游标(大数据),如何生成序表 / 游标是数据源自己的事情(所有数据源都会提供这种接口,却未必也不可能提供统一语法的 SQL 访问接口),这样就可以充分利用数据源本身的能力。
SPL 基于这些数据源进行混合跨源计算很简单。比如常见的跨库计算场景(跨异构库混合计算),用 SPL 来做:
A |
|
1 |
=oracle.query("select EId,Name from employees") |
2 |
=mysql.query("select SellerId, sum(Amount) subtotal from Orders group by SellerId") |
3 |
=join(A1:O,SellerId; A2:E,EId) |
4 |
=A3.new(O.Name,E.subtotal) |
在这个例子中,SPL 并没有取出 MySQL 中的全部原始数据,而是先用 SQL 做了一次分组汇总,经过这样的操作,Orders 大表的数据量会显著降低,再通过接口(如 JDBC)取出 IO 效率会高很多。
前面说过,SQL 翻译会面临方言问题导致数据库很多功能发挥不了作用。SPL 也提供了类似的翻译功能,可以将标准 SQL 翻译成对应的数据库语句。但更重要的是,SPL 支持直接使用数据源的语法,这样无论是 SQL 库的方言、还是非 SQL 数据源都可以直接使用自身的语法,达到发挥自身优势的效果。
除了跨库,SPL 还可以进行任意类型数据源间的混合计算。比如有时将冷数据存放到文件系统会更便宜,使用灵活度(如随意冗余)也高,而热数据还在数据库中,这时要进行全量实时查询就可以这样做:
A |
||
1 |
=cold=file(“/data/orders.ctx”).open().cursor (area,customer,amount) |
/ 冷数据从文件系统(昨天及以前的数据 |
2 |
=hot=db.cursor(“select area,customer,amount from orders where odate>=?”,date(now())) |
/ 热数据从生产库中取,今天的数据 |
3 |
=[cold,hot].conjx() |
|
4 |
=A3.groups(area,customer;sum(amout):amout) |
/ 混合计算实现 T+0 |
SPL 还能够融合除了 RDB 以外的其他数据源,尤其是对多层数据结构提供了良好支持。这样可以很方便处理 Web 接口、IoT 以及 NoSQL 中的数据。比如 SPL 读取 JSON 多层数据与数据库关联查询:
A |
||
1 |
=json(file("/data/EO.json").read()) |
JSON数据 |
2 |
=A1.conj(Orders) |
|
3 |
=A2.select(Amount>1000 && Amount<=3000 && like@c(Client,"*s*")) |
条件过滤 |
4 |
=db.query@x(“select ID,Name,Area from Client”) |
数据库数据 |
5 |
=join(A3:o,Client;A4:c,ID) |
关联计算 |
同样 MongoDB 等 NoSQL 也可以:
A |
|
1 |
=mongo_open("mongodb://127.0.0.1:27017/mongo") |
2 |
=mongo_shell(A1,"test1.find()") |
3 |
=A2.new(Orders.OrderID,Orders.Client,Name,Gender,Dept).fetch() |
4 |
=mongo_close(A1) |
5 |
=db.query@x(“select ID,Name,Area from Client”) |
6 |
=join(A3:o, Orders.Client;A4:c,ID) |
再比如 RESTful 数据与文本数据混用:
A |
||
1 |
=httpfile("http://127.0.0.1:6868/api/getData").read() |
RESTful数据 |
2 |
=json(A1) |
|
3 |
=T(“/data/Client.csv”) |
文本数据 |
4 |
=join(A2:o,Client;A3:c,ClientID) |
关联计算 |
到这里我们已经能看出来,SPL 提供了独立的计算能力,这个能力无关数据源,但仍可以利用数据源自身的能力,用户可以决定计算到底在源端还是逻辑仓(SPL)中实施,这是 SPL 的灵活之处。
物理计算能力
前面我们举了几个简单的例子说明了 SPL 融合多数据源的能力,SPL 还提供了强大的物理计算能力。
SPL 提供了专业的结构化数据对象序表,并在序表的基础上提供了丰富的计算类库,从而使得 SPL 具备了完善且简单的结构化数据处理能力。
比如部分常规计算:
Orders.sort(Amount) // 排序
Orders.select(Amount*Quantity>3000 && like(Client,"*S*")) // 过滤
Orders.groups(Client; sum(Amount)) // 分组
Orders.id(Client) // 去重
join(Orders:o,SellerId ; Employees:e,EId) // 连接
有了过程化和序表的支持,SPL 就可以完成更加丰富的运算。比如对有序运算的支持 SPL 就更为直接和彻底。还有分组运算,SPL 可以保留分组子集,即集合的集合,这样可以很方便完成我们分组后对分组结果的进一步操作。SPL 语法相较 SQL 有很多不同,确切说应该是优势,关于这点在后面我们还会探讨。
SPL 的强计算能力除了丰富的算法和类库外,还提供了高性能保障机制。我们说过,逻辑数仓应该是物理数仓加上逻辑能力,物理计算能力非常重要,这样才能提供足够的性能保障。SPL 为高性能计算设计了专门诸多高性能算法:
- 内存计算类的二分法、序号定位、位置索引、哈希索引、多层序号定位、……
- 外存查找类的二分法、哈希索引、排序索引、带值索引、全文检索、……
- 遍历计算类的延迟游标、遍历复用、多路并行游标、有序分组汇总、序号分组、……
- 外键关联类的外键地址化、外键序号化、索引复用、对位序列、单边分堆、……
- 归并与连接类的有序归并、分段归并、关联定位、附表、……
- 多维分析类的部分预汇总、时间段预汇总、冗余排序、布尔维序列、标签位维度、……
- 集群计算类的集群复组表、复写维表、分段维表、冗余与备胎容错、负载均衡、……
当然,无论是逻辑计算还是物理计算都离不开数据存储,有时将数据按照计算目标进行组织(如按照指定字段排序)可以获得更高的计算性能;反过来,有些高性能算法也需要存储作为基础。SPL 为此提供了高性能文件存储,请注意,SPL 提供的是文件存储,这与传统数据库的封闭存储完全不同,SPL 并不绑定存储,从逻辑上看,SPL 的高性能文件与其他任何数据源是等同的,只不过 SPL 在文件存储中实现了压缩、列存、索引等提高性能的工程手段。并在此存储的基础上提供了众多高性能算法。
有了物理上的计算保障,SPL 不仅提供了逻辑数仓无法比拟的物理能力,相较其他物理数仓在性能上也有很大优势。在已应用的案例中,SPL 经常能获得数倍到数十倍的性能提升。
部分性能提升案例:SPL 提速天体聚类任务 2000 倍
开源 SPL 将银行手机账户查询的预先关联变成实时关联
开源 SPL 提速保险公司团保明细单查询 2000+ 倍
开源 SPL 提升银行自助分析从 5 并发到 100 并发
开源 SPL 提速银行用户画像客群交集计算 200+ 倍
文件存储的另一个好处是使用灵活,我们可以根据计算目标随意组织数据,而不会出现像数据库那样无法干预的情况。由于存储比较便宜,我们还可以随便冗余数据,无非多几个文件而已,同一份数据可以设计不同的组织形式(如按不同字段有序),以适应不同的计算场景。
SPL 自身拥有完备且高性能的计算能力,有了强大的物理计算能力,加上丰富的多数据源接口就是完整的逻辑数仓,这也是我们为什么说 SPL 更适合用来建设逻辑数仓的原因。
SPL 的优点还不止于此,在构建逻辑数仓过程中,轻量、简单也是重要特性。
更轻量
说到数仓,都让人觉得会是个沉重的东西,即使只是逻辑的,也是一个服务器体系。但实际上,这种运算在各种场景都可能发生,很多在应用内的跨源计算本质上都属于逻辑数仓范畴。为此,SPL 不仅支持独立部署,还支持与应用集成嵌入。
SPL 对硬件的要求很低,安装很轻。只要有 JDK1.8 及以上的 JVM 环境的任何操作系统都可以运行,包括常见的 VM 和 Container,安装后空间不到 1G。与应用集成时,只需要嵌入几个 jar 包就可以运行,非常方便。现在有些报表 /BI 工具也宣称支持逻辑数仓,但实际的功能很弱,远不及专业数仓产品。把 SPL 嵌入后就能弥补这个能力的不足,在应用内实施跨源计算等逻辑计算能力。
SPL 提供的多数据源接口使用很方便。再加上文件物化存储,文件的使用和管理都很灵活简单,再加上 SPL 自身的敏捷语法,会让 SPL 作为逻辑数仓使用起来也非常轻。
基于文件系统管理数据文件非常方便,文件在文件系统中采用多级目录进行管理,我们可以针对不同业务或不同模块设置不同的目录,某个目录及子目录专门为单一业务服务,彼此之前不存在任何耦合,数据修改不会影响其他业务。如果某个业务下线,该业务对应的数据(目录)可以放心删除,整体管理十分清爽。而且 SPL 没有元数据,不需要数据库那种复杂的管理系统,这些都会让运维很轻。
安装 / 嵌入轻、使用轻、运维轻,SPL 这个逻辑数仓整体表现就非常轻量了。
更低开发成本
使用 SPL 实施数据计算会更容易开发调试,拥有更低的开发成本。
SPL 提供了支持过程的语法,这会大幅简化复杂计算。要知道一个计算 100 行写成一句(SQL)还是分成 100 句(SPL)逐步完成的复杂度是完全不同的。
SPL 也提供了更易于开发调试的 IDE,除了编辑调试功能,还可以逐格编码,还有能够查看每步结果的面板,十分便利。
更重要的是,由于 SQL 的语言能力并不完善,即使只是数据任务也常常难以独立完成。比如股票连涨问题以及更复杂一些的电商漏斗运算(这些并不是多奇怪的需求,业务中经常会碰到),用 SQL 实现就非常非常困难,通常要借助 Python 或 Java 来实施。这会带来技术栈的复杂,使用和运维都不方便。
相比 SQL 有很多实现困难甚至实现不了的场景,SPL 则提供了更简洁的语法和更完善的能力。像计算股票最长连涨天数,SPL 一句就能写出来:
stock.sort(trade_date).group@i(close_price<close_price [-1]).max(~.len())
而同样的计算 SQL 则要嵌套多层用非常绕的思路实现。
除了常规的结构化计算类库,SPL 还提供了 SQL 支持不好的有序计算,以及保留分组集合的分组运算,还有不同的关联方式等等。另外,SPL 语法还设计了独特的选项语法、层次参数以及增强的 Lambda 语法,使得复杂计算实现更为简单。
关于 SPL 语法的更多内容可以参考:写在格子里的程序语言
语法简洁、能力完善带来的直接结果是开发高效,不需要再借助其他技术让技术栈更为简单,在一个体系内就能完成所有事情,使用和运维更加简单方便,成本更低。
逻辑数仓,不仅要关注逻辑能力,物理能力同样重要,二者有机结合才能充分发挥作用。同时,数据源融合程度、数据种类支持、性能保障、使用方便性、开发运维成本同样是重要的考量指标。综合来看,使用 SPL 搭建逻辑数仓是一个不错的选择。
英文版