#lucene
#lucene
Вопрос:
Я хочу искать специальные символы в индексе.
Я экранировал все специальные символы в строке запроса, но когда я выполняю запрос как в lucene в индексе, он создает запрос как ().
Следовательно, поиск выполняется без полей.
Как решить эту проблему? Мой индекс содержит эти специальные символы.
Комментарии:
1. Пожалуйста, приведите пример того, что вы ищете и что создано. Что вы имеете в виду под «запросом как «?
2. Я ищу специальные символы, такие как ! ? и т.д. Что ж, я нашел решение. На самом деле мы используем какой-то пользовательский анализатор, и из-за примененных фильтров он выдавал запрос blanck( ()). Но когда я использовал KeywordAnalyzer, это сработало. Есть какие-либо входные данные на нем?
3. Используете ли вы один и тот же анализатор для индексации и для запроса? Пожалуйста, добавьте пример кода, описывающий ваш точный запрос и то, как вы его обрабатываете, прежде чем вызывать поиск.
Ответ №1:
Если вы используете StandardAnalyzer
, это приведет к отбрасыванию не буквенных символов. Попробуйте проиндексировать то же значение с помощью WhitespaceAnalyzer
и посмотрите, сохранятся ли при этом нужные вам символы. Он также может содержать ненужные вам данные: именно тогда вы можете подумать о написании собственного анализатора, что в основном означает создание стека 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 resu<
}
Вы можете смешивать и сопоставлять эти и другие компоненты в org.apache.lucene.analysis
, или вы можете написать свои собственные специализированные TokenStream
экземпляры, которые будут встроены в конвейер обработки вашим пользовательским Analyzer
способом.
Еще одна вещь, на которую следует обратить внимание, — это какой CharTokenizer
тип вы используете. CharTokenizer
это абстрактный класс, который определяет механизм для обозначения текстовых строк. Это используется некоторыми более простыми анализаторами (но не StandardAnalyzer
). Lucene поставляется с двумя подклассами: a LetterTokenizer
и a WhitespaceTokenizer
. Вы можете создать свой собственный, который сохраняет нужные вам символы и разбивает их на те, которые вам не нужны, путем реализации boolean isTokenChar(char c)
метода.
Ответ №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[]{" ", "-", "amp;amp;", "||", "!", "(", ")", "{", "}", "[", "]", "^", """, "~", "*", "?", ":", "\"};
// 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 - amp;amp; || ! ( ) { } [ ] ^ " ~ ? : \ *";
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();
}
}
}