快速有效的短语词典查找算法?

时间:2011-09-09 16:53:15

标签: java search tree lookup

假设我有一个包含几百万个单词和短语的字典。对于每个输入句子,我想识别(完全匹配)字典包含的所有单词/短语。最长的字典名称应该是首选的,没有重叠。 例如:

Sentence: "Los Angeles Lakers visited Washington State last week"
Dictionary: {Los Angeles, Lakers, Los Angeles Lakers, Washington, State, Washington State University}

Then the sentence would be tagged as follows:
[Los Angeles Lakers] visited [Washington] [State] last week. 

我能想到的一个解决方案是将字典存储在具有恒定查找时间的内存中(例如,基于散列的集合),然后从每个句子中提取所有单词n-gram(n可以设置为单词中的单词数量)字典中最长的短语)将每个短语与字典进行比较,并保持最长的短语不重叠。有更好的解决方案吗? (因为n-gram生成可能很慢)。也许树可以帮忙吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

您可能需要考虑radix treeprefix tree之类的内容,使用整个单词作为构建的一部分。这些是字典类型问题很自然的树种。

然后简单地将事物分成单词,然后搜索trie。根据预期的分组长度,你可以从正面(不情愿)或从背面(贪婪)构建。

答案 1 :(得分:2)

您可以查看DAWG (Directed acyclic word graph)。您可以将整个短语存储为DAWG中的路径。然后,您将开始匹配该句子并找到匹配为最长路径的最长短语。然后,您将同样继续执行其余不匹配的句子。白色空间需要一些特殊处理。

答案 2 :(得分:2)

以下代码执行句子的非重叠标记,优先考虑更长的匹配。

它将句子视为字符串标记数组。

它使用" max_key_size"参数(字典中键的最大大小),以避免搜索永远不会发生的匹配。 在您的示例中,生成的句子是:

<[洛杉矶湖人队],访问过,[华盛顿],[州],最后一周,

希望有所帮助:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

public class NonOverlappingTagging {

    private static ArrayList non_overlapping_tagging(String[] sentence, HashMap dict,int max_key_size) {
        ArrayList tag_sentence = new ArrayList();
        int N = sentence.length;

        if (max_key_size == -1) {
            max_key_size = N;
        }

        int i = 0;

        while (i < N) {

            boolean tagged = false;
            int j = Math.min(i + max_key_size, N); //avoid overflow

            while (j > i) {
                String[] literal_tokens = Arrays.copyOfRange(sentence, i, j);
                String literal = join(literal_tokens, " ");
                System.out.println(literal);

                if (dict.get(literal) != null) {
                    tag_sentence.add("["+literal+"]");
                    i = j;
                    tagged = true;
                }
                else {
                    j -= 1;
                }

            }

            if (!tagged) {
                tag_sentence.add(sentence[i]);
                i += 1;
            }
        }

        return tag_sentence;
    }

    private static String join(String[] sentence, String separator) {
        String result = "";
        for (int i = 0; i < sentence.length; i++) {
            String word = sentence[i];
            result += word + separator;
        }

        return result.trim();
    }

    public static void main(String[] args) {
        String[] sentence = {"Los", "Angeles", "Lakers", "visited", "Washington", "State", "last", "week"};
        HashMap <String, Integer>dict = new HashMap();
        dict.put("Los Angeles", 1);
        dict.put("Lakers", 1);
        dict.put("Los Angeles Lakers", 1);
        dict.put("Washington", 1);
        dict.put("State", 1);
        dict.put("Washington State University", 1);

        ArrayList tagging = non_overlapping_tagging(sentence, dict, -1);

        System.out.println(tagging);    
    }   
}