Перейти к основному содержимому

Простой поиск файлов с Lucene

· 3 мин. чтения

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 .