大数据模式匹配的数据结构

时间:2011-05-09 18:50:40

标签: algorithm data-structures hash lucene pattern-matching

问题背景

我有一个包含10个符号的有限词汇[A-J]。这些符号的含义与问题无关。它们可以是DNA碱基,音素,单词等。

项目是一系列符号。在这个问题中,所有项目都具有相同的长度(例如6)。例如。

A C B A D J

我有一个大(5M)表,其中包含从某些已知数据中采样的所有长度为6的项目的计数。 E.g。

A C B A D J     55
B C B I C F     923
A B C D E G     478

给定一个带有一个未知符号的新序列,我的任务是猜测符号。在以下示例中,缺少的符号为

B C B ? C F

猜测的简单解决方案是查看我的表格,找到符合格式B C B ? C F的最大计数项目

问题

  1. 什么是存储我的项频表的好数据结构,以便合理有效地处理时空?如果查询时的计算是合理的,我更喜欢使用更少的内存。 (我将会有很多这样的表格,所以5M数字只是一个近似值。)

  2. 哪些实施细节可以对处理速度产生很大影响?

  3. 我想到的事情:

    1. 从每个序列中创建一个字符串并使用正则表达式进行匹配。 警告:1。O(n)是不可接受的。 (2)正则表达速度很慢。 (3)字符串(至少在java中)是膨胀的。

    2. 让Lucene处理索引。关闭tfidf得分。使用短语搜索。可能会使用计数值进行评分,以便Lucene也负责排序。

    3. 使用前缀和后缀尝试索引每个项目。

    4. 将db(可能在内存中)与一个/单独列中的整个数据一起使用来处理搜索。


    5. 更新

      1. 在我的实际应用中,我将使用单独存储的长度为5,6,7,8,9,10的序列。我通过将其限制为固定长度来简化问题。因此,对使用较少内存的解决方案的约束/偏好。
      2. 我的词汇量大小可以假设在20以下。

5 个答案:

答案 0 :(得分:3)

使用尝试的决定似乎是最好的:使用叶子上的字符串出现次数,您可以轻松设计函数,该函数将返回O(log n)时间内缺少一个字符的所有可能字符串,然后你只需迭代这少量字符串,搜索最大出现次数。如果你使用从A到Z的字符,最多会有26个这样的字符串,所以迭代不会占用太多。

AFAIK,Lucene在内部对 wildcards search 使用此类机制,因此您可以连接您的字符,用KeywordAnalyzer索引它们(以省略词干),然后搜索为“ ACB?DJ”。这里唯一的限制是Lucene不能用第一个“?”处理搜索,但你可以通过在开头添加一个额外的char来绕过它(只是绕过Lucene检查的技巧)或者通过再用一个反向词的索引(将提高性能)对于带有通配符作为第一个字符的单词)。

最后,如果您首先必须计算出现次数,您可以使用一些机器学习方案,例如决策树来处理所有工作。有些情况下,当决策树用于压缩数据库并加速搜索时,您也可以这样做。使用行作为实例,将chars的位置作为属性,将chars本身作为属性值。然后运行一些像C4.5这样的算法(你可以使用名为J48的Weka's实现)进行最小的修剪和运行分类 - 算法将完成其余的工作!

答案 1 :(得分:2)

根据评论,只有1个未知,您可以执行以下操作:

但是您的数据在哈希表中。当您需要查找模式时,生成所有通配符组合,因为您的词汇量有限,这意味着最多可以查找20种模式。这听起来像一个黑客,但如果你考虑其他方法的性能影响,它很难被击败。哈希表查找是O(1),20个查找也是O(1)。

如果通配符的数量可能增加,则不建议使用此方法,尽管它可能仍然可以在2或3中表现良好。

双数组trie也可以工作,可以减少存储字符串的空间量,但性能会受到影响。

答案 2 :(得分:1)

为了唯一地表征新序列,需要两条信息:五个已知符号的序列(字符串)和未知符号的位置。如果您的字母表有10个符号,则不得超过10 ^ 5 = 100000个唯一的五符号字符串。

根据您的内存资源,这可能足够小以适应哈希表,哈希表的条目提供查找结构以找到最佳(位置,符号)组合。例如:

---------
| BCBCF | --> { 0: <heap of symbols partially ordered by frequency>, ... }
---------

这应该允许对新序列进行相当有效的查找:连接已知符号,在哈希表中查找序列,找到未知字符的位置,然后返回位于相应顶部的符号堆。

如果你可以保证在执行任何查找之前查找结构是稳定的(没有新的输入),那么你可以通过用单个符号替换每个位置索引堆来提高效率。一直处于最顶端。 (只有在有可能改变符号频率的新信息时,才需要在查找阶段使用堆结构。)

答案 3 :(得分:0)

我是这里的“所有人都错过了明显的人”。

只需使用您可以使用的任何快速键/值查找。并查找所有可能的值。这是一个小套装,不会花很长时间。除了将数据存储6次之外的任何其他事情都会变慢。

如果你的词汇量很大,那么我以前的回答是合适的。


这是我的旧(和坏)答案。

我会将它们粘贴在具有多个连锁索引的数据库中。有多少是由你决定的。

至少我会有2.我会在(col1, col2, col3, col4, col5, col6)(col4, col5, col6, col1, col2, col3)上有一个索引。这意味着,无论哪一列丢失,都有办法获取您的数据,并且只能查看最多1/1000的记录。如果您希望可以将(col1, col2, col3, col4, col5, col6)(col3, col4, col5, col6, col1, col2)(col5, col6, col1, col2, col3, col4)编入索引,将搜索范围限制为1/10000。这再次使用了一半的内存,但速度提高了10倍。 (警告,我不保证MySQL会成功找出它应该使用哪个索引。我希望其他数据库能够正确使用它,但是还没有对它进行测试。)

如果您不想使用数据库,您可以使用平衡二叉树,就像我建议使用上面的索引一样。对于任何给定的搜索,选择具有尽可能深的缺失元素的树。做范围搜索。仅针对感兴趣的行过滤返回的数据。事实上,这正是一个好的数据库应该在这些索引上面做的事情。

答案 4 :(得分:0)

db很容易解决,但另一个解决方案是树,每个节点选择一个字符,leaf将包含可能结果和计数的数组。然后在树中只需要5个步骤来匹配一个字符串。但是创建树将花费N * C时间,其中N是项目数,C是每个项目中的字符数。通配符只是树中的一个节点,可以同时从输入中删除一个字符,但保持可能的结果不变。