Быстрый и эффективный алгоритм поиска по словарю фраз? - PullRequest
2 голосов
/ 09 сентября 2011

Допустим, у меня есть словарь с несколькими миллионами слов и фраз. Для каждого входного предложения я хочу идентифицировать (точное совпадение) все слова / фразы, которые содержит словарь. Самое длинное имя словаря должно быть предпочтительным и не должно совпадать. Например:

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-граммов слов из каждого предложения (n может быть установлено на количество слов в самая длинная фраза в словаре) сравнивая каждую со словарем и сохраняя самые длинные фразы, которые не пересекаются. Есть ли лучшее решение? (потому что поколение n-грамм может быть медленным). Может быть, деревья могут помочь?

Спасибо!

Ответы [ 3 ]

2 голосов
/ 09 сентября 2011

Вы можете посмотреть на DAWG (Направленный ациклический граф слов) . Вы должны хранить целые фразы как пути в DAWG. Затем вы начинаете совпадать с предложением и находите самую длинную фразу, которая соответствует самому длинному пути. Затем вы продолжите с остальным непревзойденным предложением аналогичным образом. Пустое пространство потребует особой обработки.

2 голосов
/ 23 марта 2012

Следующий код выполняет неперекрывающуюся маркировку предложения, отдавая приоритет более длинным совпадениям.

Он обрабатывает предложение как массив строковых токенов.

Он использует параметр "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);    
    }   
}
2 голосов
/ 09 сентября 2011

Возможно, вы захотите рассмотреть что-то вроде radix tree или prefix tree , используя целые слова как часть вашего наращивания.Это те деревья, которые являются естественными для проблем типа словаря.

Затем просто разбейте вещи на слова и выполните поиск по дереву.В зависимости от ожидаемой длины групп, вы будете строить спереди (неохотно) или сзади (жадные).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...