寻找一个非云 RDBMS 来导入分区表CSV 格式及其目录结构

问题描述

上下文:我一直在研究 Cloudera/Impala,以便使用大型数据库并创建更易于管理的“聚合”表,其中包含的信息要少得多。这些更易于管理的表的数量级为数十到数百 GB,大约有两打表。我正在查看大约 500 GB 的数据,这些数据可以放在我实验室的一台计算机上。

问题:我希望使用非云 RDBMS,以便在我的实验室本地进一步处理这些表。原始 Impala 表(其中大部分按日期分区)已导出到 CSV,这样“表”文件夹包含每个日期的子文件夹,每个子文件夹包含一个唯一的 csv 文件(其中分区的“日期”列不存在,因为它位于其过时的子文件夹中)。哪个是合适的 RDBMS,我将如何导入这些表?

到目前为止我发现了什么MysqL 似乎有几个 GUI 或命令可以简化导入,例如:

然而,这些并没有解决我的具体情况,因为 1. 我只能访问集群上的 Impala,即我不能添加任何工具,因此必须在实验室计算机上完成繁重的工作,并且 2. 他们没有说一下关于导入一个已经分区的表和现有的目录/分区结构。

限制条件

  • 实验室计算机运行的是 Ubuntu 20.04
  • 理想情况下,我希望避免手动加载每个 csv/分区,因为我有数万个日期。我希望有一个已经识别分区目录结构的 RDBMS...
  • RDBMS 本身应该有一组相当新的可用函数包括前导/滞后/第一个/最后一个窗口函数。除此之外,它不必太花哨。

我愿意将 Spark 用作“矫枉过正的 sql 引擎”,如果这是最好的方法,我只是不太确定这是否是唯一计算机(而不是集群)的最佳方法。此外,如果需要(尽管我希望避免这种情况),我可以以另一种格式导出我的 Impala 表,以简化导入阶段。例如。基于文本的表格、镶木地板等的不同格式。

编辑 1 正如评论中所建议的,我目前正在研究 Apache Drill。它已正确安装,并且我已成功运行文档/教程中的基本查询。但是,我现在陷入了如何实际“导入”(实际上,我只需要“使用”它们,因为drill 似乎能够直接在文件系统上运行查询)我的表。澄清:

  • 我目前在目录 /data/table1 和 /data/table2 中有两个“表”。
  • 这些目录包含对应于不同分区的子目录,例如: /data/table1/thedate=1995 、 /data/table1/thedate=1996 等,table2 也是如此。
  • 在每个子目录中,我都有一个文件(没有扩展名),其中包含 CSV 数据,没有标题

我的理解(我还是 Apache-Drill 的新手)是我需要以某种方式创建一个文件系统存储插件,以便钻取了解在哪里查看以及它在查看什么,所以我创建了一个非常基本的插件一个使用插件管理页面上的网络界面从 this one) 准复制/粘贴。这样做的最终结果是,现在我可以输入 use data; 并且drill 理解了这一点。然后我可以说 show files in data 并且它正确地将 table1 和 table2 列为我的两个目录。不幸的是,我仍然缺少能够成功查询这些表的两个关键事项:

  1. running select * from data.table1 失败并出现错误,我尝试了 table1 或 dfs.data.table1 并且每个命令都收到不同的错误(找不到对象“数据”,找不到对象“表1”,架构[[dfs,data]] 分别对根架构或当前认架构无效)。我怀疑这是因为 table1 中有子目录?
  2. 我仍然没有提及 CSV 文件的结构,该结构需要包含以下事实:子目录名称中有“thedate”字段和值...

编辑 2 在尝试了很多事情之后,使用基于文本的文件仍然没有运气,但是使用镶木地板文件有效:

  • 我可以查询镶木地板文件

  • 我可以查询包含分区表的目录,每个目录的格式如下: thedate=1995,thedate=1996 如前所述。

  • 我使用 advice here 是为了能够以通常的方式查询表,即不使用 dir0 而是使用日期。本质上,我创建了一个视图:

    创建视图drill.test as select dir0 as thedate,* from dfs.data/table1_parquet_partitioned

  • 不幸的是,thedate Now一个文本,上面写着: thedate=1994 ,而不仅仅是 1994 (int)。所以我重命名了目录以便只包含日期,但是这不是一个好的解决方案,因为日期的类型不是整数,因此我不能使用日期来连接 table2(它在列中有日期)。所以最后,我所做的是在视图中将日期转换为 int

=> 这一切都很好,虽然不是 csv 文件,但这个替代方案对我来说是可行的。但是我想知道如果使用这样的视图,里面有一个演员,我会从分区修剪中受益吗?引用的stackoverflow链接中的答案表明分区修剪是由视图保存的,但是当在公式中使用列时我不确定这一点......最后,考虑到我可以完成这项工作的唯一方法是通过镶木地板,它引出一个问题:就性能而言,drill 是最好的解决方案吗?到目前为止,我喜欢它,但是将数据库迁移到这里会很耗时,我想尝试为此选择最佳目的地,而不会进行过多的反复试验......

解决方法

我最终使用了 Spark。我目前知道的唯一替代方案是 Apache Drill,它是由 Simon Darr(我再次感谢他!)引起我的注意。就我可以测试而言,每种解决方案的优缺点:

  • 当数据库以文本格式(在我的例子中是 CSV 文件)导出时,这两种解决方案都无法提供一种简单的方法来导入现有架构。
  • 两种解决方案都使用 parquet 文件正确导入架构,因此我决定必须从我的源集群(使用 Impala)以 parquet 格式重新创建我的表。
  • 剩下的问题是关于分区:我终于能够弄清楚如何在 Spark 上导入分区文件,并且添加该分区维度的过程是无缝的(我从 herehere 的那部分),而我无法找到一种令人信服的方法来使用 Drill 做到这一点(尽管创建视图,如建议的 here,确实有所帮助):
    • 在 Spark 上。我用过:spark.sql("select * from parquet.file:///mnt/data/SGDATA/sliced_liquidity_parq_part/")。请注意,重要的是不要像我第一次那样使用 * 通配符,因为如果使用通配符,则读取每个 parquet 文件时不会查看它所属的目录,因此它不会考虑将这些字段分区或添加到架构中。如果没有通配符,语法 field_name=value 的目录名称会被正确添加到架构中,并且值类型本身也会被正确推断(在我的例子中,是 int,因为我使用了 date=intvalue 语法)。
    • 在 Drill 上,创建视图的技巧有点混乱,因为它首先需要使用 dir0 的子字符串来提取 field_name 和值,其次需要强制转换才能发送该字段为模式中的正确类型。我真的不确定这种视图是否会在此后进行查询时启用分区修剪,因此我不喜欢这种 hack。注意:可能还有另一种方法可以正确执行此操作,我只是没有找到。

一路上我学习了 Drill(这对于日志和没有已知结构的东西来说似乎很棒),并了解到如果数据结构化,Spark 可以做很多 Drill 所做的事情(我不知道它可以在没有底层数据库系统的情况下直接读取 CSV 或镶木地板文件)。我也不知道在独立机器上安装 Spark 是如此容易:在执行步骤 here 之后,我只是在我的 bashrc 中创建了一个脚本,该脚本一次性启动了 master、worker 和 shell(虽然我无法评论使用独立计算机的性能,但可能 Spark 不擅长)。过去使用过一些 spark,考虑到我的选择,这个解决方案对我来说似乎仍然是最好的。如果有任何其他解决方案,请继续提供它们,因为我还不会接受我自己的答案(无论如何,我需要几天时间将所有桌子更改为镶木地板)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...