Lucene не работает поиск "шаблон" и "*"
Я использую Lucene 8.9.0.
Например у меня есть шаблон ABC и я хочу найти ABCaaa, для этого я использую оператор "*" и мой запрос на поиск выглядит так: ABC*.
Но при этом если, я хочу найти aaaABC, я предполагаю, что надо оператор "*" поставить перед ABC, чтобы запрос выглядел так: "*ABC".
Я ставлю оператор звездочка перед моим шаблоном, выполняю запрос:
QueryParser parser = new QueryParser(rword.getSearchField(), getAnalyzer());
Query query = null;
TopDocs topDocs = null;
try{
query = parser.parse("*ABC");
topDocs = searcher.search(query, 100);
}
catch(Exception e){
System.out.println("[ERROR - inMemoryLuceneIndex] Ошибка поиска шаблона: "+rword.getOriginalView());
System.out.println("Возможная причина: неправильно задан шаблон. Возможно в нем есть символы: 1)/ ");
e.printStackTrace();
}
ScoreDoc[] hits = topDocs.scoreDocs;
for (ScoreDoc hit : hits) { //Пройтись по найденным документам из индекса
handleHit(hit, query, reader, searcher, curDoc, rword, categ, isMetadata, isShortText);
}
и код переходит в секцию catch(), где я вижу такое сообщение об ошибки данной операции:
org.apache.lucene.queryparser.classic.ParseException: Cannot parse '*ABC': '*' or '?' not allowed as first character in WildcardQuery
at org.apache.lucene.queryparser.classic.QueryParserBase.parse(QueryParserBase.java:114)
at com.mycompany.stackexp.Rubricator.CustomIndex.query_OneWord(CustomIndex.java:192)
at com.mycompany.stackexp.Rubricator.Rubricator.toRubricateContent(Rubricator.java:234)
at com.mycompany.stackexp.TaskCallable.call(TaskCallable.java:209)
at com.mycompany.stackexp.TaskCallable.call(TaskCallable.java:40)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.lucene.queryparser.classic.ParseException: '*' or '?' not allowed as first character in WildcardQuery
at org.apache.lucene.queryparser.classic.QueryParserBase.getWildcardQuery(QueryParserBase.java:700)
at org.apache.lucene.queryparser.classic.QueryParserBase.handleBareTokenQuery(QueryParserBase.java:820)
at org.apache.lucene.queryparser.classic.QueryParser.Term(QueryParser.java:469)
at org.apache.lucene.queryparser.classic.QueryParser.Clause(QueryParser.java:355)
at org.apache.lucene.queryparser.classic.QueryParser.Query(QueryParser.java:244)
at org.apache.lucene.queryparser.classic.QueryParser.TopLevelQuery(QueryParser.java:215)
at org.apache.lucene.queryparser.classic.QueryParserBase.parse(QueryParserBase.java:109)
... 8 more
Так же я пробовал выполнять запрос таким образом:
query = parser.parse("/*ABC");
Но все равно ошибка
При этом я нашел описание, которое дало мне новое видение моей ситуации: https://docs.microsoft.com/en-us/azure/search/query-lucene-syntax#bkmk_regex
Основная мысль с этого сайта для меня:
suffix:
Term fragment comes after * or ?, with a forward slash to delimit the construct.
For example, search=/.*numeric./ returns "alphanumeric".
Там написано, что можно попробовать переформировать запрос, тем самым мой новый запрос выглядеть так: "/.*ABC./"
query = parser.parse("*ABC");
При этом ошибки нет, но и нет нахождения.
Подскажите как можно решить данную проблему? Заранее спасибо.
Ответы (1 шт):
- Если необходимо выполнить поиск и найти первую часть слова, когда известна только вторая часть слова (или также видел название поиск по suffix), то можно воспользоваться RegexpQuery.
Если используете RegexpQuery, то ваш запрос должен выглядеть так:
RegexpQuery query = new RegexpQuery(new Term("НАЗВАНИЕ-ПОЛЯ-ПО-КОТОРОМУ-ИДЕТ-ПОИСК", ".*ШАБЛОН"));
- Но также можно использовать и обычный Query, он сам сможет определить, что это RegexpQuery, но чтобы он смог это сделать важно, чтобы ваш запрос был таким:
Query query = parser.parse("/.*ШАБЛОН/");
В данном случае Query понимает, что это именно RegexpQuery по "обрамлению", имеется ввиду такие два символа: "/." - спереди и получается один символ "/" - сзади.