Blog

Blog

PHODAL

Kotlin 数据科学:从数据分析视角看 Kotlin 语言的数据生态

自去年接手 ArchGuard 到现在,差不多是一年,也差不多是我真正(虽然也是业余时间)写 Kotlin 一年的时间。在不考虑 CLI 体制的体积下,Kotlin 确实是一个快乐的语言,特别是:你经常找不到北,但是非常好用的语法糖:extension functions。在那之前,我业余经常使用的是 Rust,有些语法糖虽然好用,但是吧,有时候编译器就不让你快乐。我觉得主要原因吧,应该是:Kotlin 是 Jetbrains 的亲儿子,而 Rust 不是。次要原因是:Rust 的静态分析真不是一件容易的事。

回到文章的正题,也是因为 ArchGuard Scanner 在语法分析完之后,需要进行一系列的数据处理和就地分析、交互式分析,也因此需要一系列的数据科学工具。

  • 交互式分析:创建一个类似于 Jupyter 或 IPython 的环境,以进一步探索和分析数据。
  • 数据处理与传输:从扫描器接收到的原始数据的解析和转换,以便进一步的分析和处理。
  • 就地数据分析:对解析的数据进行查询和二次计算,将计算交由 Client 分析,可以降低服务器的压力。
  • AI:还在探索适合的用途

当然,我们并不会详细展开每一方面。

REPL 与交互式分析:Kotlin Jupyter

在我们设计《ArchGuard 的架构工作台》时,旨在提供一个交互式的架构分析环境,以帮助人们设计架构、演进架构、观测架构。从结论上来说,我们要提供一个架构领域的 Jupyter,架构师就能像数据科学家一样进行分析。而软件架构师与数据科学家不同的是,严谨性的分析需要的是静态类型语言。

于是,去年我们引入了还在开发中的、不稳定的 Kotlin Jupyter 成为了我们的选择。Kotlin Jupyter 是一个交互式的 Kotlin 编程环境,它结合了 Kotlin 语言和 Jupyter Notebook 的优点,并提供了一个方便的方式来进行 Kotlin 语言的交互式编程和数据分析。对于开发一个交互式分析平台来说,我们做的工作如下:

  • 引入 jupyter-apijupyter-kernel 作为运行 Kotlin Script 的基础环境
  • 使用 Kotlin Jupyter 提供的 %use 构建了自己的架构即代码库,以提供底层的 API 封装
  • 使用 Kotlin TypeSafe builder 构建架构即代码DSL (领域特定语言)

最后,ArchGuard 的工作台 REPL 示例代码如下:

%use archguard

repos {
    repo(name = "Backend", language = "Kotlin", scmUrl = "https://github.com/archguard/archguard")
}

context.repos.create()

作为一个还在频繁变动的库,对于三方系统的接入,还是存在一些问题的:

  • 早期我们使用的是 0.11.0-89-1 版本,因为先前的接口无法直接使用,所以用的是 Jetbrains 的内部源,直到今年更新到 0.11.0-208 才算稳定。
  • 先前版本与 Jupyter 的耦合库过度,需要手动做一些剥离?
  • 接入时,没有 API 文档,只能看源码!!

不过,现在勉强算是可以跑起来,也是可喜可贺。现在想想,当时应该去提几个 issue 来着的。

就地数据分析:Kotlin DataFrame

Kotlin DataFrame 是我们最近正在计算引入就地数据分析时考虑的工具,它提供了与 Pandas 类似的数据结构,即 DataFrame,可以对数据进行索引、切片、过滤、分组和聚合等操作。与 Pandas 稍有不同的是,Kotlin DataFrame 采用了类型安全的设计,并在设计时考虑了 Kotlin 的语言特性,如空安全和函数式编程等。

Kotlin DataFrame 提供了各种数据读写工具,可以从 ArrowFeather、CSV、Excel、JSON、TSV 等格式中读取数据,并将数据保存到这些格式或数据库中。

val dataFrame = DataFrame.read("data/one_data.json").cast<CodeDataStruct>()

// or

val ds = listOf(
    CodeDataStruct(
        NodeName = "Main",
        Functions = listOf(CodeFunction(Name = "main")),
    )
).toDataFrame()

随后,我们就可以一些统计分析和机器学习相关的功能:

dataframe
    .filter { it[CodeDataStruct::Functions].isNotEmpty() }
    .filter { it[CodeDataStruct::Functions].any { function -> function.Name == "main" } }
    .print()

ArchGuard Scanner 在数据分析后,就会输出分析完的数据。那么下一个分析任务,就可以直接进行处理,诸如于 SQL Lint、API Lint 等。此时,我们就可以解耦几种不同类型的任务,唯一的问题就是过程中序列化产生的开销,这也就是下一小节要解决的问题。

同样的,我们所经历了和 Kotlin Jupyter 相似的痛苦 —— 文档缺失,最后还是去看源码里的测试用例了。

数据传输与处理

ArchGuard 1.x 里,不存在数据传输的场景,Scanner 直接生成 SQL 然后导入数据库。在 ArchGuard 2.0 里,我们使用 JSON 来传输代码的元数据,在数据量大场景下,服务端的 OutOfMemory 成为了日常的 issue —— 虽然系统在设计之初不是给单体系统设计的,微服务架构下这么大的代码量本身就不合理。在这时,有更好的方案是引入流式系统机制,其对于现有系统的改动太大,需要有专人来负责;另外一种比较简单的方案,就是服务器不需要一个反序列化的数据格式,就成了一种更简单的选择。

Apache Arrow 与 FlatBuffers 是我们考虑的选择,而 DataFrame 支持了 Aapche Arrow 格式的转换,这就让处理工作变得相当简单:

val dataFrame = DataFrame.read("data/onedata.arrow").cast<CodeDataStruct>()

dataFrame
    .print(10)

不过,在我们引入 ArchGuard 的过程中,发现它并不支持类型嵌套 —— 原因是开发人员在设计的时候漏了:issues 271,我尝试去修复这个 issue,但是发现我需要一系列的先验知识,就暂时性放弃了。希望官方有空早日修复这个 issue,这样我就可以进行后续的发电工作。接下来,在有了数据之后,我们就可以用 Lets-Plot 来绘图:

var p = letsPlot(data)
p += geomDensity(color="dark_green", alpha=.3) {x="rating"; fill="cond"}
p + ggsize(700, 350)

在 Jetbrains IDE 支持下,结合 Kotlin 的特性,它变得很强大。诸如于,我们可以使用 DataSpell + Jupyter 来实现实时数据分析。

其它 Kotlin 数据科学:AI 等

其它的一些点诸如于:

  • 深度学习模型开发:Kotlin 不仅仅是一种通用编程语言,还可以用于开发深度学习模型。官方维护的 KotlinDL 是一个基于 Kotlin 编写的高级深度学习 API,受到 Keras 的启发。KotlinDL 使用 TensorFlow Java API 和 ONNX Runtime API for Java,提供简单易用的 API 用于训练深度学习模型、导入 Keras 和 ONNX 模型进行推断,以及利用迁移学习调整预训练模型以适应任务。
  • 数学表达式处理:如果你需要处理数学表达式,Kmath 是一个非常有用的高级数学库。它实现了组合的代数结构的数学操作,定义了线性结构、表达式、直方图、流操作的 API,并提供了对现有 Java 和 Kotlin 库的可互换包装,包括 ND4J、Commons Math、Multik 等。我们计划在 ArchGuard 2023 中探索自定义架构适应度函数,因此像 Kmath 这种库也成为了我们未来的试验范围。
  • 可视化:可视化是数据科学中重要的一环。如果你需要绘制图表,可以考虑使用 Lets-Plot 提供的绘图功能。同时,JLaTeXMath 可以显示使用 LaTeX 编写的数学公式,虽然它更多是针对理论研究的需求。

当然,除了 Kotlin 相关的库,Java 生态中也有一系列库可以满足你的需求。不过 Kotlin 的语法更加舒服,如果你想了解更多关于 Kotlin 在数据科学中的应用,可以查阅 Kotlin 官方文档:https://kotlinlang.org/docs/data-science-overview.html。

其它:除了上述提到的库,Kotlin 社区还有一个名为 Koma 的科学计算框架,可以在 Kotlin 中进行数学运算和矩阵计算。不过,由于该库目前较为不活跃,我们未展开详细研究。

小结:Kotlin 数据科学?

在现有的生态体系里,主流的数据分析语言包含(主要是我就熟悉这几个):

  • Python 依旧是今天最好的数据科学工具,它有广泛的库和工具,如 NumPy, Pandas, Matplotlib 和 Scikit-learn,这些库提供了大量的数据处理、分析和可视化功能。
  • Java 也是一种在数据科学领域使用广泛的编程语言,尤其在大数据分析方面,Apache 生态系统提供了很多强大的工具和库,如 Hadoop, Spark, Flink 和 Kafka 等。这些工具可以帮助处理大规模数据集,并提供高度可扩展的数据处理和分析能力。
  • Scala 作为一种静态类型语言,具有 Java 的可靠性和稳定性,同时又具备 Python 和 R 语言的数据科学特性。其优势在于处理大规模数据集、函数式编程范式、丰富的工具库、REPL 环境(交互式编程环境)。
  • 其它语言:R 语言、Julia 我都不太熟悉。

在诸多方面,Kotlin 与 Scala 相似,在上手的学习曲线上,Kotlin 更为简单。虽然,我也在公司项目里用过 Scala,但是要重写现有的 ArchGuard 是不可能的,除非 Copilot 哪天能帮我自动重写。所以,探索使用 Kotlin 进行数据科学更为了一种更好的选择。除此,Kotlin 也更适合于那些希望快速学习和使用 Java 风格编程语言的数据科学开发者。


或许您还需要下面的文章:

关于我

Github: @phodal     微博:@phodal     知乎:@phodal    

微信公众号(Phodal)

围观我的Github Idea墙, 也许,你会遇到心仪的项目

QQ技术交流群: 321689806
comment

Feeds

RSS / Atom

最近文章

关于作者

Phodal Huang

Engineer, Consultant, Writer, Designer

ThoughtWorks 技术专家

工程师 / 咨询师 / 作家 / 设计学徒

开源深度爱好者

出版有《前端架构:从入门到微前端》、《自己动手设计物联网》、《全栈应用开发:精益实践》

联系我: h@phodal.com

微信公众号: 最新技术分享

标签