Getting started with Apache Lucene

This section documents the current Apache Lucene 10.x line — Lucene 10 requires Java 21 — as published at the Apache Lucene documentation and Javadoc, which is the reference these pages are written and verified against. No specific patch version is pinned; examples target lucene-core 10.x and the companion modules. Some areas (the Panama foreign-memory / Vector API internals, codec file-format internals, and the nightly benchmark harness) are linked, not documented in depth.

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production, as Lucene iterates quickly.

This section’s bibliography lists the reference material consulted while preparing these pages.

Apache Lucene is a search library, not a server: you add a JAR to a JVM application and call its classes directly. This page explains what that means in practice, lists the Maven and Gradle coordinates for the modules used throughout this section, and walks one document through indexing and back out of a query.

Lucene is an embedded, in-process library

Lucene runs inside your JVM. There is no daemon to start, no port to open, no wire protocol, and nothing to deploy separately — an IndexWriter is an object you construct, and the index is a directory of files on a disk you choose. The flip side is that everything a search server would do for you is now your responsibility: concurrency control, when and how to persist, moving an index between machines, replication, and sharding a corpus that outgrows one node. Lucene gives you the inverted index, the query evaluation, and the scoring; the operational layer around it is yours to build or to borrow.

That operational layer is exactly what Elasticsearch, OpenSearch, and Apache Solr are: all three embed this same Lucene library and wrap it in a cluster, a REST API, and a persistence/replication model. Lucene vs. Solr vs. Elasticsearch vs. OpenSearch compares them directly.

These pages target the Lucene 10.x line. Lucene 10 requires Java 21, and the default directory implementation, MMapDirectory, memory-maps index files through the Java Platform’s foreign-memory (Panama) API — see Directory implementations & storage. The current requirements are on the Apache Lucene site and its system-requirements page.

// No client, no connection string: you open a directory and construct a writer.
// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/store/FSDirectory.html
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import java.nio.file.Path;

try (Directory dir = FSDirectory.open(Path.of("/var/data/my-index"));
     IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(new StandardAnalyzer()))) {
    // ... index documents ...
}

Adding Lucene to a build

org.apache.lucene:lucene-core is the only mandatory dependency. The rest of this section draws on a set of companion modules, each a separate artifact under the same group and version; add only the ones a page actually uses. The Javadoc for every module is linked from the Lucene 10 API index.

Module Used for

lucene-core

Directory, IndexWriter, DirectoryReader, IndexSearcher, the core Query types, BKD points, doc values, the default codec.

lucene-analysis-common

StandardAnalyzer, CustomAnalyzer, the common tokenizers and token filters — Analysis pipeline.

lucene-queryparser

QueryParser and the other string-to-Query parsers — Query parsers.

lucene-facet

FacetsCollector, taxonomy and SortedSetDocValues faceting — Filtering & faceting.

lucene-highlighter

The unified/postings highlighters — Highlighting, suggesters & more.

lucene-suggest

Autocomplete and "did you mean" — AnalyzingInfixSuggester, DirectSpellChecker.

lucene-join

JoinUtil and block-join queries — Grouping & joins.

lucene-grouping

First-pass/second-pass result grouping.

lucene-expressions

JavaScript expression DoubleValuesSource for sorting and scoring — Function & custom scoring.

lucene-queries

Extra Query implementations: FunctionScoreQuery, MoreLikeThis, CommonTermsQuery.

lucene-spatial-extras

Grid (prefix-tree) and serialized-DV spatial strategies on top of core’s LatLonPoint/LatLonShape — Spatial search.

lucene-monitor

Reverse search / stored-query matching — Monitor / reverse search.

lucene-backward-codecs

Read indexes written by the previous major version.

lucene-test-framework

LuceneTestCase, RandomIndexWriter, newDirectory() — Testing tools & modules.

<!-- Maven: lucene-core plus the two modules almost every app also needs. -->
<!-- https://lucene.apache.org/core/10_0_0/core/index.html -->
<dependencies>
  <dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-core</artifactId>
    <version>10.0.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-analysis-common</artifactId>
    <version>10.0.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-queryparser</artifactId>
    <version>10.0.0</version>
  </dependency>
</dependencies>
// Gradle (Groovy DSL): keep the version in one place and reuse it.
def luceneVersion = '10.0.0'
dependencies {
    implementation "org.apache.lucene:lucene-core:${luceneVersion}"
    implementation "org.apache.lucene:lucene-analysis-common:${luceneVersion}"
    implementation "org.apache.lucene:lucene-queryparser:${luceneVersion}"
    // add as needed, e.g.
    // implementation "org.apache.lucene:lucene-facet:${luceneVersion}"
    // implementation "org.apache.lucene:lucene-highlighter:${luceneVersion}"
    testImplementation "org.apache.lucene:lucene-test-framework:${luceneVersion}"
}

The distribution also bundles lucene-demo, a runnable example whose IndexFiles and SearchFiles classes index a directory tree and query it from the command line — a working reference for the code below. See the lucene-demo module docs.

A first index-and-search round-trip

The following opens a Directory, writes two documents with an IndexWriter, opens a DirectoryReader and an IndexSearcher, and runs two queries: a TermQuery built directly, and a query produced by the string parser. TopDocs holds the ranked hit list; the stored fields of each hit are read back through searcher.storedFields().

// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/index/IndexWriter.html
// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/search/IndexSearcher.html
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import java.nio.file.Path;

Directory dir = FSDirectory.open(Path.of("/var/data/books-index"));
StandardAnalyzer analyzer = new StandardAnalyzer();

// --- index ---
try (IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(analyzer))) {
    Document a = new Document();
    a.add(new StringField("isbn", "9780134685991", Field.Store.YES)); // exact term
    a.add(new TextField("title", "Effective Java", Field.Store.YES));  // analyzed
    writer.addDocument(a);

    Document b = new Document();
    b.add(new StringField("isbn", "9780596009205", Field.Store.YES));
    b.add(new TextField("title", "Head First Java", Field.Store.YES));
    writer.addDocument(b);
}   // close() commits

// --- search ---
try (DirectoryReader reader = DirectoryReader.open(dir)) {
    IndexSearcher searcher = new IndexSearcher(reader);

    // 1. a Query built in code
    Query exact = new TermQuery(new Term("isbn", "9780134685991"));
    TopDocs byIsbn = searcher.search(exact, 10);

    // 2. a Query parsed from a string ("java" is analyzed the same way the field was)
    Query parsed = new QueryParser("title", analyzer).parse("java");
    TopDocs byTitle = searcher.search(parsed, 10);

    StoredFields stored = searcher.storedFields();
    for (ScoreDoc hit : byTitle.scoreDocs) {
        Document doc = stored.document(hit.doc);
        System.out.printf("%.3f  %s  %s%n", hit.score, doc.get("isbn"), doc.get("title"));
    }
}

Each of those objects is a chain: IndexWriterConfig carries the Analyzer, the Directory holds the segments, the DirectoryReader gives the IndexSearcher a point-in-time view, and the Query produces TopDocs. The index model & class chains draws that out. The field choice above — StringField for the exact ISBN, TextField for the analyzed title — is the subject of Documents, fields & the capability matrix, and the two query forms open Core queries.

Where to go next