Eine einfache Dateisuche mit Lucene

Eine einfache Dateisuche mit Lucene

1. Überblick

Apache Lucene ist eine Volltextsuchmaschine, die von verschiedenen Programmiersprachen verwendet werden kann. Um mit Lucene zu beginnen, lesen Sie bitte unsere Einführungarticle here.

In diesem kurzen Artikel indizieren wir eine Textdatei und suchen nach BeispielStrings und Textausschnitten in dieser Datei.

2. Maven Setup

Fügen wir zuerst die erforderlichen Abhängigkeiten hinzu:


    org.apache.lucene
    lucene-core
    7.1.0

Die neueste Version finden Sie unterhere.

Zum Parsen unserer Suchanfragen benötigen wir außerdem:


    org.apache.lucene
    lucene-queryparser
    7.1.0

Denken Sie daran, die neueste Versionhere zu überprüfen.

3. Dateisystemverzeichnis

Um Dateien zu indizieren, müssen wir zuerst einen Dateisystemindex erstellen.

Lucene stellt die KlasseFSDirectoryzur Verfügung, um einen Dateisystemindex zu erstellen:

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

Hier istindexPath der Speicherort des Verzeichnisses. If the directory doesn’t exist, Lucene will create it.

Lucene bietet drei konkrete Implementierungen der abstrakten KlasseFSDirectory:SimpleFSDirectory, NIOFSDirectory, and MMapDirectory. Jede von ihnen hat möglicherweise spezielle Probleme mit einer bestimmten Umgebung.

Zum BeispielSimpleFSDirectory has poor concurrent performance as it blocks when multiple threads read from the same file.

In ähnlicher Weise sind dieNIOFSDirectory 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. Beim Aufrufen wird versucht, je nach Umgebung die beste Implementierung auszuwählen.

4. Index-Textdatei

Nachdem wir das Indexverzeichnis erstellt haben, fügen wir dem Index eine Datei hinzu:

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();
}

Hier erstellen wir ein Dokument mit zweiStringFieldsmit den Namen "Pfad" und "Dateiname" und einemTextFieldmit dem Namen "Inhalt".

Beachten Sie, dass wir die InstanzfileReader als zweiten Parameter anTextField übergeben. Das Dokument wird mitIndexWriter. zum Index hinzugefügt

Das dritte Argument im KonstruktorTextField oderStringField gibt an, ob der Wert des Felds ebenfalls gespeichert wird.

Schließlich rufen wir dieclose() derIndexWriter auf, um die Sperre ordnungsgemäß zu schließen und aus den Indexdateien zu entfernen.

5. Indizierte Dateien durchsuchen

Durchsuchen wir nun die indizierten Dateien:

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());
}

Testen wir nun die Funktionalität:

@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"));
}

Beachten Sie, wie wir einen Dateisystemindex am SpeicherortindexPath erstellen und denfile1.txt. indizieren

Dann suchen wir einfach nachString "consectetur" im Feld“contents”.

6. Fazit

Dieser Artikel war eine kurze Demonstration des Indizierens und Durchsuchens von Text mit Apache Lucene. Weitere Informationen zum Indizieren, Anbrennen und Abfragen von Lucene finden Sie in unserenintroduction to Lucene article.

Wie immer kann der Code für die Beispieleover on Github gefunden werden.