я придумал решение для programmaticlly создать запрос для поиска фразы с подстановочными с помощью этого кода: создание ПримераLucene фраза запрос с групповыми символами
public static Query createPhraseQuery(String[] phraseWords, String field) {
SpanQuery[] queryParts = new SpanQuery[phraseWords.length];
for (int i = 0; i < phraseWords.length; i++) {
WildcardQuery wildQuery = new WildcardQuery(new Term(field, phraseWords[i]));
queryParts[i] = new SpanMultiTermQueryWrapper<WildcardQuery>(wildQuery);
}
return new SpanNearQuery(queryParts, //words
0, //max distance
true //exact order
);
}
и вызвать ToString() метод будет:
String[] phraseWords = new String[]{"foo*", "b*r"};
Query phraseQuery = createPhraseQuery(phraseWords, "text");
System.out.println(phraseQuery.toString());
выходы:
spanNear([SpanMultiTermQueryWrapper(text:foo*), SpanMultiTermQueryWrapper(text:b*r)], 0, true)
Который работает достаточно велик, и быстро для большинства случаев. Например, если я создаю такой запрос и поиск с ним, он будет выход желаемых результатов, например:
Sentence with foo bar.
Foolies beer drinkers.
...
И не что-то вроде:
Bar fooes.
Foo has bar.
Я уже упоминал, что работа запроса достаточно быстро в большинство случаев. В настоящее время у меня есть индекс с размером aprox. 200 ГБ, а среднее время поиска - от 0,1 до 3 секунд. В зависимости от многих факторов, таких как: кеш, размер подмножеств документов, соответствующих одному слову во фразе, поскольку lucene будет выполнять заданные пересечения между установленными условиями.
Пример: Предположим, что я хочу запросить выражение «a * karenjin *» (которое я разделил на ["a *", "karenjin *"], а затем создал запрос с использованием метода createPhraseQuery), и я хочу, чтобы это матчи предложения, содержащие: «ana karenjina», «ani karenjinoj», «ane karenjine», ... (разные случаи из-за хорватской грамматики).
Этот запрос очень медленный, что я не дождался достаточно долго, чтобы получить результаты (более 1 часа), а иногда и превышение исключения верхнего предела GC. Такое поведение несколько ожидалось, так как сам «a *» соответствует огромному количеству документов. Я знаю, что я могу запросить «a? Karanjin *», который дает результат 30-40 секунд (быстрее, но все же медленно).
Здесь я смущен. Если я запрошу только «karenjin *», он даст результаты за 1 сек. Поэтому я попытался запросить «a * karenjin *» и использовать фильтр «karenjin *», используя WildcardQuery и QueryWrapperFilter. И это все еще неприемлемо медленным (я убил процесс, прежде чем он вернулся).
В документации говорится, что фильтр уменьшает пространство поиска в запросе. Поэтому я попытался использовать фильтр:
Filter filter = new QueryWrapperFilter(new WildcardQuery(new Term("text", "karanjin*")));
И запрос:
Query query = createPhraseQuery(new String[]{"an*", "karenjin*"}, "text");
чем поиск, (после нескольких разминочных запросов):
Sort sort = new Sort(new SortField("insertTime", SortField.Type.STRING, true));
TopDocs docs = searcher.search(query, filter, 100, sort);
ОК, что мой вопрос ?
Как же это quering:
Query query = new WildcardQuery(new Term("text", "karanjin*"));
быстро, но с использованием фильтра, описанного выше, по-прежнему медленно?
Спасибо за совет, я буду стараться ограничить число членов и посмотреть, как он будет выполнять. Я ожидаю, что это будет намного быстрее. Но результаты могут быть неполными. Это компромисс между временем и результатами. –
Я попробую. И в соответствии с книгой Lucene в действии WildcardQuery будет внутренне распознан и оптимизирован для PrefixQuery, если он заканчивается символом * или даже TermQuery, если нет подстановочных знаков. –
Я считаю, что это правильно, но я скорее ожидал, что логика будет жить в синтаксическом анализе, и я не видел ее там. Однако может быть частью самого переписывания. – femtoRgon