Простой поиск файлов с помощью Lucene

Простой поиск файлов с помощью Lucene

1. обзор

Apache Lucene - это механизм полнотекстового поиска, который может использоваться различными языками программирования. Чтобы начать работу с Lucene, обратитесь к нашему вводномуarticle here.

В этой быстрой статье мы проиндексируем текстовый файл и найдем образецStrings и текстовые фрагменты в этом файле.

2. Maven Setup

Давайте сначала добавим необходимые зависимости:


    org.apache.lucene
    lucene-core
    7.1.0

Последнюю версию можно найтиhere.

Также для разбора поисковых запросов нам понадобятся:


    org.apache.lucene
    lucene-queryparser
    7.1.0

Не забудьте проверить последнюю версиюhere.

3. Каталог файловой системы

Чтобы индексировать файлы, нам сначала нужно создать индекс файловой системы.

Lucene предоставляет классFSDirectory для создания индекса файловой системы:

Directory directory = FSDirectory.open(Paths.get(indexPath));

ЗдесьindexPath - это расположение каталога. If the directory doesn’t exist, Lucene will create it.

Lucene предоставляет три конкретные реализации абстрактного классаFSDirectory:SimpleFSDirectory, NIOFSDirectory, and MMapDirectory. У каждой из них могут быть особые проблемы с данной средой.

Например,SimpleFSDirectory has poor concurrent performance as it blocks when multiple threads read from the same file.

АналогичноNIOFSDirectory and MMapDirectory implementations face file-channel issues in Windows and memory release problems respectively.

To overcome such environment peculiarities Lucene provides the FSDirectory.open() method. При вызове пытается выбрать лучшую реализацию в зависимости от среды.

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с именами «путь» и «имя файла» иTextFieldс именами «содержимое».

Обратите внимание, что мы передаем экземплярfileReader в качестве второго параметраTextField. Документ добавляется в индекс с помощьюIndexWriter.

Третий аргумент в конструктореTextField илиStringField указывает, будет ли также сохранено значение поля.

Наконец, мы вызываемclose()IndexWriter, чтобы корректно закрыть и снять блокировку с индексных файлов.

5. Поиск по проиндексированным файлам

Теперь поищем в индексированных файлах:

public List 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 docs = luceneFileSearch
      .searchFiles("contents", "consectetur");

    assertEquals("file1.txt", docs.get(0).get("filename"));
}

Обратите внимание, как мы создаем индекс файловой системы в местоположенииindexPath и индексируемfile1.txt.

Затем мы просто ищемString «consectetur» в поле“contents”.

6. Заключение

Эта статья была быстрой демонстрацией индексации и поиска текста с помощью Apache Lucene. Чтобы узнать больше об индексировании, поиске и запросах Lucene, обратитесь к нашемуintroduction to Lucene article.

Как всегда, код примеров можно найтиover on Github.