什么数据结构用于大数据集的近实时查找?

时间:2013-05-22 01:58:39

标签: data-structures

我有一个2000万人的数据集,其位置是众所周知的。在接近实时的情况下,我想知道我收到的查询是否在此集合中,如果是,则是实际位置。基本上,我想要一个大型哈希表。由于卷(每秒数千个查询),为Redis / Memcached支付网络往返是不可能的。

是否有可以提供非常快速的成员资格测试和数据检索的数据结构?可以接受少量错误。

有些地方比其他地方更受欢迎。例如,“美国,纽约,纽约”的出现频率远高于“美国,阿拉斯加,安克雷奇”。

5 个答案:

答案 0 :(得分:1)

“2000万” - “我想要一个大型哈希表” - 听起来你已经有了答案。包含2000万个项目的哈希映射很容易适合单个进程在单个机器上使用的内存。

  • C ++:std::unordered_map<Key, Value>
  • C#:System.Collections.Generic.Dictionary<Key, Value>
  • Java:java.util.HashMap<Key, Value>
  • Scala:HashMap[Key, Value]

如果您告诉我们您使用的语言,我们可以为您指出该语言的确切类型。

此外 - 尽管我认为这可能有点过分 - 你可以使用辅助Bloom filter(猖獗的想法 - 不是我的 - 只是为了完整而将其包括在内)以便在给定人员的情况下加速成员资格测试(键)在哈希映射中

答案 1 :(得分:1)

您可以使用Bloomier filter

  

布隆过滤器 [...] 是一种节省空间的概率数据结构,用于测试元素是否是集合的成员。假阳性检索结果是可能的,但假阴性不是;即查询返回&#34;内部集合(可能是错误的)&#34;或者&#34;绝对不在集合中#34;。元素可以添加到集合中,但不会被删除(尽管可以通过计数过滤器来解决)。添加到集合中的元素越多,误报的可能性就越大。

     

<强> [...]

     

Chazelle等人。 (2004)设计了Bloom过滤器的泛化,它可以将值与已插入的每个元素相关联,从而实现关联数组。与布隆过滤器一样,这些结构通过接受小的假阳性概率来实现小的空间开销。在&#34; Bloomier过滤器&#34;的情况下,误报被定义为当键不在地图中时返回结果。地图永远不会为地图中的键返回错误的值。

答案 2 :(得分:0)

一种选择是使用简单明了的地图:

// Scala
val locations: Map[String, Geo] = Map.empty
def location(id: String): Option[Geo] = locations.get(id)

但这会耗费大量内存。

答案 3 :(得分:0)

A Judy Array

  

是一种具有高性能,低内存使用率并实现关联数组的数据结构。

Judy阵列显然压缩得很好,速度很快。

答案 4 :(得分:0)

使用排序数组并进行二进制搜索是另一种选择:

val ids: Array[Long] = new Array(30000000)
val values: Array[Int] = new Array(30000000)
var lookups = Map.empty[String, Int]

// populate ids with sorted array read from disk
Source.fromFile("sorted.csv").map(_.split("\t")).zipWithIndex.foreach {
    case (Array(id, value), index) =>
        ids[index] = id.toLong
        values[index] = lookups.get(value) match {
            case Some(valueIndex) => valueIndex
            case None =>
              val valueIndex = values.size + 1
              lookups = lookups.updated(value, valueIndex)
              valueIndex
        }
}

// Flip lookups around: value becomes key, key becomes value
val realLookup = lookups.foldLeft(Map.empty[Int, String]) {
    case (memo, (value, index)) => memo.updated(index, value)
}

// Usage:
Source.fromFile("ids.csv").foreach {
    idStr =>
        val id = idStr.toLong
        val index = java.util.Arrays.binarySearch(ids, id)
        if (index < 0) {
            // Unknown -- check javadoc
            println(idStr)
        } else {
            // Known
            println(id + "\t" + realLookup(values(index))
        }
}