Я новичок в Lucene, и у меня возникают проблемы с созданием простого кода для запроса коллекции текстовых файлов.
Я попробовал этот пример, но несовместим с новой версией Lucene.
UDPATE: Это мой новый код, но он все еще не работает.
Я новичок в Lucene, и у меня возникают проблемы с созданием простого кода для запроса коллекции текстовых файлов.
Я попробовал этот пример, но несовместим с новой версией Lucene.
UDPATE: Это мой новый код, но он все еще не работает.
Lucene - довольно большая тема с большим количеством классов и методов для покрытия, и вы, как правило, не можете ее использовать, не понимая по крайней мере некоторых базовых понятий. Если вам нужен быстродоступный сервис, используйте Solr. Если вам нужен полный контроль над Lucene, продолжайте чтение. Я расскажу о некоторых основных концепциях и классах Lucene, которые их представляют. (Информацию о том, как читать текстовые файлы в памяти, читайте, например, эту статью).
Что бы вы ни делали в Lucene - индексирование или поиск - вам нужен анализатор. Цель анализатора состоит в том, чтобы токенизировать (разбить на слова) и основыть (получить основание слова) свой текст ввода. Он также выбрасывает наиболее частые слова типа "a", "the" и т.д. Вы можете найти анализаторы для более чем 20 языков, или вы можете использовать SnowballAnalyzer и передать язык в качестве параметра.
Чтобы создать экземпляр SnowballAnalyzer для английского, вы это:
Analyzer analyzer = new SnowballAnalyzer(Version.LUCENE_30, "English");
Если вы собираетесь индексировать тексты на разных языках и хотите автоматически выбирать анализатор, вы можете использовать tika LanguageIdentifier.
Вам нужно сохранить свой индекс где-нибудь. Для этого есть две основные возможности: индекс в памяти, который является простым в использовании, и индекс диска, который является наиболее распространенным.
Используйте любую из следующих двух строк:
Directory directory = new RAMDirectory(); // RAM index storage
Directory directory = FSDirectory.open(new File("/path/to/index")); // disk index storage
Если вы хотите добавить, обновить или удалить документ, вам понадобится IndexWriter:
IndexWriter writer = new IndexWriter(directory, analyzer, true, new IndexWriter.MaxFieldLength(25000));
Любой документ (текстовый файл в вашем случае) представляет собой набор полей. Чтобы создать документ, в котором будет храниться информация о вашем файле, используйте это:
Document doc = new Document();
String title = nameOfYourFile;
doc.add(new Field("title", title, Field.Store.YES, Field.Index.ANALYZED)); // adding title field
String content = contentsOfYourFile;
doc.add(new Field("content", content, Field.Store.YES, Field.Index.ANALYZED)); // adding content field
writer.addDocument(doc); // writing new document to the index
Конструктор Field
принимает имя поля, текст и как минимум еще два параметра. Во-первых, это флаг, который показывает, должна ли Lucene сохранять это поле. Если он равен Field.Store.YES
, у вас будет возможность вернуть весь текст из индекса, иначе будет храниться только индексная информация об этом.
Второй параметр показывает, должна ли Lucene индексировать это поле или нет. Используйте Field.Index.ANALYZED
для любого поля, которое вы собираетесь искать.
Обычно вы используете оба параметра, как показано выше.
Не забудьте закрыть IndexWriter
после выполнения задания:
writer.close();
Поиск немного сложнее. Вам понадобится несколько классов: Query
и QueryParser
, чтобы сделать запрос Lucene из строки, IndexSearcher
для фактического поиска, TopScoreDocCollector
для хранения результатов (он передается в IndexSearcher
в качестве параметра) и ScoreDoc
для повторения результатов. Следующий фрагмент показывает, как все это составлено:
IndexSearcher searcher = new IndexSearcher(directory);
QueryParser parser = new QueryParser(Version.LUCENE_30, "content", analyzer);
Query query = parser.parse("terms to search");
TopScoreDocCollector collector = TopScoreDocCollector.create(HOW_MANY_RESULTS_TO_COLLECT, true);
searcher.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
// `i` is just a number of document in Lucene. Note, that this number may change after document deletion
for (int i = 0; i < hits.length; i++) {
Document hitDoc = searcher.doc(hits[i].doc); // getting actual document
System.out.println("Title: " + hitDoc.get("title"));
System.out.println("Content: " + hitDoc.get("content"));
System.out.println();
}
Обратите внимание, что второй аргумент в конструкторе QueryParser
- это поле по умолчанию, то есть поле, которое будет искать, если не задан определитель. Например, если ваш запрос "title: term", Lucene будет искать слово "term" в поле "title" всех документов, но если ваш запрос является просто "термином", если будет искать в поле по умолчанию, в этом случае - "содержимое". Для получения дополнительной информации см. Синтаксис запросов Lucene. QueryParser
также принимает анализатор в качестве последнего аргумента. Это должен быть тот же анализатор, что и для индексации вашего текста.
Последнее, что вы должны знать, это первый параметр TopScoreDocCollector.create
. Это всего лишь число, которое представляет, сколько результатов вы хотите собрать. Например, если он равен 100, Lucene будет собирать только первые (по количеству) 100 результатов и отбрасывать остальные. Это всего лишь акт оптимизации - вы получаете лучшие результаты, и если вас не устраивает, вы повторяете поиск с большим числом.
Наконец, не забудьте закрыть поисковик и каталог, чтобы не потерять системные ресурсы:
searcher.close();
directory.close();
EDIT: Также см. класс демонов IndexFiles из Источники Lucene 3.0.
package org.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import org.apache.lucene.queryParser.*;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
public class LuceneSimple {
private static void addDoc(IndexWriter w, String value) throws IOException {
Document doc = new Document();
doc.add(new Field("title", value, Field.Store.YES, Field.Index.ANALYZED));
w.addDocument(doc);
}
public static void main(String[] args) throws CorruptIndexException, LockObtainFailedException, IOException, ParseException {
File dir = new File("F:/tmp/dir");
StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
Directory index = new RAMDirectory();
//Directory index = FSDirectory.open(new File("lucDirHello") );
IndexWriter w = new IndexWriter(index, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);
w.setRAMBufferSizeMB(200);
System.out.println(index.getClass() + " RamBuff:" + w.getRAMBufferSizeMB() );
addDoc(w, "Lucene in Action");
addDoc(w, "Lucene for Dummies");
addDoc(w, "Managing Gigabytes");
addDoc(w, "The Art of Computer Science");
addDoc(w, "Computer Science ! what is that ?");
Long N = 0l;
for( File f : dir.listFiles() ){
BufferedReader br = new BufferedReader( new FileReader(f) );
String line = null;
while( ( line = br.readLine() ) != null ){
if( line.length() < 140 ) continue;
addDoc(w, line);
++N;
}
br.close();
}
w.close();
// 2. query
String querystr = "Computer";
Query q = new QueryParser( Version.LUCENE_30, "title", analyzer ).parse(querystr);
//search
int hitsPerPage = 10;
IndexSearcher searcher = new IndexSearcher(index, true);
TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage, true);
searcher.search(q, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
System.out.println("Found " + hits.length + " hits.");
for(int i=0;i<hits.length;++i) {
int docId = hits[i].doc;
Document d = searcher.doc(docId);
System.out.println((i + 1) + ". " + d.get("title"));
}
searcher.close();
}
}
Я предлагаю вам изучить Solr @http://lucene.apache.org/solr/, а не работать с lucene api