Documents, fields & the capability matrix
|
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. |
A Lucene Document has no schema: it is just an ordered List of Field objects, and two
documents in the same index may carry entirely different fields. What a field lets you do — search it, retrieve it, sort or facet on it, run a range query, do nearest-neighbour — is decided
entirely by which Field subclass you add and how its FieldType is configured.
Document: an ordered list of fields
You build a Document, add Field instances to it, and hand it to IndexWriter.addDocument. A
field name may appear more than once (the values are all indexed). Nothing validates field names or
types across documents — consistency is your responsibility, or your framework’s.
// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/document/Document.html
import org.apache.lucene.document.*;
Document doc = new Document();
doc.add(new StringField("isbn", "9780134685991", Field.Store.YES));
doc.add(new TextField("title", "Effective Java", Field.Store.YES));
doc.add(new TextField("author", "Joshua Bloch", Field.Store.YES));
doc.add(new IntField("year", 2018, Field.Store.YES)); // point + doc values
doc.add(new TextField("tag", "java", Field.Store.NO));
doc.add(new TextField("tag", "best-practices", Field.Store.NO)); // same name, second value
writer.addDocument(doc);
The field types
The modern (post-4.x) field classes each switch on a specific capability. Pick the combination that
matches how the field will be queried and read back; add two fields with the same name when you need
two capabilities (e.g. a TextField to search and a SortedDocValuesField to sort).
| Field class | What it enables |
|---|---|
|
Value is run through the |
|
The whole value is indexed as a single un-analyzed term — exact match, prefix, term filters. For ids, codes, enums. |
|
Like |
|
Stored for retrieval only — never indexed, not searchable. For payload you show but never query. |
|
Value indexed into a BKD tree for efficient range and exact numeric search. Not stored, not sortable on their own. |
|
Convenience field that bundles the matching |
|
A single columnar |
|
One columnar |
|
Multiple columnar |
|
Multiple columnar numeric values per document — multi-valued numeric sort / facet. |
|
A dense vector per document, indexed in an HNSW graph for approximate nearest-neighbour search — kNN vector search. |
|
A named |
|
An encoded latitude/longitude point for geo distance and bounding-box / polygon queries — Spatial search. Pair with |
// A field's capability follows from its class -- add several with the same name for several
// capabilities.
// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/document/package-summary.html
import org.apache.lucene.document.*;
Document d = new Document();
// exact id: searchable + sortable/facetable in one field
d.add(new KeywordField("status", "PUBLISHED", Field.Store.YES));
// numeric: range search AND sort/facet
d.add(new IntField("price_cents", 1299, Field.Store.YES));
// full-text search to match, plus doc values to sort alphabetically
d.add(new TextField("title", "The Go Programming Language", Field.Store.YES));
d.add(new SortedDocValuesField("title_sort", new org.apache.lucene.util.BytesRef("the go programming language")));
// approximate nearest-neighbour
d.add(new KnnFloatVectorField("embedding", new float[] {0.12f, -0.03f, /* ... */ 0.44f}));
// cheap score signal
d.add(new FeatureField("features", "pagerank", 4.2f));
writer.addDocument(d);
FieldType, IndexOptions and term vectors
Every field carries an IndexableFieldType. The built-in classes above ship sensible instances, but
a custom FieldType lets you dial exactly what goes into the index:
-
IndexOptions— how much postings detail to store:DOCS(which documents),DOCS_AND_FREQS(+ term frequency),DOCS_AND_FREQS_AND_POSITIONS(+ positions, needed for phrase and interval queries),DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS(+ character offsets, used by the postings highlighter).NONEmeans the field is not indexed. -
setStored(true)— keep the original value forstoredFields(). -
setStoreTermVectors(true)(with…Positions/…Offsets) — a per-document mini term list, used by some highlighters and "more like this". -
setOmitNorms(true)— drop the per-document length norm; saves a byte per doc per field but disables length normalization in scoring.StringFieldomits norms by default.
// https://lucene.apache.org/core/10_0_0/core/org/apache/lucene/index/IndexableFieldType.html
import org.apache.lucene.document.*;
import org.apache.lucene.index.IndexOptions;
FieldType bodyType = new FieldType();
bodyType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
bodyType.setStored(true);
bodyType.setStoreTermVectors(true);
bodyType.setStoreTermVectorPositions(true);
bodyType.setStoreTermVectorOffsets(true);
bodyType.setOmitNorms(false);
bodyType.freeze();
Document d = new Document();
d.add(new Field("body", "full article text ...", bodyType)); // generic Field + custom type
writer.addDocument(d);
Before Lucene 4, indexing was configured with the Field.Store and Field.Index enums (and numbers
went through a single NumericField); today the capability is the Field subclass plus an optional
custom FieldType, and only Field.Store survives.
Capability matrix
Read down the column for the capability you need, then pick a field (or a pair) whose row has it.
| Field | Searchable (term / match) | Range | Stored (retrieve) | Sort / facet / function | Vector |
|---|---|---|---|---|---|
|
analyzed |
— |
opt. |
— |
— |
|
exact term |
— |
opt. |
— |
— |
|
exact term |
— |
opt. |
yes (SortedSet) |
— |
|
— |
— |
yes |
— |
— |
|
exact |
yes (BKD) |
— |
— |
— |
|
exact |
yes (BKD) |
opt. |
yes (SortedNumeric) |
— |
|
— |
— |
— |
yes (single numeric) |
— |
|
— |
— |
— |
yes (single string) |
— |
|
— |
— |
— |
yes (multi string) |
— |
|
— |
— |
— |
yes (multi numeric) |
— |
|
— |
— |
— |
— |
yes (HNSW) |
|
boost only |
— |
— |
score signal |
— |
|
geo predicate |
geo box / distance |
— |
with |
— |
The recurring pattern: a *Point/*Field for range, a *DocValuesField for sort and facet, and
Field.Store.YES (or a StoredField) for retrieval — often all three under one name.
Points & range queries,
Filtering & faceting, and
Retrieving results each use one leg of it.
This is the library-level version of a server’s field mapping: compare
Elasticsearch mapping & field types (where
text vs. keyword and doc_values are mapping options) and
Solr field types (where the same choices are <fieldType>
declarations in a schema).
Related pages
-
Architecture & data flow — the segment files each field type writes into.
-
Points & range queries — querying the
*Point/*Fieldtypes. -
Filtering & faceting — consuming the
*DocValuesFieldtypes. -
kNN vector search —
KnnFloatVectorField/KnnByteVectorFieldin use. -
Function & custom scoring —
FeatureFieldand doc-values-driven scoring. -
Elasticsearch mapping & field types and Solr field types — the same decisions as a server schema.
-
org.apache.lucene.documentJavadoc — everyFieldsubclass andFieldType.