【问题标题】:Analyse a huge data set of numbers分析庞大的数字数据集
【发布时间】:2013-10-10 11:30:28
【问题描述】:

我对大数据这个话题完全陌生。我必须分析一个近 10 GB 的带有数字的文本文档。这些是近 10 亿个数字,所以对我来说,像这个文件这样分析并不是那么容易。文档的结构像一个列表,一行一个数字。我的主要问题是,您认为分析这些庞大数据集的最佳机会是什么?我的目的是找出列表包含多少个不同的数字,我想保存这个结果。

输入是这样的,有近十亿行:

123801
435345
123
7
43958112
4569
45
509858172
...

输出应该是这样的(仅作为示例):

1 2
2 4
3 1
4 109
5 56
...
高达近十亿

首先我尝试了 linux/unix 'sort' 和 'unique' 以及特定的参数,但是对于这样的,它不是一个解决方案。

我的下一个想法是尝试在数据集上实现快速排序或合并排序。是否可以在 Java 或其他语言中进行这样的分析/加载?我读到 ArrayList 在 Java 列表中开销最小。如果可能的话,我想我可以尝试实现一个 for 循环,它将递增到数字 'n' 并且如果 nextElement != thisElement 退出 for 循环。我想我可以通过增加一个变量来保存计数,如果条件正确则设置为零。您如何看待这个想法,当然还有这个问题?

我也想过为这个数据集建立一个数据库。这是更好的机会吗?如果是,哪个 DBMS 是最好的?

我对其他任何事情都很开放,我非常感谢您的意见、想法和解决方案!

【问题讨论】:

  • 您最好的方法必须是使用缓冲写入器并在数据库中递增每个数字,如果将其存储在堆上,则会引发异常。
  • 也许您应该首先更准确地了解输入的结构,因为您写的是“一行中的一个数字”。但在示例中,您每行显示两个数字。你算什么?文件中有多少个唯一行或每个数字出现的次数?
  • 对不起,这应该是它的输出,而不是输入文件。在上面进行了编辑。
  • 您是否尝试对每个数字进行频率计数?
  • 也许像 SAX 这样的东西可以处理这个问题,因为它能够流式传输文本,而不是将其全部加载到内存中。

标签: java database analysis


【解决方案1】:

如果你遵循这样的模式,它可以并行完成:

1) 将文件拆分为可管理的块(您需要使用“split -l”在行边界处拆分,因此选择适当的行数而不是绝对大小(MB))

2) 分析每个块,“awk”(gawk)脚本可以有效地做到这一点,因为文件大小不太大,内存需求是合理的;将这些中间结果写入每个块的单独文件。

3) 合并所有分析的结果 - 但这仍然需要太多内存;
也许如果您的脚本仅合并所有块中选定的数字范围,即数字 0..1000000、200000..3000000 等;这些结果对于每个范围都是确定的。对前几个块的初步分析可能会让您了解值的分布以及在哪里设置这些边界。

4) 最后将这些结果合并到一个文件中

我在这里推荐标准的 shell 实用程序,因为它们非常适合文本处理,并且可以这样做,但大多数语言应该能够应付。

例如,根据最大数字的大小,您可能需要在 Java 中使用 BigInteger;另一方面,“awk”只是将它们视为文本,因此这不是问题。

【讨论】:

    【解决方案2】:

    10GB 文件中的数字 = ~5-50 GB 内存

    问题是您无法加载所有数据然后“唯一”它们,导致 JVM 甚至您的计算机无法处理那么多 GB 的 RAM。

    因为不可能只加载一些输入,计算子结果并添加到结果中(例如添加所有数字),所以最好的方法是使用 UNIQUE 修饰符将这些数字发送到数据库。许多聪明人在数据库上工作了很多时间,以使它们尽可能快,因此它比您的任何“本地”解决方案都快得多。

    数据库本身...世界范围内的每个数据库都是有用的,每个数据库在某些方面是好是坏。例如 facebook 和 youtube 在 MySQL 上运行 - 所以即使是 MySQL 也用于大型系统。

    【讨论】:

    • 您不需要将原始数据加载到内存中。您只需要将计数保存在内存中。假设有 10 亿个唯一密钥:10 亿 *(4 字节密钥 + 4 字节计数)= 8 GB。从哈希表中添加一些浪费,16 GB。绝对适合我的内存,除非我使用低效的数据结构(在 Java 中,使用 GNU Trove TIntIntHashMap
    【解决方案3】:

    使用的核心数据结构是 Map(Integer,Integer) 来存储每个数字出现的计数器。

    如果你的机器有几十GB内存,你可以尝试使用普通的java.util.hashMap。

    否则,您可以使用任何数据库 - 每个 DBMS 都可以管理此类表。为简单起见,请使用嵌入式。

    但是,为了达到最佳速度,您可以编写专门的程序,它类似于外部排序,但用对 [number, counter] 替换一系列相同的数字。它可以按如下方式工作:

    • 读取输入文件并在 TreeMap 中收集对,直到内存可用。

    • 将 TreeMap 保存为二进制文件中的排序序列对

    • 清除 TreeMap 并继续直到输入文件结束

    • 合并保存的文件

    【讨论】:

      【解决方案4】:

      我相信他们希望您在某个时候达到概率计数。例如:Big Data Counting: How To Count A Billion Distinct Objects Using Only 1.5KB Of Memory

      如果您想要准确个计数,请对数据进行排序(使用 TeraSort,如果您的数据集非常大),然后只计算下一次完全相同的值出现的次数彼此。

      或者使用 MapReduce。将每个数字映射到 (number, 1),然后在 reducer 中对第二列求和。

      如果您想手动进行,sort 也可以执行合并。所以你可以使用split对你的数据进行分区,sort每个分区,然后sort -m分区和uniq -c计算结果。如果你想在 Java 中做到这一点:永远不要使用原始类型的 Java 集合。这浪费了大量的内存。使用 GNU Trove 类型,例如 TIntIntHashMap

      # Split into chunks of 100k lines:
      split -l100000 input temp-
      # Sort each chunk
      for nam in temp-*; do sort $nam > sorted-$nam; done
      # Merge-sort and count:
      sort -m sorted-* | uniq -c
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多