【问题标题】:Large-scale processing of seralized Integer objects序列化 Integer 对象的大规模处理
【发布时间】:2013-01-12 11:41:40
【问题描述】:

我有一个大型数据集,格式如下:

总共有 3687 个目标文件。每个包含 2,000,000 条记录。每个文件大小为 42MB。

每条记录包含以下内容:

  • 一个 id(整数值)
  • Value1(整数)
  • Value2(整数)
  • Value3(整数)

在数据收集过程中观察到每个文件的内容不会以任何方式排序或排序。

理想情况下,我想为这些数据建立一个索引。 (由 id 索引)这意味着以下内容:

  1. 将 id 集划分为可管理的块。

  2. 扫描文件以获取与当前工作组 id 相关的数据。

  3. 构建索引。

  4. 遍历下一个块并重复 1,2,3。

在我看来,这听起来不错,但来回加载 152GB 非常耗时,并且想知道最佳方法,甚至 Java 是否真的是用于此类过程的正确语言。

我的机器上有 256GB 的内存和 32 个内核。


更新: 让我修改一下,把 I/O 放在一边,假设文件在内存中的字节数组中。

解码具有 2,000,000 条记录且每条记录包含 4 个序列化的整数的 42MB 对象文件的最快方法是什么。

【问题讨论】:

  • “我想建立一个索引”——为什么?你想索引什么?你有什么要计算的吗?使用索引计算会更快吗?最重要的是:RDBMS 解决方案的索引对您有害吗?
  • @Csq 感谢您的提问。是的,我希望索引能够在以后而不是即时计算更多统计数据。 DBMS 不是我目前的选择。
  • 您到底在索引什么? ID 还是 Value1、Value2、Value3?还是别的什么?
  • @Mats OP 说 由 id 索引
  • Doh。感谢您对文本的编辑,它现在变得更具可读性。我一直盯着“按 id 索引”,但仍然没有看到它......

标签: java c++ lucene deserialization large-data


【解决方案1】:

嗯.. 似乎更好的方法是使用某种 DBMS。将所有数据加载到数据库中,您可以利用它的索引、存储和查询功能。当然,这取决于您的要求——以及现在的 DBMS 解决方案是否适合此

【讨论】:

  • 感谢您的建议。 DBMS 将永远持续 :) 我过去曾尝试过使用较小的数据集。为此类数据构建索引器是我目前的选择,我认为只有扫描此类数据可以变得更快才会更有效。
  • 嗯,非关系数据库怎么样?或者像 EHCache 这样的缓存库?如果问题出在内存消耗上,则需要某种分页算法来避免堆爆裂(仅将需要的页面保留在内存中,并将不需要的页面转移到磁盘)
  • 对于大型数据集,通常希望尽可能少地缓存到磁盘(即某种形式的数据库)以保持性能。
【解决方案2】:

鉴于您的可用内存大于数据集,并且您想要非常高的性能,您是否考虑过 Redis?非常适合对简单数据结构的操作,性能非常快。

在存储值时,请注意让 java 进行默认序列化。我以前遇到过在序列化之前我的原语被自动装箱的问题。

【讨论】:

    【解决方案3】:

    所以,我要做的就是加载每个文件并将 id 存储到某种排序结构中 - std::map 可能 [或 Java 的等价物,但考虑到它可能需要阅读大约 10-20 行代码在文件名中,然后将文件的内容读入地图,关闭文件并请求下一个文件,我可能只是编写 C++ 来做到这一点]。

    我真的不知道你还能/应该做什么,除非你真的想把它加载到一个 dbms 中——我认为这根本不是不合理的建议。

    【讨论】:

    • 当然,这是显而易见的事情。每个文件 7 秒意味着完成所有文件的读取和解码需要 7 小时。您不能将所有数据留在内存(哈希图)上,因此您需要在某个时候将其转储到磁盘并稍后再次重新读取以进行合并。简而言之,这是我已经完成的解决方案,但不是一个理想的解决方案。
    • 处理一个42MB文本文件的2000000条记录需要7秒?似乎很多。我刚刚用 2M 随机数填充了一个文件,将它们全部读取并存储在 std::map 中,在我的机器上花了 5.3 秒 - 但是我的文件几乎是你的两倍,77MB [因为随机数变得非常大大多数时候]。而且我的机器几乎不是什么超级骗子的 32 核野兽。只是现在相当老的四核 AMD 机器。不可否认,有 16GB 的 RAM,但仍然如此。
    • 我还尝试了 underored_map,它快了大约一秒 - 总时间为 4.7 秒。
    • 并将while(cin << id << a << b << c) 更改为scanf("%d %d %d %d", &id, &a, &b, &c) 将速度提高了四倍。所以你可能想看看代码的“读取文件”部分,而不是“插入表格”。
    • 谢谢垫子。我同意阅读文件,也许文件格式是需要关注的部分。
    【解决方案4】:

    您选择的文件格式非常糟糕。我会将序列化整数转换为使用 DataOutputStream.writeInt() 编写的二进制整数,然后使用 DataInputStream.readInt() 读取它们。在这两种情况下都有缓冲流。您将节省大量磁盘空间,从而也节省了 I/O 时间,并且还节省了所有序列化开销时间。并在将来更改您的收藏软件以使用此格式。转换需要一段时间,但只会发生一次。

    或者按照建议使用数据库,再次使用本机整数而不是序列化对象。

    【讨论】:

    • 我同意 EJP 的观点,即文件格式是个坏主意。我会试试这个。谢谢
    猜你喜欢
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 2022-11-27
    • 2013-02-03
    • 2023-03-15
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    相关资源
    最近更新 更多