陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

06|get hands dirty:SQL查询工具怎么一鱼多吃?

尝试在 Node.js 中处理和 Python 类似的接口
黄金级难度
使用了大量的 trait
白银级难度
引入了异步、泛型和更多的 trait
青铜级难度
流程简单
尝试在 Node.js 中处理和 Python 类似的接口
黄金级难度
使用了大量的 trait
白银级难度
引入了异步、泛型和更多的 trait
青铜级难度
流程简单
思考题
Queryer
Thumbor
HTTPie
思考题
Queryer
Thumbor
HTTPie
Rust 代码之旅
Rust 代码之旅
总结

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
通过 HTTPie 和 Thumbor 的例子,相信你对 Rust 的能力和代码风格有了比较直观的了解。之前我们说过 Rust 的应用范围非常广,但是这两个例子体现得还不是太明显。
有同学想看看,在实际工作中有大量生命周期标注的代码的样子;有同学对 Rust 的宏好奇;有同学对 Rust 和其它语言的互操作感兴趣;还有同学想知道 Rust 做客户端的感觉。所以,我们今天就来用一个很硬核的例子把这些内容都涵盖进来
话不多说,我们直接开始。

SQL

我们工作的时候经常会跟各种数据源打交道,数据源包括数据库、Parquet、CSV、JSON 等,而打交道的过程无非是:数据的获取(fetch)、过滤(filter)、投影(projection)和排序(sort)。
做大数据的同学可以用类似 Spark SQL 的工具来完成各种异质数据的查询,但是我们平时用 SQL 并没有这么强大。因为虽然用 SQL 对数据库做查询,任何 DBMS 都支持,如果想用 SQL 查询 CSV 或者 JSON,就需要很多额外的处理。
所以如果能有一个简单的工具,不需要引入 Spark,就能支持对任何数据源使用 SQL 查询,是不是很有意义?
比如,如果你的 shell 支持这样使用是不是爽爆了?
再比如,我们的客户端会从服务器 API 获取数据的子集,如果这个子集可以在前端通过 SQL 直接做一些额外查询,那将非常灵活,并且用户可以得到即时的响应。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何使用Rust语言设计一个可以对任何数据源使用SQL查询的库。作者首先提到了在实际工作中经常需要与各种数据源打交道,而使用SQL进行数据获取、过滤、投影和排序的过程。然后,作者介绍了设计分析的过程,包括SQL解析器的编写、数据加载为DataFrame的操作以及如何将SQL AST转换为DataFrame AST。最后,作者提到了宏编程在这个过程中的应用,以及Rust语言优秀的模式匹配支持。整体而言,本文涵盖了SQL查询工具的设计和实现过程,展示了Rust语言在此领域的应用和特点。 文章通过示例代码展示了如何创建一个自定义的SQL方言,支持从URL中读取数据,并且通过trait的方式实现了这一功能。这种灵活的特性在Rust开发中很常见,展示了Rust语言的强大之处。 在实现AST的转换过程中,作者通过模式匹配和数据结构转换的方式,展示了Rust语言对于复杂数据处理的优雅支持。同时,通过引入trait和async/await特性,作者展示了如何构建低耦合、高内聚的代码结构,使得未来对于代码的修改和扩展变得更加容易。 总的来说,本文通过深入的技术讲解和实际示例,展示了Rust语言在数据处理和库设计方面的优势,对于想要深入了解Rust语言在数据处理领域应用的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(68)

  • 最新
  • 精选
  • leesper
    置顶
    陈天老师,学完了这节课程,我觉得你和陈皓老师给了我新的启发。 在陈皓老师的《左耳听风》的《编程的本质》一节,提到了这么两个公式 (1)程序=算法+数据结构 (2)算法=逻辑+控制 我从这两个公式中领悟出:“程序=逻辑抽象+数据结构+控制”。数据结构是业务逻辑的静态的描述,它用术语表示数据结构的定义,而逻辑抽象是动态的,是对业务流程的抽象。 您在课程里所说的“绝大多数处理逻辑都是把数据从一个接口转换成另一个接口。”、“好的代码,应该是每个主流程都清晰简约,代码恰到好处地出现在那里,让人不需要注释也能明白作者在写什么” 与陈皓老师的“有效地分离 Logic、Control 和 Data 是写出好程序的关键所在!”,其实表达的是同一个意思。写任何代码,设计好Logic和Data,业务流程就算完成了(功能性需求),然后在这个基础上不断地优化Control,就能提高代码性能(非功能性需求)。 以“高性能网络编程”为例,网络编程的业务逻辑是“客户机-服务器模型”: (1)客户进程发送请求 (2)服务进程处理请求(可能会访问某些本地或远程资源) (3)服务进程发送响应 (4)客户进程处理响应 在这个过程中所体现的就是您所说的“绝大多数处理逻辑都是把数据从一个接口转换成另一个接口”的过程: (1)客户进程中的业务数据变成请求数据包 (2)请求数据包编码成字节流发送到网络上 (3)服务进程获得字节流把它解码成请求数据包 (4)服务进程根据请求数据包访问资源得到结果 (5)客户进程把结果数据变成响应数据包 (6)响应数据包编码成字节流发送到网络上 (7)客户进程获得字节流把它解码成响应数据包 (8)客户进程处理响应数据包 对于一个最简单的iterative echo server来说,一次服务一个客户端,字节码解码成字符串,业务逻辑就是把客户端发来的再原封不动编码成字节码发回去就可以了。 然而对于一个有着复杂业务逻辑的高性能服务器来说,要考虑的点就不一样了: (1)要实现字节码和“自定义消息”之间的来回转换,就要自定义Codec,甚至要引入protobuffer/flatbuffer,并实现消息的注册机制 (2)要一次服务多个客户端,就要引入epoll/kqueue这样的IO multiplexing机制,实现单个线程监听多个socket fd,甚至one-loop-per-thread,并做好网络连接管理,关闭服务器的时候不能硬着陆,要优雅关闭:等待所有网络连接接收并处理完消息再退出 (3)要提高IO性能,就要引入nonblocking IO (4)要避免复杂业务逻辑占用IO线程资源,就要引入工作者线程池,把服务端对消息的处理放到另一个线程中执行,并做好IO线程和工作者线程的同步 (5)如果服务端要访问远程资源,就要引入配置,在服务启动时装配好各种mysql或者redis的handle,甚至自己实现一个connector访问其他的服务 这些都是属于Control范畴要考虑的东西。Logic决定了程序复杂度的下限,Control决定了上限。把Logic和Control混在一起,往往是写出来的代码难以维护的原因。

    作者回复: 说得非常好! 对于「有着复杂业务逻辑的高性能服务器」,除了你说的这些,还有在处理的整个 pipeline 中要考虑引入 hook 做事件通知,以满足日志,监控等需求。在第 21 讲我们讨论 KV server 的时候,会逐步把你说的这些点都体现到。

    2021-09-20
    30
  • 葡萄
    置顶
    老师的课程消除了对解决这类问题(自己实现一个解析器的扩展)的恐惧,或者说以前一直在使用高级封装的语言,对这些偏低层一点的东西总是不敢触碰,一点点分析下来,完全没有想象中的那么难。哈哈,这就是get hands dirty的精要吧。学习rust很好,听老师讲课更好,感谢老师。

    作者回复: 👍

    2021-09-03
    2
    19
  • pedro
    置顶
    In [1]: import queryer_py In [2]: sql = queryer_py.example_sql() In [3]: print(queryer_py.query(sql, 'csv')) name,total_cases,new_cases,total_deaths,new_deaths European Union,36489548.0,84973.0,766627.0,541.0 India,32857937.0,47092.0,439529.0,509.0 South America,36922209.0,37641.0,1131322.0,1104.0 Iran,5025233.0,33170.0,108393.0,599.0 Africa,7821187.0,30793.0,196917.0,639.0 Brazil,20804215.0,27345.0,581150.0,737.0 本周最骄傲、最爽的demo: ```shell $ tree . . ├── httpie │   ├── src │   └── target ├── queryer_all │   ├── queryer │   ├── queryer-py │   └── target ├── scrape_url │   ├── src │   └── target ├── thumbor │   ├── src │   └── target ```

    作者回复: 👍 全都跟下来啦。可以试着写写 nodejs 的支持。如果有疑问,可以去 github repo 里找答案 :)

    2021-09-03
    7
  • Fenix
    太赞了,这种教学模式,处理问题的思路很有启发

    作者回复: 👍 希望能够帮到

    2021-09-03
    14
  • Geek_01c6d8
    全网最好的rust课程,没有之一!!!

    作者回复: 谢谢抬爱!

    2021-09-24
    9
  • bearlu
    老师如何有效阅读docs.rs,我看你引入来的crate的文档,但是不知道如何有效学习?

    作者回复: 我就是在需要的时候查阅,并不会系统地去一篇篇读。对于要了解的数据结构,我会去看它都实现了哪些 trait。未来你会逐渐明白这非常重要。有时候甚至被数据结构自己提供了哪些功能更重要。

    2021-09-04
    6
  • Colt
    老师的思路非常正,这几次实践课可以看出RUST的魅力和优雅,能力有限需要多品几次

    作者回复: 谢谢赞赏!

    2021-09-10
    5
  • 老荀
    太强了!这种实战性质的教学正是大家都需要的!不是那种重复啰嗦语法细节的烂课程

    作者回复: 谢谢!这周先给大家看看 Rust 能做什么,怎么做。下周起就要从堆和栈的关系入手讲所有权啦。

    2021-09-03
    5
  • 拉斯特
    通过一个实际案例展现了rust的特性,设计模式的使用,决解问题的思路和设计过程。简直不要太棒~

    作者回复: 谢谢夸奖!希望能够帮到。

    2021-09-03
    5
  • 玄澈
    老师你好,有观点认为用 Deref 模拟继承通常不是好的做法。例如:https://www.zhihu.com/question/36488041 https://rust-unofficial.github.io/patterns/anti_patterns/deref.html 有好处也有坏处,我们该如何权衡以至于防止滥用呢。

    作者回复: 首先 deref 的用途不是模拟继承。它最根源的需求是为只能指针提供对内部数据的方便的访问:https://doc.rust-lang.org/std/ops/trait.Deref.html。当你需要你的数据结构在使用时用起来可以感觉和内部的数据类似时,可以使用 Deref trait。比如我可以构建一个 Memmap 结构,把文件 mmap 到内存中,但如果我提供一系列额外的接口,会让使用者很不方便,但我把它 deref 到 &[u8],让用户操作起来像一个内存 buffer,用起来就很舒服。当然,滥用它会给使用者带来一些困惑,所以标准文档建议只有在构建智能指针时使用。 我的建议: 1. 简单的数据结构的封装。像我 DataSet 的使用那样。 2. 智能指针。比如你要实现一个 SmartString,在 < 24 字节时使用栈上的内存,更大的字符串才使用 String。这样的场合,如果不用 Deref,使用起来会非常不友好。

    2021-09-05
    4
收起评论
显示
设置
留言
68
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部