【问题标题】:Handling large String lists in java在java中处理大型字符串列表
【发布时间】:2011-11-29 05:30:20
【问题描述】:

我有一个任务,我必须遍历数十亿行字符串并检查每一个是否都是唯一的。 PC 的 RAM 内存中无法容纳所有线路本身。此外,行数可能大于 Integer.MAX_VALUE。

我假设处理这么多数据的最佳方法是将每个字符串的哈希码放入某种哈希表中。

所以,这是我的问题:

  1. 我应该使用什么来代替String.hashCode()? (返回值是int,但我可能需要long)
  2. 处理这种大小的列表的最快方式/框架是什么?我最需要的是能够快速检查列表是否包含元素

【问题讨论】:

  • 为什么不利用数据库的力量呢?是否需要严格在java中完成?
  • 如果它是一个选项,“数据库”的想法是伟大的。此外,您需要考虑两种“最坏情况”:a)每个字符串都是唯一的,b)每个字符串都是相同的。无论您想出什么解决方案,您是否拥有处理这两种情况的磁盘/RAM 容量和时间/计算能力?
  • 行数可以有多大?我知道大于 MAX_VALUE - 大于 32 * MAX_VALUE?大于...?
  • 最大字符串数可能在 int32.maxValue 和 int64.maxValue 之间。坦率地说,数据库看起来不错,但这是完成任务的最快方法吗?我的意思是,在实施后的执行时间?
  • 在 Unix 上,我会使用 sort {file} | uniq -c 来查找重复的字符串。也许您不需要编写程序来执行此操作。

标签: java data-structures bigdata hashset


【解决方案1】:

你想太多了,这一切都可以通过一个 MySQL 表非常简单地完成,该表将数据保存到磁盘而不是将所有内容保存在内存中。这么多数据从来都不是由独立应用程序有效处理的。

CREATE TABLE TONS_OF_STRINGS
(
  unique_string varchar(255) NOT NULL,
  UNIQUE (unique_string)
)

只需遍历这些值(假设这里是逗号分隔的列表)并尝试插入每个标记。每个失败的令牌都是重复的。

public static void main(args) {
  Connection con = DriverManager.getConnection("jdbc:mysql://localhost/database","username","password");
  FileReader file = new FileReader("SomeGiantFile.csv");
  Scanner scan = new Scanner(file);
  scan.useDelimiter(",");
  String token;
  while ( scan.hasNext() ) {
    token = scan.next();
    try {
      PreparedStatement ps = con.prepareStatement("Insert into TONS_OF_STRING (UNIQUE_STRING) values (?)");
      ps.setString(1, token);
      ps.executeUpdate();
    } catch (SQLException e) {
      System.out.println("Found duplicate: " + token );
    }
  }
  con.close();
  System.out.println("Well that was easy, I'm all done!");
  return 0;
}

完成后别忘了清空表格,这是很多数据。

【讨论】:

  • 正是忽必烈上面的建议。
【解决方案2】:

仅仅存储 32 位或 64 位哈希码是不够的,因为两个不同的字符串(几十亿个)很容易拥有相同的哈希码。一旦你有两个具有相同哈希码的字符串,你需要比较实际的字符串,看看它们是否真的相等。

这是我解决这个问题的方法:

  1. 读取文件/字符串流:

    1. 阅读每一行

    2. 计算行的哈希码

    3. 将哈希码和字符串写入临时文件,并在其间使用合适的字段分隔符

  2. 使用合适的外部排序程序对临时文件进行排序,使用哈希码字段作为主排序键,字符串字段作为辅助排序键。

  3. 一次读取一行临时文件。如果两个连续的行具有相同的哈希码字段和不同的字符串字段,那么您发现了一个重复的字符串。

注意:这种方法同样适用于 32 位或 64 位哈希码。

【讨论】:

    猜你喜欢
    • 2011-06-15
    • 1970-01-01
    • 2023-02-26
    • 1970-01-01
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多