【问题标题】:Array-like data structure efficient in terms of insert & find time在插入和查找时间方面有效的类数组数据结构
【发布时间】:2011-05-05 14:41:09
【问题描述】:

我需要一个以Ruby 语言实现的数据结构来容纳大量不同的网址(例如10**10 片段),所以性能是我关心的问题。 我正在使用Array 并保持其元素有序,因此我可以执行binary search 来查找是否已经存在或者快速插入网址的位置。 我是这样写的:

class UrlStore
    def initialize(*args)
        @urls = []
        args.each { |e| add(e) unless e.class != String }
    end

    def add(url)
        p = find(url)
        @urls.insert(p, url) unless p.class == String
    end


    def find(url)
        l, m, h = 0, 0, @urls.size - 1

        while l <= h do
            m = l + (h - l) / 2
            b = url <=> @urls[m]
            if b == 0
                return m.to_s
            elsif b == 1
                l = m + 1
            else
                h = m - 1
            end
        end

        return l
    end
end

find 方法如果找到,将返回 url 在托管数组中的位置,但以String 形式返回,以便与找到的插入位置进行区分;否则,返回一个整数(Fixnum),告诉 url 应该去哪里以保持数组有序。

但请注意,我使用Array#insert 在指定位置添加元素。我的直觉告诉我,这种方法会将插入点后的所有元素向后移动一步,这可能会导致严重的性能下降。 Array 模块不在标准库中,它是 Ruby 的固有数据类型,所以我不知道我是否正确。

可能是用于托管此类任务的数据结构太天真了。 所以任何人都可以分享一个很棒的。

【问题讨论】:

  • 假设每个 URL 平均有 40 个字节。对于 1e10 URL,存储信息需要超过 370 GB 的内存。显然您没有用于此的 RAM,因此显然您需要一个数据库。
  • 无论如何,二分搜索不是要走的路。如果可以的话,你会使用哈希查找(参见 Set 解决方案)
  • 数组非常适合队列和堆栈,您可以在其中按顺序添加和删除元素,但是当您必须搜索大型数组时它们真的会崩溃。当您随机访问一个元素或需要检查它的存在时,哈希值会好得多。当您突破内存限制时,您需要考虑将查找和存储卸载到数据库。至少一个键/值存储,或类似 SQLite 的东西会有所帮助。我更喜欢 Postgres 或 MySQL,因为它们非常聪明,并且随着应用需求的增长提供了许多有用的功能。

标签: ruby performance data-structures


【解决方案1】:

如果按照 Phrogz 的建议,您确实设法获得了 370GB 内存,或者您意识到实际上不需要存储那么多 URL,您可能需要考虑使用 SortedSet

【讨论】:

  • 或者一个简单的SetSortedSet 永远不会比 Set 快​​;它有一个在这里不需要的额外保证。
  • 在问题中要求元素保持有序。
  • 从 OP 中,我收集到元素保持有序因此他可以执行二进制搜索。使用哈希查找(SetOrderedSet 使用)优于二分查找,因此不再需要顺序。
  • @Marc-AndréLafortune:谢谢,我会比较一下这些。
  • @Marc-AndréLafortune,不错,我的大脑过滤掉了那一点。
【解决方案2】:

您可能想了解越来越多的开源 NoSQL 解决方案,包括 MongoDB、Cassandra、Kyoto Cabinet 或 Redis。

MongoHQ 为 MongoDB 提供免费的托管服务。 RedisToGo 为 Redis 提供免费的托管服务。两者都有非常易于使用的 Ruby 绑定。我都用过,推荐一下。

我听说过有关 Cassandra 和京都内阁的好消息,但没有在任何生产应用程序中使用它们。

【讨论】:

  • 是的,Nosql负责快速查询。但我想在合理的时间内完成整个任务,而不仅仅是单个查询/插入。这意味着计算通信(http请求)时间,所以如果不使用本地Nosql,将会有很重的HTTP连接负担。事实上,我想要的是在商用机器上完成所有这些工作。因此,需要一个好的数据结构。不关心数字10**10,我只是想描述一下任务负载,可能我对数量没有概念:),1000万对我来说就足够了。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2012-04-20
  • 1970-01-01
  • 2023-03-27
  • 2013-06-29
  • 2013-03-05
  • 2022-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多