代码之家  ›  专栏  ›  技术社区  ›  SPWorley

用于查找具有相似位值的附近键的数据结构

  •  10
  • SPWorley  · 技术社区  · 17 年前

    我有一些数据,高达100万到10亿条记录,每个记录都由一个位字段表示,每个键大约64位。比特是独立的,你可以把它们想象成随机比特。

    如果我有一个测试键,并且希望在我的数据中找到具有相同键的所有值,哈希表将很容易地在O(1)中输出这些值。

    什么算法/数据结构能最有效地查找所有记录? 类似的 到查询键?这里类似的意思是大多数位是相同的,但允许最小的数字是错误的。这是传统的衡量标准 Hamming distance. ,只计算不匹配的位数。

    这个查询有两种方式,一种是指定一个不匹配率,比如“给我一个与我的查询不到6位的所有现有键的列表”,或者简单地指定一个最佳匹配,比如“给我一个与我的查询不同位数最少的10000个键的列表”。

    你可能会被临时解雇 k-nearest-neighbor algorithms 但是这里我们讨论的是独立比特,所以四叉树这样的结构似乎不太有用。

    这个问题可以通过简单的强力测试一个哈希表来解决,该哈希表的不同位数很低。例如,如果我们想找到所有与查询有一点不同的键,我们可以枚举所有64个可能的键并测试它们。但是这个爆炸很快,如果我们想允许两个比特的差异,那么我们必须探测64*63=4032次。对于更高的位数,它会以指数形式变得更糟。

    那么,是否还有另一种数据结构或策略使这种查询更有效呢? 数据库/结构可以根据您的喜好进行预处理,应该优化查询速度。

    13 回复  |  直到 13 年前
        1
  •  5
  •   Nick Johnson    17 年前

    你想要的是 BK-Tree . 它是一种非常适合索引度量空间的树(您的问题是,它支持最近邻查询和距离查询)。我写 an article 不久前的事。

    BK树通常是参照文本和使用Levenshtein距离来构建树的,但是用二进制字符串和Hamming距离来编写它是很简单的。

        2
  •  3
  •   Apocalisp    17 年前

    这听起来很适合S-Tree,它就像一个层次颠倒的文件。关于这个主题的好资源包括以下论文:

    Hierarchical Bitmap Index: An Efficient and Scalable Indexing Technique for Set-Valued Attributes.

    Improved Methods for Signature-Tree Construction (2000)

    引自第一个:

    分层位图索引e_很好地支持不同的- 查询的不同类,包括子集、超集和相似性查询。 实验表明,层次位图索引的性能优于 其他集合索引技术很有意义。

    这些论文包括对其他可能有用的研究的参考,例如 M-Trees .

        3
  •  3
  •   PeterAllenWebb    17 年前

    创建二叉树(特别是 trie )用以下方式表示开始集中的每个键:根节点是空字,向下移动树到左边会附加0,向下移动右键会附加1。树的叶数将与起始集的元素数相同,因此大小应保持可控。

    现在,您可以对该树进行递归遍历,在执行的每一个递归行中,最多允许与查询键有N个“偏差”,直到您在开始集合中找到在该偏差数范围内的所有节点为止。

        4
  •  1
  •   Jay Kominek    17 年前

    我愿意和你一起去 inverted index 像搜索引擎一样。基本上你有64个固定词汇表。然后通过汉明距离来测量相似性,而不是像搜索引擎希望使用的余弦相似性。构建索引会很慢,但是您应该能够以正常的搜索引擎速度进行查询。

    书 Introduction to Information Retrieval 包括倒排索引的高效构造、存储、压缩和查询。

        5
  •  1
  •   Community Mohan Dere    9 年前

    "Near-optimal hashing algorithms for approximate nearest neighbor in high dimensions" 从2008年开始,这似乎是迄今为止最好的结果。我一年多以前读过这本书,而且它毛茸茸的,所以我不想总结。这是从一页 locality-sensitive hashing 以及该方案的早期版本的实现。对于更一般的指针,请阅读 nearest neighbor search .

    以前有人问过这种问题: Fastest way to find most similar string to an input?

        6
  •  1
  •   Ray    17 年前

    数据库/结构可以是 预处理为 随你喜欢

    好。。。 如果 那是真的。那么你所需要的就是一个汉明距离的相似度矩阵。通过大距离修剪使矩阵稀疏。它不会变快,也不会像记忆猪那么多。

        7
  •  0
  •   Martin Hock    17 年前

    好吧,您可以将所有相邻的键和原始键一起插入。这意味着对于k个不同的位,您存储(64选择k)倍的数据,它将要求您预先决定k。尽管您可以通过强制查询邻居来扩展k,但这将自动查询您插入的邻居的邻居。这也给了你一个时空权衡:例如,如果你接受一个64倍的数据放大和64倍的慢,你可以得到两位的距离。

        8
  •  0
  •   David Johnstone    17 年前

    我还没有完全想清楚,但我知道从哪里开始。

    你可以把搜索空间分成 桶 每个桶都有一个 桶键 桶中的钥匙是与这个桶钥匙更相似的钥匙,而不是任何其他桶钥匙。要创建bucket密钥,您可以随机生成64位密钥并丢弃任何与以前创建的bucket密钥太近的密钥,或者您可以制定一些生成完全不同的密钥的算法。要找到与测试密钥最接近的密钥,首先要找到最接近的bucket密钥,然后测试bucket中的每个密钥。(实际上,最近的钥匙可能在另一个桶中,但不太可能在另一个桶中-您需要找到最近的钥匙,还是非常近的钥匙足够好?)

        9
  •  0
  •   ilya n.    17 年前

    如果你对概率方法没意见的话,我认为有一个很好的方法来解决问题2。我假设你有2^30的数据和 cutoff 你想找到里面所有的点 截止 距离 test .

    One_Try()
        1. Generate randomly a 20-bit subset S of 64 bits
        2. Ask for a list of elements that agree with test on S (about 2^10 elements)
        3. Sort that list by Hamming distance from test 
        4. Discard the part of list after cutoff
    

    你重复 One_Try 在合并列表时尽可能多。你的尝试次数越多,你发现的点数就越多。例如,如果 x 在5位之内,你会在一次尝试中找到它,大约(2/3)^5=13%的概率。因此,如果你重复100次尝试,你会发现除了大约10 ^-6以外的所有尝试。 X . 总时间: 100*(1000*log 1000) .

    这样做的主要优点是,您可以在继续操作时输出问题2的答案,因为在前几次尝试之后,您肯定会发现距离内的所有内容都不超过3位,等等。

    如果你有很多台计算机,你会给它们中的每一台进行多次尝试,因为它们是完全可并行的:每台计算机都会提前保存一些哈希表。

        10
  •  0
  •   bortzmeyer    17 年前
        11
  •  0
  •   Apurv    13 年前

    假设您必须访问每一行来测试它的值(或者如果对位字段进行索引,则对每个索引项进行索引),那么您可以使用

    异或B

    要找到不同的位,然后使用如下技术对结果进行位计数 this .

    这实际上给了你汉明距离。

    因为每个测试可以编译成数十条指令,所以运行速度非常快。

        12
  •  0
  •   Apurv    13 年前

    如果您对随机算法(在本例中是蒙特卡罗)没问题,可以使用 minhash .

        13
  •  -1
  •   Harper Shelby damiankolasa    17 年前

    如果数据不是那么稀疏,那么一个以关键点作为顶点和边的图连接“相邻”(Hamming Distance=1)节点可能是非常有效的时间方面。但是空间会很大,所以在你的情况下,我不认为这是一个值得的折衷。