计算Java中+ 2000万条记录的统计数据
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算Java中+ 2000万条记录的统计数据相关的知识,希望对你有一定的参考价值。
我有csv文件(600 MB)和20百万行。我需要读取所有这些数据,从中创建java对象列表,并计算对象字段的一些指标,例如平均值,中位数,最大值,总和和其他统计数据。在Java中使用它的最佳方法是什么?我尝试了简单的.forEach循环,花了一段时间(20分钟)迭代它。
更新:我用户BufferReader读取数据并将csv文件转换为某些Java类的对象列表。这很快。它在forEach循环中停留了20分钟,在那里我试图迭代那些2000万个对象列表并将它们分成3个列表,具体取决于当前对象中的值。所以基本上,我迭代整个列表一次,我有if / else条件,我检查对象中的某个字段是否等于“X”,“Y”或“Z”,并根据答案,分离那些20毫升记录到3个列表中。
然后,对于这3个列表,我需要计算不同的统计数据:例如中位数,平均值,总和等
在广泛使用超过600Mb的数据量后,我可以发表两个声明:
- 600Mb不是大量数据,特别是如果我们谈论表格数据;
- 这些数量与大数据无关,实际上可以在内存中的传统硬件上轻松处理,这是最快的选择。
但是,您应该做的是确保将数据读入列式连续数组,并使用直接在列式数据的连续数组上运行的方法。
因为它是一个csv文件,它是按行存储的,所以你最好将它读取到一个字节数组中并将其解析为一个按列的预分配表示。
在SSD上读取一块600Mb的内存应该只需几秒钟,解析它将取决于你的算法(但必须能够立即在该结构内寻找)。记忆方面,你将使用大约600Mb的三倍,但使用16Gb的机器应该是一个明智的选择。
因此,不要急于SQL或切片文件,也不要将每个单元格实例化为Java对象。也就是说,在这种特殊情况下,您不需要Java对象列表,您需要double[]
等。如果您预先分配确切的大小,则可以使用ArrayList
s。其他标准集合会杀了你。
说了这么多,我宁愿推荐使用python
和numpy
来完成任务而不是Java。 Java对于对象很好,而对于连续的内存块和相应的操作则不是很好。 C++
会做得好甚至R
。
我强烈建议不要将所有600MB加载到RAM中并将其用作Java对象。如你所说,这需要很长时间才能加载。
你可以做什么:
使用SQL:将数据转换为数据库,并在此数据库上执行搜索查询。不要遍历RAM中的所有对象。这会使您的应用程序非常不符合要求。
SQL经过优化,可以处理大量数据并对其执行查询。
阅读更多关于Java中的数据库管理:JDBC Basics
当你在列表中添加内容时,听起来你的程序只是内存不足。如果接近分配给JVM的内存限制,垃圾收集器将花费大部分时间尝试尽可能地防止内存不足。
您应该使用fast CSV库(如univocity-parsers)迭代每一行并执行所需的计算而不将所有内容存储在内存中。像这样使用它:
CsvParserSettings parserSettings = new CsvParserSettings(); //configure the parser
parserSettings.selectFields("column3", "column1", "column10"); //only read values from columns you need
CsvParser parser = new CsvParser(parserSettings);
//use this if you just need plain strings
for(String[] row : parser.iterate(new File("/path/to/your.csv"))){
//do stuff with the row
}
//or use records to get values ready for calculation
for(Record record : parser.iterateRecords(new File("/path/to/your.csv"))){
int someValue = record.getInt("columnName");
//perform calculations
}
如果出于某种原因需要多次遍历所有行,只需将数据存储在一个巨大的列表中。在这种情况下,使用-Xms8G -Xmx8G
之类的东西为程序分配更多内存。请记住,你不能拥有大小超过ArrayList
的Integer.MAX_VALUE
,这样即使你有足够的记忆,这也是你的下一个限制。
如果你真的需要一个列表,你可以使用这样的解析器:
List<Record> twentyMillionRecords = parser.parseAllRecords(new File("/path/to/your.csv"), 20_000_000);
否则,最好的办法是根据需要多次运行解析器。我建议的解析器每次应该花几秒钟来浏览文件。
希望这可以帮助
免责声明:我是这个图书馆的作者。它是开源和免费的(apache 2.0许可证)
我打赌大部分时间花在阅读数据上。拥有BufferedReader应该可以显着提高速度。
以上是关于计算Java中+ 2000万条记录的统计数据的主要内容,如果未能解决你的问题,请参考以下文章
紧急求助:如何在5秒钟内从2000万条记录的数据库中查询获取20条记录?
性能 - 使用 Spring JPA Data 搜索具有 2000 万条记录的表
如何在 TSQL 中排除 1800 万条记录的最高和最低 5% 的年薪,然后使用所选数据计算平均值