使用子序列匹配实现sortedMap

时间:2015-04-20 09:09:27

标签: java dictionary data-structures treemap sortedmap

我想实现一个带有键和值的sortedMap,以便通过提供一些子序列来搜索键。例如,地图包含3个条目:

abcd -> obj1
def -> obj2
abccd -> obj3

对于查询ac,结果应该是包含第1和第3个条目的子图,但对于查询acc,只应返回第3个条目。

我应该在内部使用什么样的数据结构来有效地返回这样的子图?例如,Treemap将密钥存储在树(trie)中,以便根据前缀有效地返回子图?

5 个答案:

答案 0 :(得分:1)

总结一下我在评论中所写的内容,我将其如下:

  1. 使用条目创建附加索引HashMap [2-char子序列 - >单词列表]。
  2. 另外:从给定的单词生成所有不同的2-char子序列,将此单词添加到索引图的每个对应条目。
  3. 查询:从查询中生成所有不同的2-char子序列,其中找到一个对应于索引图中最短列表的子序列,取此列表。通过完整查询过滤它并从主地图中收集相应的值。
  4. 如果查询包含一个字符,则执行完整扫描。我相信这会比为单个字符创建额外的索引具有更好的空间/复杂性,尤其是当1-char查询很少时。

答案 1 :(得分:0)

注意:我的解决方案适用于查找子字符串的情况。阅读编辑。

<强>解决方案:

使用前缀数据结构:http://en.wikipedia.org/wiki/Trie

您需要存储:

abcd -> obj1

为:

abcd -> obj1
bcd -> obj1
cd -> obj1
d -> obj1

为了找到你的结果,你将在trie中足够深入以满足条件和DFS从那里找到所有可能的解决方案。

<强>示例:

ab -> obj1
cde -> obj1
bad -> obj2

我们会在Trie中插入下一个条目:

ab -> obj1
b -> obj1
cde -> obj1
de -> obj1
e -> obj1
bad -> obj2
ad -> obj2
d -> obj2

现在假设我们寻找下一个条目:

d

首先向下移动Trie中的角色d。之后我们会DFS。我们已经在obj2,如果我们在obj1移动角色e。因此,我们可以通过条目d获得它们。

cd

首先我们移动角色c然后移动角色d。现在我们DFS和我们唯一可以找到的路径是添加导致obj1的字符e。

efg

Trie中没有满足条件的路径,因此我们没有解决方案。

修改

如果我们要查找原始元素的子字符串,我的解决方案就有效。要修改我的解决方案以使其适用于任何非传染性子字符串,您必须在Trie中插入所有排列。

答案 2 :(得分:0)

你的&#34;字符&#34;可以解释为传统搜索引擎AND查询中的术语。

来自此评论:

  

abcd的所有子序列,例如a,b,c,d,ab,ac,ad,bc,bd,cd,   abc,abd,acd,abcd等,查询时,应返回子图   abcd - &gt; obj1作为其入口之一。

我们可以解释一下,使用带有Aspid Beaver Cherokee Deer(ABCD)术语的文档时,应该在搜索任何单词或其任何组合时返回该文档。

您要为此构建的是inverted index。有关详细信息,请参阅this answer。从本质上讲,你会为每个&#34;字符&#34;构建一个HashMap或查找表(没有那么多的字符)。 (= term 在search-engine-speak中),其中查找将返回它出现的所有objX(= document 在search-engine-speak中),理想情况下按升序排列。

要查找与一组字符关联的所有对象,您可以加入每个字符的集合。由于它们是有序的,因此您可以在线性时间内计算集合交点。

如果查询ba abc键匹配,则可以优化查找表/ HashMap以存储字符位置(例如: store&#34; b在Obj1中位于0&#34;,&#34; a在Obj1中找到位置1&#34;而不是丢弃位置)。在计算搜索交叉时,您将按搜索顺序继续并丢弃具有不正确相对顺序的匹配。

这是搜索引擎的惯例,并且已经在性能方面进行了详尽的分析。


编辑:效果

如果不同的&#34;术语的数量&#34;很低(例如:26个小写英文字母)你可以通过添加n-gram作为术语来加快速度(其中,对于&#34; abc&#34;,你要添加&#34; a&#34;,& #34; b&#34;,&#34; c&#34;,&#34; ab&#34;,&#34; ac&#34;,&#34; bc&#34;,&#34; abc& #34)。相同的规则将适用 - 搜索量减半,并且由于预期会出现重叠,因此可以使用Sasha的技巧来避免存储索引。

答案 3 :(得分:0)

您可以尝试使用通配符进行aho-corasick。 Aho-Corasick是更快的多模式匹配算法,并且通过通配符可以给出所有子串。您可以在codeplex(https://phpahocorasick.codeplex.com)上尝试我的php实现。例如,带有基因模式通配符的单元测试:

$tree = new Ahocorasick\Ahocorasick();
$tree->add("AC");
$tree->add("GTG");
$tree->add("AACT");
echo $tree->match("ACCGAGTGCGTGGACAAACTACGATTGTGGAATGAACT","AC*GT");
$this->expectOutputString("ACCGAGT,ACCGAGTGCGT,ACCGAGTGCGTGGACAAACTACGATTGT,ACAAACTACGATTGT,ACTACGATTGT,ACGATTGT");

答案 4 :(得分:0)

/**
 * @author viborole
 *
 */
public class SortedMapSubsequence {

/**
 * @param args
 */
public static void main(String[] args) {
    Map<String, String> data = new HashMap<String,String>();
    data.put("abcd", "obj1");
    data.put("def", "obj2");
    data.put("abccd", "obj3");
    String query="acc";
    search(query, data);
}

private static void search(String query, Map<String, String> data) {
    for (Map.Entry<String, String> entry : data.entrySet())
    {
        String key=entry.getKey();
        char[] k=key.toCharArray();
        char[] q=query.toCharArray();
        int kpos=0;
        char[] found = new char[q.length];
        for(int i=0;i<q.length;i++){
            if(i>0){
                kpos++;
            }
            for(int j=kpos;j<k.length;j++){
                if(k[j]==q[i]){
                    kpos=j;
                    found[i]=k[j];
                    break;
                } 
            }
        }
        if(Arrays.equals(found,q)){
            System.out.println("found : "+ entry.getValue());
        }
    }
}

}