Speeding Up Text Queries in Neo4j with Full‑Text Indexes
Learn how Neo4j’s full‑text indexes, powered by Lucene, can turn slow text searches into millisecond queries. See a concrete example, trade‑offs, and a quick checklist to decide if you should adopt one in your graph.
21 Apr 2026, 13:00 UTC

Why Full‑Text Indexes Matter for Large Graphs
When your graph contains thousands or millions of nodes with free‑text properties, scanning every node to find matches can take seconds or even minutes. Neo4j’s full‑text indexes, built on Apache Lucene, let you search those properties in milliseconds while still returning a relevance score to rank results.
Thesis: Use a full‑text index when you need fast, flexible text search on string properties.
Full‑text indexes are the go‑to solution for:
- Phrase, prefix, or fuzzy matches (e.g., "neo4j*" or "graph~1").
- Ranking results by relevance.
- Avoiding full‑scan performance penalties as your graph grows.
Setting Up a Full‑Text Node Index
Indexes are created with a name, a list of labels (or relationship types), and the property to index. The following example builds an index on the description property of all Person nodes.
# Run in Neo4j Browser or Cypher Shell – requires admin privileges
CALL db.index.fulltext.createNodeIndex(
'descIndex', // index name
['Person'], // labels to include
['description'] // property to index
);
After the index is built, Neo4j automatically keeps it in sync with any changes to description values.
Querying the Index with Relevance Scoring
Use the CALL db.index.fulltext.queryNodes procedure. It returns the matching node and a score that reflects how well the node matches the query string.
# Find nodes whose description contains words starting with 'neo4j'
CALL db.index.fulltext.queryNodes('descIndex', 'neo4j*')
YIELD node, score
RETURN node.name, score
ORDER BY score DESC
LIMIT 10;
To confirm the index is actually used, run:
EXPLAIN
CALL db.index.fulltext.queryNodes('descIndex', 'neo4j*')
YIELD node, score
RETURN node.name;
The execution plan should include a FulltextNodeIndexSeek operator.
Trade‑offs and Practical Limits
- Write latency: Every time a
descriptionis created, updated, or deleted, Lucene must update the index. If your application writes to that property at high frequency, you may see slower transaction commit times. - Storage footprint: Full‑text indexes can grow large, especially when many nodes share the same property. Monitor disk usage and consider pruning unused indexes.
- Memory consumption: Lucene keeps a portion of the index in RAM for speed. On a JVM with limited heap, you might hit out‑of‑memory errors. Adjust
dbms.memory.heap.max_sizeif needed. - Query scope: Indexes only support string data. Numeric or date properties cannot be indexed in this way, and range queries are not possible through the full‑text API.
- Score interpretation: The
scoreis relative to the current query; it should be used only for ordering within that query, not as an absolute metric across different searches.
When to Adopt a Full‑Text Index
If you face:
- Slow text search performance as your graph scales.
- Need for advanced search features (phrases, wildcards, fuzzy matches).
- Ranking results by relevance.
Then a full‑text index is likely the right choice. Otherwise, for simple exact matches on a small dataset, a standard property index may suffice.
Actionable Checklist
- Identify the string property that requires text search.
- Measure current query latency with a full‑scan.
- Create the full‑text index as shown above.
- Run a representative query and compare latency.
- Monitor write latency and disk usage.
- Adjust JVM heap or prune unused indexes if necessary.
By following these steps, you can decide whether the performance gains outweigh the additional storage and write overhead for your specific workload.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.