#java #indexing #full-text-search #lucene
#java #индексирование #полнотекстовый поиск #lucene
Вопрос:
я индексирую один большой обзор базы данных (только текстовые поля), в котором пользователь должен иметь возможность выполнять поиск (ниже в методе indexFields). Этот поиск ранее выполнялся в базе данных с помощью ILIKE query, но был медленным, поэтому теперь поиск выполняется по индексу. Hovewer, когда я сравниваю результаты поиска по запросу базы данных и результаты, которые я получаю при поиске по индексу, при поиске по индексу всегда получается намного меньше результатов. Я не уверен, допускаю ли я ошибку при индексации или в процессе поиска. Мне кажется, что здесь все имеет смысл. Есть идеи?
Вот код. Все советы приветствуются!
// INDEXING
StandardAnalyzer analyzer = new StandardAnalyzer(
Version.LUCENE_CURRENT, stopSet); // stop set is empty
IndexWriter writer = new IndexWriter(INDEX_DIR, analyzer, true,
IndexWriter.MaxFieldLength.UNLIMITED);
indexFields(writer);
writer.optimize();
writer.commit();
writer.close();
analyzer.close();
private void indexFields(IndexWriter writer) {
DetachedCriteria criteria = DetachedCriteria
.forClass(Activit.class);
int count = 0;
int max = 50000;
boolean existMoreToIndex = true;
List<Activit> result = new ArrayList<Activit>();
while (existMoreToIndex) {
try {
result = activitService.listPaged(count, max);
if (result.size() < max)
existMoreToIndex = false;
if (result.size() == 0)
return;
for (Activit ao : result) {
Document doc = new Document();
doc.add(new Field("id", String.valueOf(ao.getId()),
Field.Store.YES, Field.Index.ANALYZED));
if(ao.getActivitOwner()!=null)
doc.add(new Field("field1", ao.getActivityOwner(),Field.Store.YES, Field.Index.ANALYZED));
if(ao.getActivitResponsible() != null)
doc.add(new Field("field2", ao.getActivityResponsible(), Field.Store.YES,Field.Index.ANALYZED));
try {
writer.addDocument(doc);
} catch (CorruptIndexException e) {
e.printStackTrace();
}
count = max;
//SEARCH
public List<Activit> searchActivitiesInIndex(String searchCriteria) {
Set<String> stopSet = new HashSet<String>(); // empty because we do not want to remove stop words
Version version = Version.LUCENE_CURRENT;
String[] fields = {
"field1", "field2"};
try {
File tempFile = new File("C://testindex");
Directory INDEX_DIR = new SimpleFSDirectory(tempFile);
Searcher searcher = new IndexSearcher(INDEX_DIR, true);
QueryParser parser = new MultiFieldQueryParser(version, fields, new StandardAnalyzer(
version, stopSet));
Query query = parser.parse(searchCriteria);
TopDocs topDocs = searcher.search(query, 500);
ScoreDoc[] hits = topDocs.scoreDocs;
//here i always get smaller hits lenght
searcher.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Комментарии:
1. Выведите TopDocs.totalHits, если вы этого еще не делаете. Это число даст вам общее количество документов, соответствующих вашему запросу.
2. @Shashikant Kore: я уже делаю это и вижу, что это неверное число, вот почему я опубликовал вопрос.
Ответ №1:
Скорее всего, анализатор делает что-то, чего вы не ожидаете.
Откройте свой индекс с помощью Luke, вы можете увидеть, как выглядят ваши (проанализированные) проиндексированные документы, а также ваши проанализированные запросы — это должно позволить вам увидеть, что происходит не так.
Кроме того, можете ли вы привести пример searchCriteria
? И соответствующий SQL-запрос? Без этого трудно понять, правильно ли выполнена индексация. Вам также может не понадобиться использовать MultiFieldQueryParser
, что довольно неэффективно.
Комментарии:
1. Я использую MultiFieldQueryParser (я думаю, вы это пропустили :))! критерии поиска — это просто простые строки, такие как «отель», «горячий» или что-нибудь еще. Я использую MultiFieldQueryParser, потому что я не хочу выполнять поиск по каждому полю отдельно
2. @Julia, это была моя точка зрения, если вы используете MultiFieldQueryParser, вы выполняете поиск по полям отдельно, это просто обеспечивает некоторый синтаксический сахар. Если вы хотите, чтобы ваши ключевые слова совпадали в любом из полей, гораздо лучше объединить текст в одно поле.