Test framework, tools & a module map
|
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 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. |
Lucene ships far more than lucene-core. This page covers the tooling you reach for when working
on an index rather than through it — the randomized test framework, the corruption checker, the
version upgrader, the Luke GUI, and the benchmark, replicator and misc modules — and ends with a
one-line description of every module so you know what exists before you go looking.
The lucene-test-framework
lucene-test-framework is the harness Lucene tests itself with, published for you to use the same
way. Add it in test scope:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-test-framework</artifactId>
<version>10.0.0</version>
<scope>test</scope>
</dependency>
<!-- https://lucene.apache.org/core/10_0_0/test-framework/index.html -->
Extend LuceneTestCase and you inherit a RandomizedRunner that seeds every run and randomizes the
codec, Directory implementation, locale, time zone, and merge policy, printing the seed on failure
so you can reproduce it with -Dtests.seed=…. newDirectory() returns a randomly chosen,
assertion-heavy Directory that also verifies every file is closed. RandomIndexWriter is a drop-in
for IndexWriter that randomly flushes, commits, and reopens mid-test to shake out
segment-boundary bugs.
// https://lucene.apache.org/core/10_0_0/test-framework/org/apache/lucene/tests/util/LuceneTestCase.html
public class TitleSearchTest extends LuceneTestCase {
public void testFindsByTitle() throws Exception {
try (Directory dir = newDirectory(); // random Directory impl
RandomIndexWriter w = new RandomIndexWriter(random(), dir)) { // random flush/commit
Document doc = new Document();
doc.add(new TextField("title", "the left hand of darkness", Field.Store.YES));
w.addDocument(doc);
try (IndexReader r = w.getReader()) {
IndexSearcher s = newSearcher(r); // random concurrency slices
assertEquals(1, s.count(new TermQuery(new Term("title", "darkness"))));
}
}
}
}
For analyzer tests, BaseTokenStreamTestCase asserts a TokenStream produces an exact token /
offset / position sequence, and independently fuzzes it with random strings for reset() / close()
correctness:
// https://lucene.apache.org/core/10_0_0/test-framework/org/apache/lucene/tests/analysis/BaseTokenStreamTestCase.html
public class MyAnalyzerTest extends BaseTokenStreamTestCase {
public void testTokens() throws Exception {
Analyzer a = new StandardAnalyzer(); // no stop words by default
assertAnalyzesTo(a, "The 2 QUICK Brown-Foxes",
new String[] {"the", "2", "quick", "brown", "foxes"});
checkRandomData(random(), a, 200); // fuzz with 200 random inputs
a.close();
}
}
Tag slow or large tests @Nightly (or @Slow); they run only with -Dtests.nightly=true, keeping
the default build fast. The randomized engine underneath is documented at
randomizedtesting.
CheckIndex: detect and triage corruption
CheckIndex walks every segment and verifies the term dictionary, postings, doc-values, points,
norms, and stored fields against their checksums. Run it from the command line against a closed
index:
java -ea -cp lucene-core-10.0.0.jar \
org.apache.lucene.index.CheckIndex /var/lib/app/index -verbose
# add -exorcise to drop unrecoverable segments (destructive; back up first)
Or call it from a health check and act on the result:
// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/index/CheckIndex.html
try (Directory dir = FSDirectory.open(path);
CheckIndex checker = new CheckIndex(dir)) {
CheckIndex.Status status = checker.checkIndex();
if (!status.clean) {
log.error("index has broken segments: {} docs would be lost", status.totLoseDocCount);
}
}
IndexUpgrader and lucene-backward-codecs
Lucene reads indexes written by the previous major version only. lucene-backward-codecs (a
transitive dependency of lucene-core) carries the read-only codecs that make that one-version
bridge work; IndexUpgrader rewrites every segment with the current codec so the index stays
readable after the next major upgrade.
# One hop per major version: 8.x -> 9.x on Lucene 9, then 9.x -> 10.x on Lucene 10.
java -cp lucene-core-10.0.0.jar:lucene-backward-codecs-10.0.0.jar \
org.apache.lucene.index.IndexUpgrader -verbose /var/lib/app/index
// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/index/IndexUpgrader.html
new IndexUpgrader(dir).upgrade();
// module: https://lucene.apache.org/core/10_0_0/backward-codecs/index.html
Skipping a major version means exporting and reindexing from source instead.
Luke: browse an index by hand
The luke module is a Swing GUI for opening an index directory and inspecting it — term
frequencies, per-field statistics, document contents, the effect of an analyzer on a string, and
ad-hoc queries. It ships in the Lucene binary distribution under luke/:
./luke.sh # or luke.bat on Windows; opens a directory chooser
Use it to answer "what actually got indexed?" without writing a probe program. Module docs: https://lucene.apache.org/core/10_0_0/luke/index.html.
The benchmark module
lucene-benchmark runs repeatable indexing and search workloads described by an .alg task file — handy for a local before/after when tuning.
# collection.alg -- excerpt
analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer
content.source=org.apache.lucene.benchmark.byTask.feeds.LineDocSource
docs.file=work/enwiki.txt
{ "Rounds"
ResetSystemErase
{ "Populate" CreateIndex { "MAddDocs" AddDoc > : 200000 CloseIndex }
{ "Search" OpenReader { "SearchSameRdr" Search > : 500 CloseReader }
}
Run it with the module’s Benchmark main class. Module docs and the full task vocabulary:
https://lucene.apache.org/core/10_0_0/benchmark/index.html. For the project’s own continuous numbers
see Performance tuning.
The replicator module
lucene-replicator copies a committed (or NRT) index from a primary to one or more replicas, either
in-process or over HTTP with the bundled Jetty handler. IndexReplicationHandler /
ReplicationClient do the commit-point-based copy; the nrt package (PrimaryNode / ReplicaNode)
does segment-level NRT replication without forcing a commit on the primary.
// Primary side: publish each commit.
// https://lucene.apache.org/core/10_0_0/replicator/index.html
Replicator replicator = new LocalReplicator();
replicator.publish(new IndexRevision(writer));
// Replica side: pull into a local directory, then refresh the searcher.
ReplicationClient client = new ReplicationClient(
replicator,
new IndexReplicationHandler(replicaDir, () -> searcherManager.maybeRefresh()),
new PerSessionDirectoryFactory(workDir));
client.updateNow();
This is the building block a home-grown distributed setup uses; see Near-real-time search for the reopen side.
Misc command-line tools
lucene-misc bundles small utilities:
-
IndexMergeTool— merge several index directories into one from the command line (addIndexeswithout writing code) — https://lucene.apache.org/core/10_0_0/misc/org/apache/lucene/misc/IndexMergeTool.html -
HighFreqTerms— list the highest-frequency terms in a field,-tfor total term frequency; a fast way to spot a missing stop-word list or a tokenizer mistake — https://lucene.apache.org/core/10_0_0/misc/org/apache/lucene/misc/HighFreqTerms.html -
GetTermInfo— print the document frequency and total term frequency of one term — https://lucene.apache.org/core/10_0_0/misc/org/apache/lucene/misc/GetTermInfo.html
java -cp lucene-core-10.0.0.jar:lucene-misc-10.0.0.jar \
org.apache.lucene.misc.HighFreqTerms -t /var/lib/app/index 25 body
A map of every module
Every artifact is org.apache.lucene:lucene-<name>. Most projects need only core plus
analysis-common and queryparser.
| Module | What it gives you |
|---|---|
|
The index, the analysis API, |
|
|
|
ICU segmentation and folding; Japanese; Korean; Chinese; Polish (algorithmic); dictionary stemming; OpenNLP tokenizers; phonetic (Soundex / Metaphone) filters. |
|
The classic query-string parser plus the flexible, standard, complex-phrase, and surround parsers. |
|
|
|
Newer, not-yet-stable queries and features. |
|
Taxonomy and |
|
Result grouping and block / parent grouping. |
|
Query-time and index-time (block) joins. |
|
The unified, plain, and postings-based highlighters. |
|
Autocomplete and "did you mean" — |
|
Compile a JavaScript expression into a |
|
Geospatial shapes and prefix-tree strategies; 3D / geodesic maths. |
|
|
|
Alternative and experimental codecs (direct, bloom-filter postings, and others). |
|
Read-only codecs for the previous major version (pulled in by |
|
k-NN and naive-Bayes document classifiers over an index. |
|
|
|
Reverse search: register many queries, stream documents past them — see Monitor / reverse search. |
|
Primary / replica index replication, in-process or over HTTP. |
|
|
|
|
|
The Swing index-inspection GUI. |
|
The |
The full module list with Javadoc links is on the Lucene 10 documentation index.
Related pages
-
Getting started — the module coordinates you start from.
-
Architecture & data flow — what these tools inspect and rewrite.
-
Near-real-time search — the reopen side of the replicator module.
-
Monitor / reverse search — the
monitormodule in depth. -
Performance tuning — uses the benchmark module and luceneutil.