agrag.graphdb.neo4j.Neo4jGraphStore
Neo4jGraphStore(*, settings:Neo4jSettings | None = None, driver:AsyncDriver | None = None, tracer:Tracer | None = None) -> None
Bases: GraphStore
A GraphStore backed by Neo4j, using native vector indexes.
The driver connects lazily on first use, so constructing the store does not
open a network connection. execute_read/execute_write wrap the
driver's managed transactions with no added retry loop.
Functions:
- close – Close the driver, releasing its connection pool.
- connect – Open the driver and verify connectivity.
- ensure_relation_constraint – Create a relationship type's
iduniqueness constraint once. - ensure_vector_index – Create a native vector index if it does not exist.
- execute_read – Run a read transaction and return its rows.
- execute_write – Run a write transaction and return its rows.
- register_labels – Add labels to this instance's known-label set.
- register_relation_types – Add types to this instance's known-relation-type set.
- session – Open a session to the configured database.
- setup_constraints – Create
idandmerge_keyuniqueness constraints per label. - setup_indexes – Set up indexes now provided by the store's uniqueness constraints.
- transaction – Open one Neo4j explicit transaction spanning multiple writes.
- upsert_nodes – Write or merge nodes, honoring each record's full label set.
- upsert_relations – Write or merge relationships between existing nodes.
- vector_search – Search nodes by dense vector using the native vector index.
Parameters:
- settings (
Neo4jSettings | None) – Neo4j connection settings. Defaults toNeo4jSettings(). - driver (
AsyncDriver | None) – A pre-builtAsyncDriver, for tests. When set,__init__imports nothing and the store calls this object directly instead of building one. - tracer (
Tracer | None) – Opens every span this store's methods produce.
close
close() -> None
Close the driver, releasing its connection pool.
connect
connect() -> None
Open the driver and verify connectivity.
ensure_relation_constraint
ensure_relation_constraint(rel_type:str) -> None
Create a relationship type's id uniqueness constraint once.
Public entry point onto _ensure_relation_constraint for
_Neo4jTransaction.upsert_relations, which must give the same
constraint-before-first-write guarantee inside an explicit
transaction that the non-transactional upsert_relations gives.
Parameters:
- rel_type (
str) – The relationship type to ensure a constraint for. Must already be validated.
ensure_vector_index
ensure_vector_index(*, label:str, vector_property:str, dimensions:int, distance:Distance) -> None
Create a native vector index if it does not exist.
A concurrent creator can commit the same index after this operation starts. Neo4j reports that race as an equivalent-schema error, which means the requested index already exists.
Raises:
EmbeddingDimensionMismatchError– The index already exists with a different dimension thandimensions.
execute_read
execute_read(query:str, parameters:Mapping[str, Any] | None = None, *, timeout:float | None = None) -> list[dict[str, Any]]
Run a read transaction and return its rows.
Parameters:
- query (
str) – The Cypher query to run. - parameters (
Mapping[str, Any] | None) – The query parameters. - timeout (
float | None) – Server-side transaction timeout in seconds, applied through the driver'sunit_of_workso the database terminates the transaction when it runs longer. None uses the server's default timeout.
Returns:
list[dict[str, Any]]– The result rows as dicts.
execute_write
execute_write(query:str, parameters:Mapping[str, Any] | None = None) -> list[dict[str, Any]]
Run a write transaction and return its rows.
Raises:
GraphStoreConstraintViolationError– The write violated a uniqueness constraint, translated from the driver's own exception so callers do not need a hard dependency on it.
register_labels
register_labels(labels:Sequence[str]) -> None
Add labels to this instance's known-label set.
Parameters:
- labels (
Sequence[str]) – The labels to register. Each must be a safe Cypher identifier.
Raises:
ValueError– Any label is not a safe identifier.
register_relation_types
register_relation_types(types:Sequence[str]) -> None
Add types to this instance's known-relation-type set.
Parameters:
- types (
Sequence[str]) – The relationship types to register. Each must be a safe Cypher identifier.
Raises:
ValueError– Any type is not a safe identifier.
session
session() -> AbstractAsyncContextManager[Any]
Open a session to the configured database.
setup_constraints
setup_constraints() -> None
Create id and merge_key uniqueness constraints per label.
"Known" means written by this instance or already present in the
database, so a fresh store can set up constraints for an existing
database without first rewriting every record. The id constraint
backs node identity; merge_key prevents concurrent ingestion from
creating duplicate canonical entities. Also creates the global
uniqueness constraint on NODE_IDENTITY_LABEL that
upsert_node_query's MERGE relies on to resolve a node by id
regardless of its other, mutable labels, and a per-type uniqueness
constraint on id for every known relationship type, which backs
the stale-relationship cleanup upsert_relation_query performs on
endpoint changes.
setup_indexes
setup_indexes() -> None
Set up indexes now provided by the store's uniqueness constraints.
Kept as a no-op for callers that provision constraints and indexes in
separate steps. Neo4j creates backing indexes for the id and
merge_key uniqueness constraints, so creating range indexes for
the same properties would conflict with those constraints.
transaction
transaction() -> AsyncIterator[GraphStoreTransaction]
Open one Neo4j explicit transaction spanning multiple writes.
Commits when the async with block exits cleanly; rolls back and
re-raises when it raises. The identity constraint is ensured before
opening the transaction, the same way upsert_nodes ensures it
before writing, since _Neo4jTransaction.upsert_nodes skips that
check to avoid a nested write racing the transaction it belongs to.
Raises:
GraphStoreConstraintViolationError– A write inside the block, or the commit itself, violated a uniqueness constraint -- Neo4j validates some constraints only at commit time for an explicit transaction, so this can surface here even when every individual write appeared to succeed.
upsert_nodes
upsert_nodes(label:str, nodes:Sequence[NodeRecord], *, batch_size:int = 256, pending_job_id:UUID | None = None) -> UpsertResult
Write or merge nodes, honoring each record's full label set.
label names the batch for constraint/index bookkeeping, matching
every other tracked label; the labels actually written to a node come
from NodeRecord.labels, which may name more than one label (for
example a node that is both Chunk and Entity). Records with
different label sets are grouped and written with separate MERGE
queries, since Cypher requires labels to be literal in the query text
rather than a runtime parameter, so batch_size chunks apply within
each group rather than across the whole call.
pending_job_id tags only the nodes this call creates, through
ON CREATE SET. A node that already exists keeps its state, so a
job's rollback cannot delete data committed earlier.
Returns:
UpsertResult– The number written and one failure entry for each isolated record.
Raises:
ValueError–batch_sizeis not positive.
upsert_relations
upsert_relations(relations:Sequence[RelationRecord], *, batch_size:int = 256, pending_job_id:UUID | None = None) -> UpsertResult
Write or merge relationships between existing nodes.
Relationship identity is each record's id, not its endpoints: see
upsert_relation_query for how endpoint changes and same-id
parallel relationships are handled. pending_job_id tags only the
relationships this call creates.
Returns:
UpsertResult– The number written and one failure entry for each isolated record.
Raises:
ValueError–batch_sizeis not positive.
vector_search
vector_search(*, label:str, vector_property:str, query_vector:Sequence[float], limit:int = 10, filters:dict[str, Any] | None = None) -> list[VectorHit]
Search nodes by dense vector using the native vector index.
A label with no provisioned vector index has nothing to search, so an absent index returns an empty result list rather than a driver error.
Neo4j's vector procedure applies pending and caller filters only after
selecting its top k candidates, so a plain k=limit call can
return fewer matches than actually exist. This escalates k and
retries until limit visible hits come back or the escalation
reaches _VECTOR_SEARCH_MAX_K.
Raises:
ValueError–limitis not positive. A non-positive value is not a meaningful request and would send that same non-positivekto Neo4j's native vector procedure, which requires a positive top-k.