1. Обзор
Apache Lucene — это полнотекстовый поисковый движок, который может использоваться различными языками программирования. Чтобы начать работу с Lucene, см. нашу вводную статью здесь .
В этой быстрой статье мы проиндексируем текстовый файл и найдем образцы строк
и текстовые фрагменты в этом файле.
2. Настройка Мавена
Сначала добавим необходимые зависимости:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>7.1.0</version>
</dependency>
Последнюю версию можно найти здесь .
Также для разбора наших поисковых запросов нам понадобится:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>7.1.0</version>
</dependency>
Не забудьте проверить последнюю версию здесь .
3. Каталог файловой системы
Чтобы индексировать файлы, нам сначала нужно создать индекс файловой системы.
Lucene предоставляет класс FSDirectory
для создания индекса файловой системы:
Directory directory = FSDirectory.open(Paths.get(indexPath));
Здесь indexPath
— это расположение каталога. Если каталог не существует, Lucene создаст его.
Lucene предоставляет три конкретные реализации абстрактного класса FSDirectory
: SimpleFSDirectory, NIOFSDirectory и MMapDirectory.
У каждого из них могут быть особые проблемы с данной средой.
Например, SimpleFSDirectory
имеет низкую производительность одновременного выполнения, поскольку он блокируется, когда несколько потоков читают один и тот же файл.
Точно так же реализации NIOFSDirectory и MMapDirectory
сталкиваются с проблемами файлового канала в Windows и проблемами освобождения памяти соответственно.
Для преодоления таких особенностей среды Lucene предоставляет метод FSDirectory.open()
. При вызове он пытается выбрать наилучшую реализацию в зависимости от среды.
4. Индексный текстовый файл
После того, как мы создали индексный каталог, давайте добавим файл в индекс:
public void addFileToIndex(String filepath) {
Path path = Paths.get(filepath);
File file = path.toFile();
IndexWriterConfig indexWriterConfig
= new IndexWriterConfig(analyzer);
Directory indexDirectory = FSDirectory
.open(Paths.get(indexPath));
IndexWriter indexWriter = new IndexWriter(
indexDirectory, indexWriterConfig);
Document document = new Document();
FileReader fileReader = new FileReader(file);
document.add(
new TextField("contents", fileReader));
document.add(
new StringField("path", file.getPath(), Field.Store.YES));
document.add(
new StringField("filename", file.getName(), Field.Store.YES));
indexWriter.addDocument(document);
indexWriter.close();
}
Здесь мы создаем документ с двумя StringFields
с именами «path» и «filename» и TextField
с именем «contents».
Обратите внимание, что мы передаем экземпляр fileReader
в качестве второго параметра TextField
. Документ добавляется в индекс с помощью IndexWriter.
Третий аргумент в конструкторе TextField
или StringField
указывает, будет ли также сохранено значение поля.
Наконец, мы вызываем close()
IndexWriter
, чтобы корректно закрыть и снять блокировку с файлов индекса.
5. Поиск проиндексированных файлов
Теперь давайте искать файлы, которые мы проиндексировали:
public List<Document> searchFiles(String inField, String queryString) {
Query query = new QueryParser(inField, analyzer)
.parse(queryString);
Directory indexDirectory = FSDirectory
.open(Paths.get(indexPath));
IndexReader indexReader = DirectoryReader
.open(indexDirectory);
IndexSearcher searcher = new IndexSearcher(indexReader);
TopDocs topDocs = searcher.search(query, 10);
return topDocs.scoreDocs.stream()
.map(scoreDoc -> searcher.doc(scoreDoc.doc))
.collect(Collectors.toList());
}
Теперь давайте проверим функциональность:
@Test
public void givenSearchQueryWhenFetchedFileNamehenCorrect(){
String indexPath = "/tmp/index";
String dataPath = "/tmp/data/file1.txt";
Directory directory = FSDirectory
.open(Paths.get(indexPath));
LuceneFileSearch luceneFileSearch
= new LuceneFileSearch(directory, new StandardAnalyzer());
luceneFileSearch.addFileToIndex(dataPath);
List<Document> docs = luceneFileSearch
.searchFiles("contents", "consectetur");
assertEquals("file1.txt", docs.get(0).get("filename"));
}
Обратите внимание, как мы создаем индекс файловой системы в расположении indexPath
и индексируем файл file1.txt.
Затем мы просто ищем строку
« consectetur
» в поле «contents»
.
6. Заключение
Эта статья была быстрой демонстрацией индексации и поиска текста с помощью Apache Lucene. Чтобы узнать больше об индексировании, поиске и запросах Lucene, обратитесь к нашей вводной статье Lucene .
Как всегда, код примеров можно найти на Github .