Как искать специальные символы (+! \?:) В Lucene - PullRequest
11 голосов
/ 24 мая 2011

Я хочу искать специальные символы в индексе.

Я избежал всех специальных символов в строке запроса, но когда я выполняю запрос как + на lucene в индексе, он создает запрос как + ().

Отсюда и поиск по полям.

Как решить эту проблему?Мой указатель содержит эти специальные символы.

Ответы [ 2 ]

11 голосов
/ 25 мая 2011

Если вы используете StandardAnalyzer, это приведет к удалению не буквенных символов.Попробуйте индексировать то же значение с помощью WhitespaceAnalyzer и посмотрите, сохранит ли оно нужные вам символы.Он также может хранить вещи, которые вам не нужны: вот когда вы можете подумать о написании собственного Analyzer, что в основном означает создание стека TokenStream, который выполняет именно тот тип обработки, который вам необходим.

Например, SimpleAnalyzer реализует следующий конвейер:

@Override
public TokenStream tokenStream(String fieldName, Reader reader) {
   return new LowerCaseTokenizer(reader);
}

, который просто вводит токены в нижнем регистре.

StandardAnalyzer делает гораздо больше:

/** Constructs a {@link StandardTokenizer} filtered by a {@link
StandardFilter}, a {@link LowerCaseFilter} and a {@link StopFilter}. */
@Override
public TokenStream tokenStream(String fieldName, Reader reader) {
    StandardTokenizer tokenStream = new StandardTokenizer(matchVersion, reader);
    tokenStream.setMaxTokenLength(maxTokenLength);
    TokenStream result = new StandardFilter(tokenStream);
    result = new LowerCaseFilter(result);
    result = new StopFilter(enableStopPositionIncrements, result, stopSet);
    return result;
 }

Вы можете смешивать исовпадают с этими и другими компонентами в org.apache.lucene.analysis, или вы можете написать свои собственные специализированные TokenStream экземпляры, которые обернуты в конвейер обработки вашим пользовательским Analyzer.

Еще одна вещь, на которую стоит обратить внимание, это то, чтовроде CharTokenizer вы используете.CharTokenizer - это абстрактный класс, который определяет механизм токенизации текстовых строк.Он используется некоторыми более простыми анализаторами (но не StandardAnalyzer).Lucene поставляется с двумя подклассами: LetterTokenizer и WhitespaceTokenizer.Вы можете создать свой собственный, который хранит нужные вам символы и разбивает на те, которые вам не нужны, реализуя метод boolean isTokenChar(char c).

1 голос
/ 12 октября 2015

Возможно, это не актуально для автора, но для возможности поиска нужных вам специальных символов:

  1. Создать собственный анализатор
  2. Используйте его для индексации и поиска

Пример, как это работает для меня:

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.custom.CustomAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.RAMDirectory;
import org.junit.Test;

import java.io.IOException;

import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;

public class LuceneSpecialCharactersSearchTest {

/**
 * Test that tries to search a string by some substring with each special character separately.
 */
@Test
public void testSpecialCharacterSearch() throws Exception {
    // GIVEN
    LuceneSpecialCharactersSearch service = new LuceneSpecialCharactersSearch();
    String[] luceneSpecialCharacters = new String[]{"+", "-", "&&", "||", "!", "(", ")", "{", "}", "[", "]", "^", "\"", "~", "*", "?", ":", "\\"};

    // WHEN
    for (String specialCharacter : luceneSpecialCharacters) {
        String actual = service.search("list's special-characters " + specialCharacter);

        // THEN
        assertThat(actual, equalTo(LuceneSpecialCharactersSearch.TEXT_WITH_SPECIAL_CHARACTERS));
    }
}

private static class LuceneSpecialCharactersSearch {
    private static final String TEXT_WITH_SPECIAL_CHARACTERS = "This is the list's of special-characters + - && || ! ( ) { } [ ] ^ \" ~ ? : \\ *";

    private final IndexWriter writer;

    public LuceneSpecialCharactersSearch() throws Exception {
        Document document = new Document();
        document.add(new TextField("body", TEXT_WITH_SPECIAL_CHARACTERS, Field.Store.YES));

        RAMDirectory directory = new RAMDirectory();
        writer = new IndexWriter(directory, new IndexWriterConfig(buildAnalyzer()));
        writer.addDocument(document);
        writer.commit();
    }

    public String search(String queryString) throws Exception {
        try (IndexReader reader = DirectoryReader.open(writer, false)) {
            IndexSearcher searcher = new IndexSearcher(reader);

            String escapedQueryString = QueryParser.escape(queryString).toLowerCase();

            Analyzer analyzer = buildAnalyzer();
            QueryParser bodyQueryParser = new QueryParser("body", analyzer);
            bodyQueryParser.setDefaultOperator(QueryParser.Operator.AND);


            Query bodyQuery = bodyQueryParser.parse(escapedQueryString);
            BooleanQuery query = new BooleanQuery.Builder()
                    .add(new BooleanClause(bodyQuery, BooleanClause.Occur.SHOULD))
                    .build();
            TopDocs searchResult = searcher.search(query, 1);

            return searcher.doc(searchResult.scoreDocs[0].doc).getField("body").stringValue();
        }
    }

    /**
     * Builds analyzer that is used for indexing and searching.
     */
    private static Analyzer buildAnalyzer() throws IOException {
        return CustomAnalyzer.builder()
                .withTokenizer("whitespace")
                .addTokenFilter("lowercase")
                .addTokenFilter("standard")
                .build();

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