Boost Neo4j Query Speed with Native Full‑Text Indexing
Learn how Neo4j’s native full‑text indexes can cut query latency from seconds to milliseconds, what trade‑offs to watch for, and a step‑by‑step example that shows how to create, query, and monitor a full‑text index in a graph of millions of nodes.
18 Apr 2026, 00:08 UTC

The Problem: Scanning a Sea of Text
In many graph applications the most common bottleneck isn’t the graph structure itself but the sheer volume of string data stored on nodes and relationships. Imagine a knowledge‑graph of millions of research papers where you need to find all articles whose title contains the word “Neo4j”. A simple MATCH (a:Article) followed by a WHERE a.title CONTAINS 'Neo4j' forces Neo4j to scan every Article node, turning a few‑millisecond query into a multi‑second one.
The Solution: Neo4j’s Native Full‑Text Index
Neo4j ships with a built‑in full‑text indexing engine that tokenises, stems, and optionally language‑specific‑analyses string properties. Once the index is built, search queries are reduced to a lookup of pre‑tokenised terms, giving sub‑millisecond latency even on graphs with tens of millions of nodes.
Key Features
- Tokenisation and stemming for natural‑language queries.
- Language‑specific analyzers (e.g., English, French) to handle stop‑words and inflection.
- Automatic incremental updates: edits to indexed properties are reflected without rebuilding the entire index.
- Separate indexes for nodes and relationships, each defined once per property per graph.
Creating and Using a Full‑Text Index
1. Verify Edition and Permissions
Full‑text indexing is available in the Enterprise Edition and in Community Edition starting with Neo4j 4.4. Run the following to confirm you’re on the correct edition and have the necessary privileges (typically a user with system role):
SHOW DATABASES; // Look for "enterprise" in the "edition" column
2. Create the Index
Replace <indexName>, <Label>, and <property> with your own values. The command must be executed in a Neo4j session that has CREATE privileges on the target database.
CALL db.index.fulltext.createNodeIndex('articleTitleIndex', ['Article'], ['title']);
Check that the index is listed and in a ONLINE state:
CALL db.index.fulltext.list();
3. Query the Index
The query API returns only node or relationship IDs and a relevance score. To retrieve full properties, combine the index call with a MATCH clause. The following example finds articles whose title matches the term “Neo4j” and returns the title and author:
CALL db.index.fulltext.queryNodes('articleTitleIndex', 'Neo4j') YIELD node, score
MATCH (node)
RETURN node.title AS title, node.author AS author, score
ORDER BY score DESC
LIMIT 10;
Tips for a smooth query:
- Use
YIELD node, scoreto bring the result into a standard Cypher flow. - Apply
LIMITbeforeRETURNto avoid pulling too many rows into memory. - When searching multiple properties, create separate indexes (e.g., for
titleandabstract) and combine results withUNION ALL.
Performance Gains and Trade‑offs
Speed
Benchmarks from Neo4j’s own documentation show query latency dropping from ~2 s for a full‑scan to <10 ms for a full‑text lookup on a 10‑million node graph. The exact numbers depend on your hardware, JVM heap size, and query complexity.
Memory Footprint
Full‑text indexes consume additional heap memory proportional to the number of unique tokens. For very large graphs, you might observe a 1–2 GB increase. Monitor with metrics endpoint or Neo4j Browser’s system database.
Flexibility Limits
Neo4j enforces one index per property per graph. Attempting to create a second index on the same property results in an error, which can be a constraint if you need varied analyzers for the same property. Workarounds include:
- Creating a dedicated property for the search term (e.g.,
searchTitle) and indexing that. - Using
db.index.fulltext.createNodeIndexwith a custom analyzer that handles multiple languages.
Concrete Example: Search for Articles About Neo4j
Suppose you run a research portal storing millions of Article nodes, each with properties: title, abstract, author, and publicationYear. You want a fast “search by keyword” feature.
- Create the index:
- Query with relevance:
- Verify: Inspect the first few rows in Neo4j Browser or use
CALL db.index.fulltext.list();to confirm the index isONLINE.
CALL db.index.fulltext.createNodeIndex('articleSearch', ['Article'], ['title', 'abstract']);
CALL db.index.fulltext.queryNodes('articleSearch', 'Neo4j AND graph') YIELD node, score
MATCH (node)
RETURN node.title AS title, node.author AS author, node.publicationYear AS year, score
ORDER BY score DESC
LIMIT 20;
Result: a ranked list of articles, each with a relevance score indicating how well the title or abstract matches the query.
Monitoring and Maintenance
- Check index health:
CALL db.index.fulltext.list();– look forstatus: "ONLINE". - Monitor JVM heap: Neo4j Browser’s
systemdatabase ormetrics/neo4j/heap/used_bytesendpoint. - Re‑create the index only when you need to change the analyzer or add new properties; otherwise, rely on incremental updates.
Takeaway
Full‑text indexing in Neo4j is a powerful, low‑overhead way to turn slow, full‑scan string queries into lightning‑fast relevance searches. By creating a single index per property, you can dramatically reduce latency, but keep an eye on memory usage and remember that each property can only have one index. If your application requires multiple analyzers for the same property, consider storing a dedicated searchable field or using a custom analyzer. With these steps, you’ll deliver a responsive search experience even as your graph grows.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.