Lucene Indexing / Query стратегия для переносимых слов - PullRequest
2 голосов
/ 08 февраля 2011

Есть много слов, которые разделены пробелами или пробелами, но часто используются как одно слово. Например: Баскетбольный мяч или баскетбольный мяч можно записать как баскетбольный мяч.

Теперь, когда я индексирую в качестве предложения, скажем: "Hey dude, I played basket ball yesterday". Теперь я пытаюсь запросить "basketball" [без двойных кавычек] ..

В этом случае или в обратном случае (индекс basketball и запрос basket ball) я не получу никаких результатов. Есть ли способ решить эту проблему прямо или косвенно?

Edit:
Я привел пример, чтобы просто продемонстрировать проблему. В моем реальном сценарии приложения я буду индексировать и искать идентификаторы. Если я индекс: 011 12345,
Я должен быть в состоянии запросить его, используя 01112345.

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 08 февраля 2011

Дефисы здесь не проблема, если вы используете что-то вроде StandardTokenizer, который разделяется на токены, такие как дефисы, тогда пользователи, ищущие «баскетбол», будут соответствовать исходному тексту «Баскетбол» (и наоборот) так что никаких проблем нет.

Проблема идет между двумя словами и эквивалентами одного слова, например, «баскетбол» и «баскетбол». В основном вам нужно использовать синонимы (например, куртка / пальто или в вашем случае баскетбол / 'баскетбольный мяч').

Вы можете преодолеть это, создав список эквивалентных слов самостоятельно или воспользовавшись словарем, подобным WordNet , и добавив в индекс или поиск синонимы для каждого термина. Solr имеет SynonymFilter , который вы, вероятно, можете использовать (см. Также здесь ).

EDIT:

Вот код для очень простого фильтра синонимов, который я написал некоторое время назад. Синонимы не являются внешними, но вы легко можете добавить это сами.

public class SynonymFilter extends TokenFilter {
    private static final Logger log = Logger.getLogger(SynonymFilter.class);

    private Stack<Token> synStack = new Stack<Token>();

    static CharArrayMap<String[]> synLookup = new CharArrayMap<String[]>(5, true);
    static {
        synLookup.put("basketball".toCharArray(), new String[]{"basket ball"});
        synLookup.put("trainer".toCharArray(), new String[]{"sneaker"});
        synLookup.put("burger".toCharArray(), new String[]{"hamburger"});
        synLookup.put("bike".toCharArray(), new String[]{"bicycle", "cycle"});
    }

    // TODO reverse map all the syns to each other e.g. sneaker to trainer

    protected SynonymFilter(TokenStream input) {
        super(input);
    }

    @Override
    public Token next(Token reusableToken) throws IOException {
        if (synStack.size() > 0)
            return synStack.pop();

        Token nextToken = input.next(reusableToken);
        if (nextToken != null) {
            addSynonyms(nextToken);
        }

        return nextToken;
    }

    private void addSynonyms(Token nextToken) {
        char[] word = Arrays.copyOf(nextToken.termBuffer(), nextToken.termLength());
        String[] synonyms = synLookup.get(word);
        if (synonyms != null) {
            for (String s : synonyms) {
                if (!equals(word, s)) {
                    char[] chars = s.toCharArray();
                    Token synToken = new Token(chars, 0, chars.length, nextToken.startOffset(),  nextToken.endOffset());
                    synToken.setPositionIncrement(0);
                    synStack.add(synToken);
                    log.info("Found synonym: " + s + " for: " + new String(nextToken.term()));
                }
            }
        }
    }

public static boolean equals(char[] word, String subString) {
    return equals(word, word.length, subString);
}

public static boolean equals(char[] word, int len, String subString) {

    if (len != subString.length())
        return false;

    for (int i = 0 ; i < subString.length(); i++) {
        if (word[len - i - 1] != subString.charAt(subString.length() - i - 1))
            return false;
    }

    return true;

}
}
0 голосов
/ 08 февраля 2011

Я не пользователь Lucene, но вот мои 2 цента: перед тем, как начать индексирование, вы должны предварительно обработать ваши данные, чтобы они выглядели так, как вы хотите их искать.Вы также хотите, чтобы он появлялся в результатах поиска, если кто-то ищет только мяч?Если да, то вы должны сделать два предложения в качестве входных данных для этого единственного предложения («эй, чувак, я играл в баскетбол вчера» и «эй, чувак, я играл в баскетбол вчера») и индексировать их оба.Это то, что вы ищете?

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