处理大型 CSV 文件的最佳方法是什么?

What is the best way to process large CSV files?

我有一个第三方系统,每天生成大量数据(这些是存储在 FTP 上的 CSV 个文件)。正在生成 3 种类型的文件:

4 CSV 的总大小是 1.5 Gb。但我们应该考虑到某些文件每 15 分钟生成一次。这些数据也应该汇总(不是那么困难的过程,但肯定需要时间)。我需要快速响应。 我正在考虑如何存储这些数据和整体实现。

我们有 java 个堆栈。数据库是MS SQL Standard。根据我的测量 MS SQL Standard,其他应用程序无法处理此类负载。我想到了什么:

你会在这里推荐什么?可能有更好的选择。

编辑#1

这些大文件是每天的新数据。

您可以考虑查看 Apache Spark project. After validating and curating the data maybe use Presto 到 运行 个查询。

Pentaho 数据集成(或类似的 ETL 工具)可以处理将数据导入 SQL 数据库,并且可以动态进行聚合。 PDI 有社区版,可以 运行 独立版或通过 Java API.

您可以使用 uniVocity-parsers to process the CSV as fast as possible, as this library comes with the fastest CSV 解析器。我是这个库的作者,它是开源和免费的(Apache V2 许可证)

现在要将数据加载到数据库中,您可以尝试 univocity framework(商业)。我们使用它将大量数据快速加载到 SQL 服务器和 PostgreSQL 等数据库中 - 从 25K 到 200K rows/second,具体取决于数据库及其配置。

下面是一个简单示例,说明从 CSV 迁移的代码如下所示:

public static void main(String ... args){
    //Configure CSV input directory
    CsvDataStoreConfiguration csv = new CsvDataStoreConfiguration("csv");
    csv.addEntitiesFromDirectory(new File("/path/to/csv/dir/"), "ISO-8859-1");

    //should grab column names from CSV files
    csv.getDefaultEntityConfiguration().setHeaderExtractionEnabled(true);

    javax.sql.DataSource dataSource = connectToDatabaseAndGetDataSource(); //specific to your environment

    //Configures the target database
    JdbcDataStoreConfiguration database = new JdbcDataStoreConfiguration("database", dataSource);

    //Use only for postgres - their JDBC driver requires us to convert the input Strings from the CSV to the correct column types.
    database.getDefaultEntityConfiguration().setParameterConversionEnabled(true);

    DataIntegrationEngine engine = Univocity.getEngine(new EngineConfiguration(csv, database));

    //Creates a mapping between data stores "csv" and "database"
    DataStoreMapping mapping = engine.map(csv, database);

    // if names of CSV files and their columns match database tables an their columns
    // we can detect the mappings from one to the other automatically
    mapping.autodetectMappings();

    //loads the database.
    engine.executeCycle();

}

为了提高性能,该框架允许您管理数据库模式并执行诸如删除约束和索引、加载数据以及重新创建它们等操作。如果您需要,数据和模式转换也得到很好的支持。

希望对您有所帮助。

好的。在花了一些时间解决这个问题之后(包括阅读、咨询、实验、做几个 PoC)。我想出了以下解决方案。

Tl;博士

数据库PostgreSQL 因为它适用于 CSV,免费且开源。

Tool: Apache Spark 非常适合此类任务。表现不错。

数据库

关于数据库,决定是一件很重要的事情。选择什么以及将来如何处理如此大量的数据。它绝对应该是一个单独的服务器实例,以免在主数据库实例上产生额外的负载并且不会阻塞其他应用程序。

没有SQL

我在这里考虑了 Cassandra 的用法,但是现在这个解决方案太复杂了。 Cassandra 没有临时查询。 Cassandra 数据存储层基本上是一个键值存储系统。这意味着您必须围绕您需要的查询“建模”您的数据,而不是围绕数据本身的结构。

关系数据库管理系统

我不想在这里过度设计。而我在这里停止了选择。

MS SQL 服务器

这是一个可行的方法,但最大的缺点是定价。相当昂贵。考虑到我们的硬件,企业版要花很多钱。关于定价,你可以阅读这个 policy document.

这里的另一个缺点是对 CSV 文件的支持。这将是我们这里的主要数据源。 MS SQL Server 既不能导入也不能导出 CSV。

  • MS SQL Server 静默截断文本字段。

  • MS SQL Server 的文本编码处理出错。

MS SQL 服务器抛出一条错误消息,因为它不理解引号或转义。 有关该比较的更多信息,请参阅文章 PostgreSQL vs. MS SQL Server.

PostgreSQL

这个数据库是一个成熟的产品,也是久经考验的。我从其他人那里听到了很多积极的反馈(当然,也有一些权衡)。它具有更经典的 SQL 语法,良好的 CSV 支持,而且它是开源的。

值得一提的是SSMS is a way better than PGAdmin. SSMS has an autocomplete feature, multiple results (when you run several queries and get the several results at one, but in PGAdmin你只能得到最后一个)。

无论如何,我现在正在使用 JetBrains 的 DataGrip

处理工具

我查看了 Spring 批次 Apache SparkSpring Batch 对于这个任务来说有点太低级了,而且 Apache Spark 提供了更容易扩展的能力,如果将来需要的话。无论如何,Spring Batch 也可以完成这项工作。

关于Apache Spark示例,代码可以在learning-spark项目中找到。 我现在的选择是Apache Spark