分析庞大的数据集

时间:2013-10-10 11:30:29

标签: java database analysis

我对大数据的主题完全陌生。我必须用数字分析一个近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还是其他语言来分析/加载这样的?我在Java列表中读取ArrayList的开销最小。如果有可能,我认为我可以尝试实现一个for循环,它将递增到数字'n',如果nextElement!= thisElement超出for循环。我想我可以通过递增一个变量来保存计数,如果条件正确则设置为零。你怎么看待这个想法,当然还有这个问题?

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

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

4 个答案:

答案 0 :(得分:1)

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

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

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

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

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

我建议使用标准shell实用程序,因为它们非常适合文本处理,并且可以这样做,但大多数语言应该能够应对。

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

答案 1 :(得分:0)

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

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

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

数据库itselft ...每个世界范围的数据库都很有用,每个数据库都有好坏之处。例如,facebook和youtube在MySQL上运行 - 所以即使MySQL也用于庞大的系统。

答案 2 :(得分:0)

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

如果您的计算机有几十GB GB,您可以尝试使用普通的java.util.hashMap。

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

然而,要获得最佳速度,您可以编写专门的程序,它类似于外部排序,但用对[数字,计数器]替换一系列相同的数字。它可以如下工作:

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

  • 将TreeMap保存为二进制文件,作为对的排序顺序

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

  • 合并已保存的文件

答案 3 :(得分:0)

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

如果您想要完全计数,排序数据(使用TeraSort,如果您有非常大的集合),那么只计算下一次完全相同的值的次数彼此。

或者使用MapReduce。将每个数字映射到(数字,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