Chapter 21 · Full-Text Search, Text Analysis, Relevance, and Hybrid Retrieval with Graph Context

Evaluate Search Quality with Queries/Judgments Instead of Tuning Only by Anecdotal Examples

Evaluate search quality with a versioned judged query set, precision/recall/MRR/nDCG-style metrics, failure slices, freshness tests, and repeatable regression gates instead of tuning to a handful of attractive demos.

Advanced250–340 minutesJudged-query evaluation labNeo4j 2026.07.1 · Community mandatoryCypher 25 · Full-text/Lucene · english analyzerJava 21/25 · Python driver 6.3 optionalLast reviewed: September 2026

Search teams often tune on the last embarrassing query: add a synonym for “camra,” boost a field for one product, change the analyzer, celebrate the demo, then unknowingly damage dozens of other intents. AtlasMart needs a search acceptance suite: versioned queries, relevance judgments, reproducible retrieval settings, ranking metrics, failure slices and explicit freshness/latency SLOs. The goal is not one perfect number; it is evidence that a change improves the intended population without unacceptable regressions elsewhere.

Mental model

A judged query set is to search what a test suite is to application logic. Every analyzer/schema/query/rank change is an experiment. Freeze inputs and environment, capture ranked IDs, compute metrics, inspect failures, then decide whether to ship.

Learning outcomes

01

Create versioned binary/graded relevance judgments for representative AtlasMart search intents and edge cases.

02

Compute precision@k, recall@k, reciprocal rank and nDCG@k from ranked IDs without using full-text score as the ground truth.

03

Compare lexical-only and graph-aware variants with the same source data, sourceK/finalK and freshness state.

04

Build regression slices for misspellings, phrases, language, stock/inactive filtering, freshness, empty/long queries and security-sensitive cases.

05

Define a production search release gate that includes quality, tail latency, freshness, observability, rollback and bridge-to-vector/hybrid readiness.

Chapter 21 baseline · reviewed 9 September 2026

Current Neo4j Database is 2026.07.1; current 5.26 LTS patch is 5.26.30. Version-sensitive examples use explicit CYPHER 25. The mandatory lab uses self-managed Neo4j Community 2026.07.1, database neo4j, user neo4j, disposable password atlasmart-course-2026, loopback Bolt 7687 and HTTP 7474. Neo4j 2026.x supports Java 21/25. Optional application examples pin the official Python driver to neo4j==6.3.0. No APOC, GDS, embeddings, paid AI service, Aura subscription, or Enterprise license is required for the chapter.

Full-text availability and platform boundary

Full-text indexes and the db.index.fulltext.* procedures used in the mandatory lab are part of the normal Neo4j database feature set and are reproducible in Community. Enterprise adds fine-grained authorization and built-in metrics surfaces that can change what full-text queries are allowed to return or what operational counters are available. Aura also supports database full-text functionality, but server configuration/filesystem/metrics controls are platform-managed and must not be presented as identical to self-managed Neo4j.

Lab contract and exact assumptions

Dimension Chapter 21 assumption
server Neo4j Community 2026.07.1, single disposable local database
Cypher Explicit CYPHER 25 for version-sensitive examples; current packaged configs default new databases to Cypher 25 from 2026.02
Java Java 21 or 25 for the 2026.07 server line
database/auth neo4j / neo4j / atlasmart-course-2026
transport bolt://localhost:7687 and http://localhost:7474 only for disposable loopback lab; remote/production uses verified TLS
plugins none required; no APOC/GDS/GenAI plugin
graph 8 Product nodes, 4 Category nodes, 1 Store, 2 Customers, 8 STOCKED_AT edges, 2 REVIEWED edges
full-text catalog node index uses english analyzer and synchronous updates; reviews relationship index uses english analyzer
score policy never hard-code expected score numbers; verify candidate IDs/order and collect actual scores because Lucene/corpus changes can alter values
measurement learner captures real query latency, ranking, freshness and index state; generated lesson does not claim server execution
Term Mechanism-first meaning
lexical retrieval Retrieval based on analyzed text terms and Lucene query semantics. It is different from graph traversal and different from embedding/vector similarity.
full-text index Lucene-backed Neo4j semantic index over one or more STRING or LIST properties of nodes or relationships, explicitly queried through full-text procedures.
schema The labels or relationship types plus indexed properties associated with one full-text index. An entity qualifies when it has at least one indexed label/type and at least one indexed property.
tokenization Breaking a character stream into searchable terms. The analyzer decides token boundaries, normalization, stemming and stop-word behavior.
analyzer Index/query text-processing pipeline. The default is standard-no-stop-words; language analyzers can stem/filter language-specific terms.
query analyzer Optional analyzer selected in queryNodes/queryRelationships options. It analyzes the query string only; it does not rebuild or reinterpret already-indexed tokens.
Lucene query string The second argument to a full-text query procedure. It can contain Boolean, phrase, field and fuzzy query syntax; parameterizing it protects Cypher syntax but does not make Lucene operators literal.
score Lucene relevance score returned with each hit. It orders results for that query/index; it is not a probability, confidence percentage or portable score scale.
candidate set Top lexical hits retained before graph/business filtering or downstream rank fusion. Candidate limit is a retrieval-recall decision, not merely a UI page size.
eventually consistent index Full-text mode that removes Lucene update work from the commit path and applies queued updates in the background, introducing a freshness window.
freshness SLO Application requirement for how soon committed text must become searchable. It determines whether eventual consistency is acceptable and how staleness is measured.
judged query set Versioned collection of user queries and relevance labels used to evaluate ranking changes reproducibly.
precision@k Fraction of the first k returned results judged relevant.
recall@k Fraction of all judged relevant items retrieved in the first k results.
MRR Mean Reciprocal Rank: rewards returning the first relevant result near the top.
nDCG Normalized Discounted Cumulative Gain: graded relevance metric that rewards putting highly relevant items earlier.
post-ranking Reordering or filtering a retrieved candidate set using graph context, business rules, permissions or a separate ranking model.
rank fusion Combining multiple retrieval lists by their rank positions instead of directly comparing source-specific raw scores.

Direct-entry setup

Run the fixture and wait for indexes to be ONLINE. If you test eventual mode, force a refresh barrier before comparing relevance variants so freshness is not a confounder unless freshness is the thing being evaluated.

Cypher 25 · fixture
CYPHER 25
// Safe to rerun in the disposable Chapter 21 lab.
CREATE CONSTRAINT ch21_product_id IF NOT EXISTS
FOR (p:Product) REQUIRE p.productId IS UNIQUE;
CREATE CONSTRAINT ch21_category_id IF NOT EXISTS
FOR (c:Category) REQUIRE c.categoryId IS UNIQUE;
CREATE CONSTRAINT ch21_store_id IF NOT EXISTS
FOR (s:Store) REQUIRE s.storeId IS UNIQUE;
CREATE CONSTRAINT ch21_customer_id IF NOT EXISTS
FOR (c:Customer) REQUIRE c.customerId IS UNIQUE;

MERGE (cam:Category {categoryId:'CAT-21-CAM'}) SET cam.name='Cameras', cam.labTag='ch21'
MERGE (out:Category {categoryId:'CAT-21-OUT'}) SET out.name='Outdoor', out.labTag='ch21'
MERGE (sec:Category {categoryId:'CAT-21-SEC'}) SET sec.name='Security', sec.labTag='ch21'
MERGE (acc:Category {categoryId:'CAT-21-ACC'}) SET acc.name='Accessories', acc.labTag='ch21'
MERGE (st:Store {storeId:'ST-21-CENTRAL'}) SET st.name='AtlasMart Central', st.labTag='ch21'
MERGE (c1:Customer {customerId:'C-2101'}) SET c1.name='Mina Rahimi', c1.labTag='ch21'
MERGE (c2:Customer {customerId:'C-2102'}) SET c2.name='Omid Karimi', c2.labTag='ch21';

UNWIND [
 {id:'P-2101',name:'Trail Camera Pro',description:'Weatherproof wildlife trail camera with infrared night vision and long battery life',tags:['wildlife','trail','infrared','outdoor'],active:true,category:'CAT-21-CAM',qty:5,featured:true},
 {id:'P-2102',name:'Trail Camera Mini',description:'Compact wildlife camera for trails, gardens, and backyard monitoring',tags:['wildlife','trail','compact'],active:true,category:'CAT-21-CAM',qty:0,featured:false},
 {id:'P-2103',name:'Indoor Security Camera',description:'Wi-Fi home security camera with motion alerts and night vision',tags:['security','indoor','night vision'],active:true,category:'CAT-21-SEC',qty:7,featured:false},
 {id:'P-2104',name:'Trail Running Hydration Vest',description:'Lightweight hydration vest for long trail runs and mountain races',tags:['running','trail','hydration'],active:true,category:'CAT-21-OUT',qty:11,featured:false},
 {id:'P-2105',name:'Action Camera 4K',description:'Water-resistant action sports camera for cycling, hiking, and travel',tags:['action','sports','camera'],active:true,category:'CAT-21-CAM',qty:3,featured:true},
 {id:'P-2106',name:'Wildlife Field Guide',description:'Illustrated guide to birds and mammals for outdoor observation',tags:['wildlife','book','outdoor'],active:true,category:'CAT-21-OUT',qty:6,featured:false},
 {id:'P-2107',name:'Solar Trail Charger',description:'Solar charger for outdoor cameras, sensors, and trail equipment',tags:['solar','trail','charger'],active:true,category:'CAT-21-ACC',qty:0,featured:false},
 {id:'P-2108',name:'Refurbished Trail Camera',description:'Older trail camera unit retained for support reference only',tags:['trail','camera','refurbished'],active:false,category:'CAT-21-CAM',qty:2,featured:false}
] AS row
MERGE (p:Product {productId:row.id})
SET p.name=row.name, p.description=row.description, p.tags=row.tags,
    p.active=row.active, p.featured=row.featured, p.labTag='ch21'
WITH row,p
MATCH (cat:Category {categoryId:row.category}), (st:Store {storeId:'ST-21-CENTRAL'})
MERGE (p)-[:IN_CATEGORY]->(cat)
MERGE (p)-[stock:STOCKED_AT]->(st)
SET stock.quantity=row.qty, stock.labTag='ch21';

MATCH (c1:Customer {customerId:'C-2101'}), (p1:Product {productId:'P-2101'})
MERGE (c1)-[r1:REVIEWED]->(p1)
SET r1.reviewId='REV-2101', r1.rating=5,
    r1.message='Excellent night vision for wildlife at the cabin', r1.labTag='ch21';
MATCH (c2:Customer {customerId:'C-2102'}), (p4:Product {productId:'P-2104'})
MERGE (c2)-[r2:REVIEWED]->(p4)
SET r2.reviewId='REV-2102', r2.rating=4,
    r2.message='Comfortable on long trail runs', r2.labTag='ch21';

CREATE FULLTEXT INDEX ch21_catalog_ft IF NOT EXISTS
FOR (p:Product) ON EACH [p.name, p.description, p.tags]
OPTIONS {indexConfig: {
  `fulltext.analyzer`: 'english',
  `fulltext.eventually_consistent`: false
}};

CREATE FULLTEXT INDEX ch21_reviews_ft IF NOT EXISTS
FOR ()-[r:REVIEWED]-() ON EACH [r.message]
OPTIONS {indexConfig: {`fulltext.analyzer`: 'english'}};

CALL db.awaitIndexes(300);
Cypher 25 · verify state
CYPHER 25
SHOW FULLTEXT INDEXES
YIELD name, state, populationPercent, entityType, labelsOrTypes,
      properties, indexProvider, options, lastRead, readCount
WHERE name STARTS WITH 'ch21_'
RETURN * ORDER BY name;

MATCH (p:Product {labTag:'ch21'})
RETURN count(p) AS products,
       count { (p)-[:STOCKED_AT]->(:Store {storeId:'ST-21-CENTRAL'}) } AS stockEdges;
// Deterministic graph invariant: products = 8 and stockEdges = 8.
// Full-text state invariant before search: both indexes are ONLINE and 100% populated.

1. Judgments describe user intent, not current ranking

Assign relevance labels before looking at the proposed ranking change whenever possible. Grade 3 can mean “ideal,” 2 “useful,” 1 “weakly relevant,” and 0/unlisted “not relevant.” Keep judgments versioned with intent notes. The fixture deliberately includes ambiguity: P-2106 contains “wildlife” but is a field guide, while P-2108 is a strong lexical trail-camera match that is inactive.

Query ID Intent Graded relevant IDs
q1 wildlife camera P-2101=3, P-2102=2, P-2106=1
q2 trail camera P-2101=3, P-2102=3, P-2108=1
q3 night vision camera P-2101=3, P-2103=2
q4 camera outdoor P-2101=3, P-2105=2, P-2102=1
Business-filtered judgments may differ

For a “buy now at ST-21-CENTRAL” result set, out-of-stock P-2102 and inactive P-2108 may be judged non-eligible even if lexically relevant. Keep lexical-relevance judgments and final-business judgments as separate datasets when both questions matter.

2. Capture ranked IDs; never make Lucene score the label

Run each query with identical index/analyzer/sourceK settings and store product IDs in returned order. Keep actual scores as diagnostics, but the evaluator consumes ranks and human/business judgments. That prevents the system from “proving itself correct” using its own score.

Cypher 25 · rank capture query
// Capture ranked IDs for the four judged queries. Run each query separately and
// put the returned productId order into results.json; do not copy score values into the judgments.
CYPHER 25
CALL db.index.fulltext.queryNodes('ch21_catalog_ft', $q, {limit: 10})
YIELD node, score
RETURN node.productId AS productId, node.name AS name, score
ORDER BY score DESC;
Example results.json shape — replace IDs with your measured ranks
{
  "q1": ["P-2101", "P-2106", "P-2102"],
  "q2": ["P-2101", "P-2102", "P-2108"],
  "q3": ["P-2103", "P-2101"],
  "q4": ["P-2105", "P-2101", "P-2102"]
}
Illustrative shape, not claimed server output

The JSON above only demonstrates file format. Replace it with IDs captured from your Neo4j 2026.07.1 lab before interpreting metrics.

3. Evaluate with multiple metrics because they answer different questions

Precision@k asks how many shown items are relevant. Recall@k asks how much known relevant inventory was recovered. MRR emphasizes the first relevant hit. nDCG@k uses graded relevance and position. A retail autosuggest may prioritize early precision/MRR; a support discovery workflow may care more about recall.

Python · evaluate_search.py
#!/usr/bin/env python3
"""Evaluate AtlasMart Chapter 21 ranked product IDs captured from Neo4j.
Usage: python evaluate_search.py results.json
results.json example: {"q1":["P-2101","P-2102","P-2106"], ...}
"""
import json, math, sys

JUDGMENTS = {
  "q1": {"query":"wildlife camera", "grades":{"P-2101":3,"P-2102":2,"P-2106":1}},
  "q2": {"query":"trail camera", "grades":{"P-2101":3,"P-2102":3,"P-2108":1}},
  "q3": {"query":"night vision camera", "grades":{"P-2101":3,"P-2103":2}},
  "q4": {"query":"camera outdoor", "grades":{"P-2101":3,"P-2105":2,"P-2102":1}},
}
K = 3

def dcg(ids, grades, k):
    total = 0.0
    for rank, pid in enumerate(ids[:k], start=1):
        gain = grades.get(pid, 0)
        total += (2**gain - 1) / math.log2(rank + 1)
    return total

def metrics(ids, grades, k):
    rel = {pid for pid,g in grades.items() if g > 0}
    top = ids[:k]
    hits = [pid for pid in top if pid in rel]
    precision = len(hits) / k
    recall = len(hits) / len(rel) if rel else 0.0
    rr = 0.0
    for rank,pid in enumerate(ids, start=1):
        if pid in rel:
            rr = 1.0 / rank; break
    ideal = [pid for pid,_ in sorted(grades.items(), key=lambda x:x[1], reverse=True)]
    idcg = dcg(ideal, grades, k)
    ndcg = dcg(ids, grades, k) / idcg if idcg else 0.0
    return precision, recall, rr, ndcg

results = json.load(open(sys.argv[1], encoding='utf-8'))
rows=[]
for qid,spec in JUDGMENTS.items():
    ids = results.get(qid, [])
    p,r,rr,n = metrics(ids, spec['grades'], K)
    rows.append((qid,p,r,rr,n))
    print(f"{qid} P@{K}={p:.3f} R@{K}={r:.3f} RR={rr:.3f} nDCG@{K}={n:.3f}")
if rows:
    print('macro', ' '.join([
      f"P@{K}={sum(x[1] for x in rows)/len(rows):.3f}",
      f"R@{K}={sum(x[2] for x in rows)/len(rows):.3f}",
      f"MRR={sum(x[3] for x in rows)/len(rows):.3f}",
      f"nDCG@{K}={sum(x[4] for x in rows)/len(rows):.3f}",
    ]))
Terminal · run after capturing results.json
python evaluate_search.py results.json
# The script prints measured metrics from your captured ranks.
# Do not paste fixed expected values into the course: ranking can change with corpus/analyzer/release.

4. Compare variants with controlled experiments

Variant Change exactly one factor Hold constant
A english analyzer catalog index fixture, query set, sourceK, graph rules
B different analyzer/schema fixture, query set, sourceK, graph rules
C lexical only same index, same sourceK, finalK
D lexical + graph eligibility/rank same index/query set/sourceK
E eventual consistency same quality model but measure visibility lag separately

Do not compare a cold rebuilt index, different corpus, different candidate count and new ranking rule in one experiment. If four things change, a better metric cannot tell you which mechanism helped.

5. Build failure slices, not only macro averages

Slice Why it can regress independently
exact product names / IDs tokenization or stop-word changes can harm precision
misspellings / fuzzy query parser and fuzzy expansion can add noise/cost
phrases analyzer/token positions affect phrase behavior
multilingual stemming/stop words/tokenization differ by language
inactive/out-of-stock graph/business eligibility can reduce lexical recall intentionally
long/empty/operator-heavy queries query grammar and candidate explosion risk
freshly updated products eventual indexing changes visibility timing
security-sensitive roles semantic-index conservative filtering can reduce available candidates

6. Quality is only one release gate

A ranking variant that raises nDCG but doubles p99 latency or violates freshness is not automatically better. Search release evidence should join relevance, latency, resource, correctness and operations.

Gate Example evidence
quality no unacceptable regression in P@k/R@k/MRR/nDCG overall and critical slices
latency retrieval + graph expansion p50/p95/p99 under representative concurrency
freshness commit-to-search visibility distribution meets chosen SLO
capacity index/store growth, CPU/disk, result bytes and candidate expansion headroom
security exact application role and tenant filters tested
operations ONLINE/rebuild/recovery checks, dashboards/log correlation, rollback plan
versioning server/Cypher/index provider/analyzer/config and judged-set versions recorded

7. Wrong approach → failure → repair

Wrong approach Failure Repair
tune from one anecdotal query local fix harms unseen intents versioned representative judged set
use full-text score as “truth” self-referential evaluation human/business judgments + rank metrics
optimize macro average only critical language/security/typo slice regresses slice metrics and minimum gates
change corpus/analyzer/rules together causality disappears one controlled change per experiment
ship relevance gain despite p99/freshness collapse search quality improves while product SLO fails multi-dimensional release gate

8. Production runbook and bridge to Chapter 22

  1. Freeze fixture/corpus snapshot, server/Cypher/index/analyzer configuration and judged-set version.
  2. Wait for indexes ONLINE; if testing quality rather than freshness, synchronize eventual indexes.
  3. Warm the workload consistently and execute the complete query suite.
  4. Capture candidate IDs/ranks/scores, filter reasons, p50/p95/p99, zero-result rate and resource evidence.
  5. Compute quality metrics and slices.
  6. Review security/freshness/capacity regressions.
  7. Approve or reject the single change; retain rollback commands/index definition.
  8. When adding vector retrieval in Chapter 22, keep the lexical baseline unchanged and fuse ranked lists rather than raw score magnitudes.

9. Cleanup / reset

Run only against the disposable Chapter 21 lab. This removes the chapter indexes, synthetic graph entities and chapter constraints.

Cypher 25 · cleanup
CYPHER 25
DROP INDEX ch21_catalog_ft IF EXISTS;
DROP INDEX ch21_reviews_ft IF EXISTS;
DROP INDEX ch21_freshness_ft IF EXISTS;
MATCH (n) WHERE n.labTag='ch21' DETACH DELETE n;
DROP CONSTRAINT ch21_product_id IF EXISTS;
DROP CONSTRAINT ch21_category_id IF EXISTS;
DROP CONSTRAINT ch21_store_id IF EXISTS;
DROP CONSTRAINT ch21_customer_id IF EXISTS;

10. Final production judgment

Production decision Evidence to require before changing the system
graph/workload fit Search logs and judged queries show a lexical need; traversal-only or exact/text-index predicates are not sufficient.
correctness/non-guarantees Document analyzer, query syntax contract, candidate limit, freshness mode and the fact that relevance score is not a probability.
model/cardinality/degree Measure candidate counts and graph expansion fan-out; cap/bound traversal after retrieval.
latency Track p50/p95/p99 for retrieval plus graph expansion separately; do not optimize only the Lucene call.
transactions/freshness Choose synchronous vs eventual full-text updates from freshness SLO and write-path cost, not folklore.
memory/storage Observe index size, page cache/store pressure, heap impact of eventual-consistency queues and result materialization.
CPU/disk/network Correlate query rate, index update rate, store I/O and response bytes; large candidate sets can shift cost to application/network.
indexes/constraints Keep business-key constraints separate from full-text access paths; wait for ONLINE before querying or benchmarking.
driver/pool/timeouts Use bounded result limits, parameterized Cypher and explicit timeout/retry policy; avoid keeping sessions open while users inspect results.
security/tenant risk Verify graph privileges plus semantic-index conservative filtering; do not assume index membership equals authorization.
backup/recovery Include full-text index recreation/check behavior in recovery drills and verify search after restore rather than assuming index health.
observability Community: SHOW FULLTEXT INDEXES + application logs/OS evidence. Enterprise: add supported metrics such as fulltext queried/populated counters.
testing/failure injection Regression-test analyzer changes, misspellings, empty queries, high-result queries, stale-index windows, denied-data cases and graph-filter effects.
version/tier Record Neo4j/Cypher/analyzer/index provider/platform versions; Aura/self-managed controls and metrics are not identical.
cost/migration Account for reindex time, storage, write amplification, evaluation maintenance and eventual move to vector/hybrid retrieval.

Check your understanding

  1. Why should judgments not be copied from current full-text scores?
  2. What does nDCG add beyond precision@k?
  3. Why keep failure slices?
  4. What must be held constant in a search experiment?
  5. What changes when Chapter 22 adds vector search?
Review the answers

1. The score is the system output being evaluated; using it as truth makes evaluation circular.

2. It uses graded relevance and discounts lower ranks, rewarding highly relevant items near the top.

3. Macro averages can hide regressions in languages, typo queries, security roles, freshness or exact-name intents.

4. Corpus/fixture, query/judgment set, sourceK/finalK, freshness state and all settings except the intended factor as far as practical.

5. A second retrieval source and ranking signal are introduced; full-text and vector lists must be ranked independently and fused deliberately, not compared by raw score.

Summary and next step

Chapter 21 now treats lexical search as an engineered retrieval system: schema + analyzer + query contract + freshness + bounded candidates + graph/business context + judged evaluation. Chapter 22 can add embeddings/vector search without destroying that discipline: semantic/vector scores remain source-specific, and hybrid retrieval will fuse independently ranked lexical and vector lists before graph-aware context assembly.

Authoritative references

  • Current Neo4j versions — Current database release 2026.07.1 and current 5.26 LTS patch 5.26.30.
  • Full-text indexes — Cypher 25 — Current schema, analyzer, query, score, eventual-consistency, SHOW FULLTEXT INDEXES and procedure semantics.
  • Semantic indexes — Why full-text and vector indexes are explicit semantic retrieval systems and why raw cross-source scores should not be compared.
  • Built-in full-text procedures — Current signatures for queryNodes/queryRelationships/listAvailableAnalyzers/awaitEventuallyConsistentIndexRefresh and limit/skip/query-analyzer options.
  • Index configuration — Default analyzer, eventual-consistency queue model, background update settings and operational implications.
  • Configuration settings — Current db.index.fulltext.* defaults, including standard-no-stop-words and eventual-consistency settings.
  • Index syntax — Current CREATE/SHOW/DROP and semantic-index query syntax; SHOW FULLTEXT INDEXES is the supported filtered SHOW form.
  • Security limitations for semantic indexes — Lucene-backed full-text/vector security filtering can conservatively return partial or zero results under fine-grained restrictions.
  • Hybrid search developer guide — Current rank-fusion guidance for lexical, vector and structural sources; fuse ranks, not incomparable raw scores.
  • Hybrid search engineering article — 2026 worked explanation of combining words, meaning and graph topology with rank-based fusion.
  • Metrics — Enterprise-only built-in metrics surface and monitoring responsibilities.
  • Metrics reference — Current full-text queried/populated counters; edition boundary is Enterprise.
  • System requirements — Neo4j 2026.07 supported Java 21/25 and current OS/runtime boundaries.
  • Python driver 6.3 — Official driver API used by the optional evaluation harness; current 6.3 supports Neo4j 2026.x.
  • Vector SEARCH clause — Bridge to Chapter 22 and explicit current warning to rank vector/full-text sources independently.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.