Hive迁移Presto的技术实践

2,116 阅读3分钟

本文来自OPPO互联网技术团队,如需要转载,请注明出处及作者。欢迎关注我们的公众号:OPPO_tech

hive设计之初,就被定位一款离线数仓产品,虽然Hortonworks喊出了Make Apache Hive 100x Faster的牛逼口号,也在上面做了大量的优化,然而性能提升依旧不大。

而随着OPPO数据量一步步的增多,动辄运行几个小时的hive再也满足不了交互查询的需求,因此我们引入了presto,sql on hadoop阵营里的优秀代表。主要适用于即席查询。

然而事情往往木有那么简单,很多分析师用惯了hql,迁移的成本很大,所以本着业务方都是美丽的上帝的原则。为了使用户能平滑的将业务迁移到presto上,我们义无反顾跳入了presto兼容hive这个大坑中,接下来介绍下我们主要兼容工作。

presto兼容hive,总的来说需要解决如下几点问题:

  1. hive的udf;

  2. hive视图;

  3. 语义处理上的不同,如presto中1/2=0, hive中为0.5。

要完全解决这些问题无疑是费时费力,所以我们在presto和hive之上构建一层路由层--功能是将查询请求优先提交到presto中查询。若执行错误,则路由到hive中。

当然还是存在一定风险,因为由于语义处理上的不同,相同的sql在presto和hive中可能会得到不同的结果。

语义上的修改

Part 1: Key not present in map

presto处理map,若key不存在,会报错,而hive会返回null。

Part 2: Cast as string

由于presto中并没有名为string的类型,出现若进行cast as string这样的转换,或者表定义中有string类型会出现Unknown type 的错误。因此我们在ASTBuilder.java中把string替换为了varchar类型(实现了对sql语法树的转换)

Part 3: 类型隐式转换

迁移过程中,在presto中经常会出现类型不匹配的错误。核心原因就是hive会对数据类型做兼容性转换。一开始考虑对运算符进行重载,如添加以下函数:

就能支持如下case:

然而这种方式需要对+,- ,* ,/ ,between ,in 等几乎所有的运算符进行重载,太繁琐了。

因此我们换了一种思路:即隐式的插入一个CAST。相当于把 select 1 = '1' 转换成了 select 1 = cast('1' as int),从而在sql编译的前端实现了转换,兼容性上不会有任何问题。

hive视图兼容

presto和hive语义不同,自然hive定义的视图presto不能访问,但对一些简单的视图定义,如:

我们可以提供支持,方法也很简单:即在presto读取视图定义(StatementAnalyzer.java)的时候,解析原始的sql定义的语句,转换成presto的视图结构。

总结

  1. 对于业务开发的一些udf函数的支持;

  2. 对map结构的解析,比如map数据"{fk_1=1,fk_2:2,fk_3:3}",在hive 1.x 中使用"colelction.delim"作为值之间的分割符;而 hive 3.x 用"collection.delim" ;Prestosql 315则依赖于 hive 3.x,导致对线上的hive 1.x中的map数据解析出现问题。

当然presto对于hive的兼容工作远不止这些,udtf,hive对null处理等等,涉及到方方面面的细节,这也凸显了统一的sql标准的重要性。

重点来啦:

最后说一个题外重点:OPPO互联网运维云存储团队急招多个岗位,欢迎对MongoDB内核源码、Wiredtiger存储引擎、RocksDB存储引擎、数据库机房多活、数据链路同步系统、中间件、数据库等有兴趣的同学加入,一起参与OPPO百万级高并发文档数据库研发。

工作地点:深圳 / 成都

联系邮箱:yangyazhou@oppo.com(最好注明来源掘金)