Skip to content

Commit 102d799

Browse files
authored
Adds a fail_if_exist option to index creation functions (#180)
* Updated changelog * Added a fail_if_exists option to create_fulltext_index and create_vector_index * Updated test_indexes.py unit tests * Added tests to test_indexes.py to test fail_if_exists parameters * Replace double quotes with single quotes in f strings * Updated changelog
1 parent 59c6207 commit 102d799

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## Next
44

5+
### Added
6+
- Introduced a fail_if_exist option to index creation functions to control behavior when an index already exists.
7+
8+
### Changed
9+
- Comprehensive rewrite of the README to improve clarity and provide detailed usage examples.
10+
511
## 1.0.0
612

713
### Fixed

src/neo4j_graphrag/indexes.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def create_vector_index(
3838
embedding_property: str,
3939
dimensions: int,
4040
similarity_fn: Literal["euclidean", "cosine"],
41+
fail_if_exists: bool = False,
4142
neo4j_database: Optional[str] = None,
4243
) -> None:
4344
"""
@@ -46,7 +47,6 @@ def create_vector_index(
4647
4748
See Cypher manual on `creating vector indexes <https://neo4j.com/docs/cypher-manual/current/indexes/semantic-indexes/vector-indexes/#create-vector-index>`_.
4849
49-
Important: This operation will fail if an index with the same name already exists.
5050
Ensure that the index name provided is unique within the database context.
5151
5252
Example:
@@ -72,6 +72,7 @@ def create_vector_index(
7272
embedding_property="vectorProperty",
7373
dimensions=1536,
7474
similarity_fn="euclidean",
75+
fail_if_exists=False,
7576
)
7677
7778
@@ -83,6 +84,7 @@ def create_vector_index(
8384
dimensions (int): Vector embedding dimension
8485
similarity_fn (str): case-insensitive values for the vector similarity function:
8586
``euclidean`` or ``cosine``.
87+
fail_if_exists (bool): If True raise an error if the index already exists. Defaults to False.
8688
neo4j_database (Optional[str]): The name of the Neo4j database. If not provided, this defaults to "neo4j" in the database (`see reference to documentation <https://neo4j.com/docs/operations-manual/current/database-administration/#manage-databases-default>`_).
8789
8890
Raises:
@@ -105,7 +107,7 @@ def create_vector_index(
105107

106108
try:
107109
query = (
108-
f"CREATE VECTOR INDEX $name FOR (n:{label}) ON n.{embedding_property} OPTIONS "
110+
f"CREATE VECTOR INDEX $name {'' if fail_if_exists else 'IF NOT EXISTS'} FOR (n:{label}) ON n.{embedding_property} OPTIONS "
109111
"{ indexConfig: { `vector.dimensions`: toInteger($dimensions), `vector.similarity_function`: $similarity_fn } }"
110112
)
111113
logger.info(f"Creating vector index named '{name}'")
@@ -123,6 +125,7 @@ def create_fulltext_index(
123125
name: str,
124126
label: str,
125127
node_properties: list[str],
128+
fail_if_exists: bool = False,
126129
neo4j_database: Optional[str] = None,
127130
) -> None:
128131
"""
@@ -131,7 +134,6 @@ def create_fulltext_index(
131134
132135
See Cypher manual on `creating fulltext indexes <https://neo4j.com/docs/cypher-manual/current/indexes/semantic-indexes/full-text-indexes/#create-full-text-indexes>`_.
133136
134-
Important: This operation will fail if an index with the same name already exists.
135137
Ensure that the index name provided is unique within the database context.
136138
137139
Example:
@@ -155,6 +157,7 @@ def create_fulltext_index(
155157
INDEX_NAME,
156158
label="Document",
157159
node_properties=["vectorProperty"],
160+
fail_if_exists=False,
158161
)
159162
160163
@@ -163,6 +166,7 @@ def create_fulltext_index(
163166
name (str): The unique name of the index.
164167
label (str): The node label to be indexed.
165168
node_properties (list[str]): The node properties to create the fulltext index on.
169+
fail_if_exists (bool): If True raise an error if the index already exists. Defaults to False.
166170
neo4j_database (Optional[str]): The name of the Neo4j database. If not provided, this defaults to "neo4j" in the database (`see reference to documentation <https://neo4j.com/docs/operations-manual/current/database-administration/#manage-databases-default>`_).
167171
168172
Raises:
@@ -180,7 +184,7 @@ def create_fulltext_index(
180184

181185
try:
182186
query = (
183-
"CREATE FULLTEXT INDEX $name "
187+
f"CREATE FULLTEXT INDEX $name {'' if fail_if_exists else 'IF NOT EXISTS'} "
184188
f"FOR (n:`{label}`) ON EACH "
185189
f"[{', '.join(['n.`' + prop + '`' for prop in node_properties])}]"
186190
)

tests/unit/test_indexes.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
def test_create_vector_index_happy_path(driver: MagicMock) -> None:
3232
create_query = (
33-
"CREATE VECTOR INDEX $name FOR (n:People) ON n.name OPTIONS "
33+
"CREATE VECTOR INDEX $name IF NOT EXISTS FOR (n:People) ON n.name OPTIONS "
3434
"{ indexConfig: { `vector.dimensions`: toInteger($dimensions), `vector.similarity_function`: $similarity_fn } }"
3535
)
3636

@@ -43,9 +43,26 @@ def test_create_vector_index_happy_path(driver: MagicMock) -> None:
4343
)
4444

4545

46+
def test_create_vector_index_fail_if_exists(driver: MagicMock) -> None:
47+
create_query = (
48+
"CREATE VECTOR INDEX $name FOR (n:People) ON n.name OPTIONS "
49+
"{ indexConfig: { `vector.dimensions`: toInteger($dimensions), `vector.similarity_function`: $similarity_fn } }"
50+
)
51+
52+
create_vector_index(
53+
driver, "my-index", "People", "name", 2048, "cosine", fail_if_exists=True
54+
)
55+
56+
driver.execute_query.assert_called_once_with(
57+
create_query,
58+
{"name": "my-index", "dimensions": 2048, "similarity_fn": "cosine"},
59+
database_=None,
60+
)
61+
62+
4663
def test_create_vector_index_ensure_escaping(driver: MagicMock) -> None:
4764
create_query = (
48-
"CREATE VECTOR INDEX $name FOR (n:People) ON n.name OPTIONS "
65+
"CREATE VECTOR INDEX $name IF NOT EXISTS FOR (n:People) ON n.name OPTIONS "
4966
"{ indexConfig: { `vector.dimensions`: toInteger($dimensions), `vector.similarity_function`: $similarity_fn } }"
5067
)
5168

@@ -120,7 +137,7 @@ def test_create_fulltext_index_happy_path(driver: MagicMock) -> None:
120137
label = "node-label"
121138
text_node_properties = ["property-1", "property-2"]
122139
create_query = (
123-
"CREATE FULLTEXT INDEX $name "
140+
"CREATE FULLTEXT INDEX $name IF NOT EXISTS "
124141
f"FOR (n:`{label}`) ON EACH "
125142
f"[{', '.join(['n.`' + property + '`' for property in text_node_properties])}]"
126143
)
@@ -134,6 +151,26 @@ def test_create_fulltext_index_happy_path(driver: MagicMock) -> None:
134151
)
135152

136153

154+
def test_create_fulltext_index_fail_if_exists(driver: MagicMock) -> None:
155+
label = "node-label"
156+
text_node_properties = ["property-1", "property-2"]
157+
create_query = (
158+
"CREATE FULLTEXT INDEX $name "
159+
f"FOR (n:`{label}`) ON EACH "
160+
f"[{', '.join(['n.`' + property + '`' for property in text_node_properties])}]"
161+
)
162+
163+
create_fulltext_index(
164+
driver, "my-index", label, text_node_properties, fail_if_exists=True
165+
)
166+
167+
driver.execute_query.assert_called_once_with(
168+
create_query,
169+
{"name": "my-index"},
170+
database_=None,
171+
)
172+
173+
137174
def test_create_fulltext_index_raises_error_with_neo4j_client_error(
138175
driver: MagicMock,
139176
) -> None:
@@ -159,7 +196,7 @@ def test_create_fulltext_index_ensure_escaping(driver: MagicMock) -> None:
159196
label = "node-label"
160197
text_node_properties = ["property-1", "property-2"]
161198
create_query = (
162-
"CREATE FULLTEXT INDEX $name "
199+
"CREATE FULLTEXT INDEX $name IF NOT EXISTS "
163200
f"FOR (n:`{label}`) ON EACH "
164201
f"[{', '.join(['n.`' + property + '`' for property in text_node_properties])}]"
165202
)

0 commit comments

Comments
 (0)