Как добавить параметры для анализа в Apache Lucene? - PullRequest
0 голосов
/ 24 ноября 2011

В Lucene есть анализаторы, которые в основном токенизируют и фильтруют корпус при индексации.Операции включают в себя преобразование токенов в нижний регистр, создание стволов, удаление стоп-слов и т. Д.

Я провожу эксперимент, в котором я хочу попробовать все возможные комбинации операций анализа: только остановка, только остановка, остановка и остановка, ...

Всего 36 комбинаций, которые я хочу попробовать.

Как мне легко и изящно это сделать?

Я знаю, что могу расширить класс Analyzer.и реализовать функцию tokenStream () для создания моего собственного анализатора:

public class MyAnalyzer extends Analyzer
{

public TokenStream tokenStream(String field, final Reader reader){
return new NameFilter(
    CaseNumberFilter(
            new StopFilter(
                    new LowerCaseFilter(
                            new StandardFilter(
                                    new StandardTokenizer(reader)
                    )
            ), StopAnalyzer.ENGLISH_STOP_WORDS)
    )
);
}

Я хотел бы написать один такой класс, который может каким-то образом принимать логические значения для каждой из возможных операций (doStopping,доСтемминг и т. д.).Я не хочу писать 36 различных классов Analyzer, каждый из которых выполняет одну из 36 комбинаций.Что затрудняет то, как фильтры все объединяются вместе в своих конструкторах.

Есть идеи, как это сделать изящно?

РЕДАКТИРОВАТЬ : «Изящно»Я имею в виду, что я могу легко создать новый Анализатор в каком-то цикле:

analyzer = new MyAnalyzer(doStemming, doStopping, ...)

, где doStemming и doStopping меняются с каждой итерацией цикла.

Ответы [ 2 ]

2 голосов
/ 24 ноября 2011

Solr решает эту проблему, используя фабрики Tokenizer и TokenFilter.Вы можете сделать то же самое, например:

public interface TokenizerFactory {
    Tokenizer newTokenizer(Reader reader);
}

public interface TokenFilterFactory {
    TokenFilter newTokenFilter(TokenStream source);
}

public class ConfigurableAnalyzer {

    private final TokenizerFactory tokenizerFactory;
    private final List<TokenFilterFactory> tokenFilterFactories;

    public ConfigurableAnalyzer(TokenizerFactory tokenizerFactory, TokenFilterFactory... tokenFilterFactories) {
        this.tokenizerFactory = tokenizerFactory;
        this.tokenFilterFactories = Arrays.asList(tokenFilterFactories);
    }

    public TokenStream tokenStream(String field, Reader source) {
        TokenStream sink = tokenizerFactory.newTokenizer(source);
        for (TokenFilterFactory tokenFilterFactory : tokenFilterFactories) {
            sink = tokenFilterFactory.newTokenFilter(sink);
        }
        return sink;
    }

}

Таким образом, вы можете настроить свой анализатор, передав фабрику для одного токенизатора и от 0 до n фильтров в качестве аргументов конструктора.

0 голосов
/ 25 ноября 2011

Добавьте некоторые переменные класса в пользовательский класс Analyzer, которые можно легко устанавливать и отключать на лету. Затем в функции tokenStream () используйте эти переменные, чтобы определить, какие фильтры выполнять.

public class MyAnalyzer extends Analyzer {

    private Set customStopSet; 
    public static final String[] STOP_WORDS = ...;

    private boolean doStemming = false;
    private boolean doStopping = false;

    public JavaSourceCodeAnalyzer(){
            super();
            customStopSet = StopFilter.makeStopSet(STOP_WORDS);
    }

    public void setDoStemming(boolean val){
            this.doStemming = val;
    }

    public void setDoStopping(boolean val){
            this.doStopping = val;
    }

    public TokenStream tokenStream(String fieldName, Reader reader) {

            // First, convert to lower case
            TokenStream out = new  LowerCaseTokenizer(reader);

            if (this.doStopping){
                    out = new StopFilter(true, out, customStopSet);
            }

            if (this.doStemming){
                    out = new PorterStemFilter(out);
            }

            return out;
    }
}

Есть одна ошибка: LowerCaseTokenizer принимает в качестве входных данных переменную читателя и возвращает TokenStream. Это хорошо для следующих фильтров (StopFilter, PorterStemFilter), потому что они принимают TokenStreams в качестве входных данных и возвращают их в качестве выходных, и поэтому мы можем аккуратно связать их вместе. Однако это означает, что у вас не может быть фильтра перед LowerCaseTokenizer, который возвращает TokenStream. В моем случае я хотел разбить слова camelCase на части, и это нужно сделать перед преобразованием в нижний регистр. Мое решение состояло в том, чтобы выполнить разделение вручную в пользовательском классе Indexer, поэтому к тому времени, когда MyAnalyzer увидит текст, он уже был разделен.

(Я также добавил логический флаг в свой класс Indexer, так что теперь оба могут работать исключительно на основе флагов.)

Есть лучший ответ?

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