graphiti-core 0.5.2__tar.gz → 0.5.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphiti-core might be problematic. Click here for more details.
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/PKG-INFO +1 -1
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/graphiti.py +6 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/config.py +1 -1
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/search/search.py +19 -4
- graphiti_core-0.5.3/graphiti_core/search/search_filters.py +152 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/search/search_utils.py +49 -23
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/pyproject.toml +1 -1
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/LICENSE +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/README.md +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/cross_encoder/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/cross_encoder/bge_reranker_client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/cross_encoder/client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/cross_encoder/openai_reranker_client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/edges.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/embedder/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/embedder/client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/embedder/openai.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/embedder/voyage.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/errors.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/helpers.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/anthropic_client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/errors.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/groq_client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/openai_client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/openai_generic_client.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/utils.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/models/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/models/edges/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/models/edges/edge_db_queries.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/models/nodes/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/models/nodes/node_db_queries.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/nodes.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/dedupe_edges.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/dedupe_nodes.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/eval.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/extract_edge_dates.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/extract_edges.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/extract_nodes.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/invalidate_edges.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/lib.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/models.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/prompt_helpers.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/prompts/summarize_nodes.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/py.typed +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/search/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/search/search_config.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/search/search_config_recipes.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/bulk_utils.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/datetime_utils.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/__init__.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/community_operations.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/edge_operations.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/graph_data_operations.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/node_operations.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/temporal_operations.py +0 -0
- {graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/utils.py +0 -0
|
@@ -35,6 +35,7 @@ from graphiti_core.search.search_config_recipes import (
|
|
|
35
35
|
EDGE_HYBRID_SEARCH_NODE_DISTANCE,
|
|
36
36
|
EDGE_HYBRID_SEARCH_RRF,
|
|
37
37
|
)
|
|
38
|
+
from graphiti_core.search.search_filters import SearchFilters
|
|
38
39
|
from graphiti_core.search.search_utils import (
|
|
39
40
|
RELEVANT_SCHEMA_LIMIT,
|
|
40
41
|
get_communities_by_nodes,
|
|
@@ -481,6 +482,7 @@ class Graphiti:
|
|
|
481
482
|
except Exception as e:
|
|
482
483
|
raise e
|
|
483
484
|
|
|
485
|
+
#### WIP: USE AT YOUR OWN RISK ####
|
|
484
486
|
async def add_episode_bulk(self, bulk_episodes: list[RawEpisode], group_id: str = ''):
|
|
485
487
|
"""
|
|
486
488
|
Process multiple episodes in bulk and update the graph.
|
|
@@ -624,6 +626,7 @@ class Graphiti:
|
|
|
624
626
|
center_node_uuid: str | None = None,
|
|
625
627
|
group_ids: list[str] | None = None,
|
|
626
628
|
num_results=DEFAULT_SEARCH_LIMIT,
|
|
629
|
+
search_filter: SearchFilters | None = None,
|
|
627
630
|
) -> list[EntityEdge]:
|
|
628
631
|
"""
|
|
629
632
|
Perform a hybrid search on the knowledge graph.
|
|
@@ -669,6 +672,7 @@ class Graphiti:
|
|
|
669
672
|
query,
|
|
670
673
|
group_ids,
|
|
671
674
|
search_config,
|
|
675
|
+
search_filter if search_filter is not None else SearchFilters(),
|
|
672
676
|
center_node_uuid,
|
|
673
677
|
)
|
|
674
678
|
).edges
|
|
@@ -682,6 +686,7 @@ class Graphiti:
|
|
|
682
686
|
group_ids: list[str] | None = None,
|
|
683
687
|
center_node_uuid: str | None = None,
|
|
684
688
|
bfs_origin_node_uuids: list[str] | None = None,
|
|
689
|
+
search_filter: SearchFilters | None = None,
|
|
685
690
|
) -> SearchResults:
|
|
686
691
|
return await search(
|
|
687
692
|
self.driver,
|
|
@@ -690,6 +695,7 @@ class Graphiti:
|
|
|
690
695
|
query,
|
|
691
696
|
group_ids,
|
|
692
697
|
config,
|
|
698
|
+
search_filter if search_filter is not None else SearchFilters(),
|
|
693
699
|
center_node_uuid,
|
|
694
700
|
bfs_origin_node_uuids,
|
|
695
701
|
)
|
|
@@ -39,6 +39,7 @@ from graphiti_core.search.search_config import (
|
|
|
39
39
|
SearchConfig,
|
|
40
40
|
SearchResults,
|
|
41
41
|
)
|
|
42
|
+
from graphiti_core.search.search_filters import SearchFilters
|
|
42
43
|
from graphiti_core.search.search_utils import (
|
|
43
44
|
community_fulltext_search,
|
|
44
45
|
community_similarity_search,
|
|
@@ -64,6 +65,7 @@ async def search(
|
|
|
64
65
|
query: str,
|
|
65
66
|
group_ids: list[str] | None,
|
|
66
67
|
config: SearchConfig,
|
|
68
|
+
search_filter: SearchFilters,
|
|
67
69
|
center_node_uuid: str | None = None,
|
|
68
70
|
bfs_origin_node_uuids: list[str] | None = None,
|
|
69
71
|
) -> SearchResults:
|
|
@@ -86,6 +88,7 @@ async def search(
|
|
|
86
88
|
query_vector,
|
|
87
89
|
group_ids,
|
|
88
90
|
config.edge_config,
|
|
91
|
+
search_filter,
|
|
89
92
|
center_node_uuid,
|
|
90
93
|
bfs_origin_node_uuids,
|
|
91
94
|
config.limit,
|
|
@@ -133,6 +136,7 @@ async def edge_search(
|
|
|
133
136
|
query_vector: list[float],
|
|
134
137
|
group_ids: list[str] | None,
|
|
135
138
|
config: EdgeSearchConfig | None,
|
|
139
|
+
search_filter: SearchFilters,
|
|
136
140
|
center_node_uuid: str | None = None,
|
|
137
141
|
bfs_origin_node_uuids: list[str] | None = None,
|
|
138
142
|
limit=DEFAULT_SEARCH_LIMIT,
|
|
@@ -143,11 +147,20 @@ async def edge_search(
|
|
|
143
147
|
search_results: list[list[EntityEdge]] = list(
|
|
144
148
|
await semaphore_gather(
|
|
145
149
|
*[
|
|
146
|
-
edge_fulltext_search(driver, query, group_ids, 2 * limit),
|
|
150
|
+
edge_fulltext_search(driver, query, search_filter, group_ids, 2 * limit),
|
|
147
151
|
edge_similarity_search(
|
|
148
|
-
driver,
|
|
152
|
+
driver,
|
|
153
|
+
query_vector,
|
|
154
|
+
None,
|
|
155
|
+
None,
|
|
156
|
+
search_filter,
|
|
157
|
+
group_ids,
|
|
158
|
+
2 * limit,
|
|
159
|
+
config.sim_min_score,
|
|
160
|
+
),
|
|
161
|
+
edge_bfs_search(
|
|
162
|
+
driver, bfs_origin_node_uuids, config.bfs_max_depth, search_filter, 2 * limit
|
|
149
163
|
),
|
|
150
|
-
edge_bfs_search(driver, bfs_origin_node_uuids, config.bfs_max_depth, 2 * limit),
|
|
151
164
|
]
|
|
152
165
|
)
|
|
153
166
|
)
|
|
@@ -155,7 +168,9 @@ async def edge_search(
|
|
|
155
168
|
if EdgeSearchMethod.bfs in config.search_methods and bfs_origin_node_uuids is None:
|
|
156
169
|
source_node_uuids = [edge.source_node_uuid for result in search_results for edge in result]
|
|
157
170
|
search_results.append(
|
|
158
|
-
await edge_bfs_search(
|
|
171
|
+
await edge_bfs_search(
|
|
172
|
+
driver, source_node_uuids, config.bfs_max_depth, search_filter, 2 * limit
|
|
173
|
+
)
|
|
159
174
|
)
|
|
160
175
|
|
|
161
176
|
edge_uuid_map = {edge.uuid: edge for result in search_results for edge in result}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright 2024, Zep Software, Inc.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
from enum import Enum
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from pydantic import BaseModel, Field
|
|
22
|
+
from typing_extensions import LiteralString
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ComparisonOperator(Enum):
|
|
26
|
+
equals = '='
|
|
27
|
+
not_equals = '<>'
|
|
28
|
+
greater_than = '>'
|
|
29
|
+
less_than = '<'
|
|
30
|
+
greater_than_equal = '>='
|
|
31
|
+
less_than_equal = '<='
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DateFilter(BaseModel):
|
|
35
|
+
date: datetime = Field(description='A datetime to filter on')
|
|
36
|
+
comparison_operator: ComparisonOperator = Field(
|
|
37
|
+
description='Comparison operator for date filter'
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SearchFilters(BaseModel):
|
|
42
|
+
valid_at: list[list[DateFilter]] | None = Field(default=None)
|
|
43
|
+
invalid_at: list[list[DateFilter]] | None = Field(default=None)
|
|
44
|
+
created_at: list[list[DateFilter]] | None = Field(default=None)
|
|
45
|
+
expired_at: list[list[DateFilter]] | None = Field(default=None)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def search_filter_query_constructor(filters: SearchFilters) -> tuple[LiteralString, dict[str, Any]]:
|
|
49
|
+
filter_query: LiteralString = ''
|
|
50
|
+
filter_params: dict[str, Any] = {}
|
|
51
|
+
|
|
52
|
+
if filters.valid_at is not None:
|
|
53
|
+
valid_at_filter = 'AND ('
|
|
54
|
+
for i, or_list in enumerate(filters.valid_at):
|
|
55
|
+
for j, date_filter in enumerate(or_list):
|
|
56
|
+
filter_params['valid_at_' + str(j)] = date_filter.date
|
|
57
|
+
|
|
58
|
+
and_filters = [
|
|
59
|
+
'(r.valid_at ' + date_filter.comparison_operator.value + f' $valid_at_{j})'
|
|
60
|
+
for j, date_filter in enumerate(or_list)
|
|
61
|
+
]
|
|
62
|
+
and_filter_query = ''
|
|
63
|
+
for j, and_filter in enumerate(and_filters):
|
|
64
|
+
and_filter_query += and_filter
|
|
65
|
+
if j != len(and_filter_query) - 1:
|
|
66
|
+
and_filter_query += ' AND '
|
|
67
|
+
|
|
68
|
+
valid_at_filter += and_filter_query
|
|
69
|
+
|
|
70
|
+
if i == len(or_list) - 1:
|
|
71
|
+
valid_at_filter += ')'
|
|
72
|
+
else:
|
|
73
|
+
valid_at_filter += ' OR '
|
|
74
|
+
|
|
75
|
+
filter_query += valid_at_filter
|
|
76
|
+
|
|
77
|
+
if filters.invalid_at is not None:
|
|
78
|
+
invalid_at_filter = 'AND ('
|
|
79
|
+
for i, or_list in enumerate(filters.invalid_at):
|
|
80
|
+
for j, date_filter in enumerate(or_list):
|
|
81
|
+
filter_params['invalid_at_' + str(j)] = date_filter.date
|
|
82
|
+
|
|
83
|
+
and_filters = [
|
|
84
|
+
'(r.invalid_at ' + date_filter.comparison_operator.value + f' $invalid_at_{j})'
|
|
85
|
+
for j, date_filter in enumerate(or_list)
|
|
86
|
+
]
|
|
87
|
+
and_filter_query = ''
|
|
88
|
+
for j, and_filter in enumerate(and_filters):
|
|
89
|
+
and_filter_query += and_filter
|
|
90
|
+
if j != len(and_filter_query) - 1:
|
|
91
|
+
and_filter_query += ' AND '
|
|
92
|
+
|
|
93
|
+
invalid_at_filter += and_filter_query
|
|
94
|
+
|
|
95
|
+
if i == len(or_list) - 1:
|
|
96
|
+
invalid_at_filter += ')'
|
|
97
|
+
else:
|
|
98
|
+
invalid_at_filter += ' OR '
|
|
99
|
+
|
|
100
|
+
filter_query += invalid_at_filter
|
|
101
|
+
|
|
102
|
+
if filters.created_at is not None:
|
|
103
|
+
created_at_filter = 'AND ('
|
|
104
|
+
for i, or_list in enumerate(filters.created_at):
|
|
105
|
+
for j, date_filter in enumerate(or_list):
|
|
106
|
+
filter_params['created_at_' + str(j)] = date_filter.date
|
|
107
|
+
|
|
108
|
+
and_filters = [
|
|
109
|
+
'(r.created_at ' + date_filter.comparison_operator.value + f' $created_at_{j})'
|
|
110
|
+
for j, date_filter in enumerate(or_list)
|
|
111
|
+
]
|
|
112
|
+
and_filter_query = ''
|
|
113
|
+
for j, and_filter in enumerate(and_filters):
|
|
114
|
+
and_filter_query += and_filter
|
|
115
|
+
if j != len(and_filter_query) - 1:
|
|
116
|
+
and_filter_query += ' AND '
|
|
117
|
+
|
|
118
|
+
created_at_filter += and_filter_query
|
|
119
|
+
|
|
120
|
+
if i == len(or_list) - 1:
|
|
121
|
+
created_at_filter += ')'
|
|
122
|
+
else:
|
|
123
|
+
created_at_filter += ' OR '
|
|
124
|
+
|
|
125
|
+
filter_query += created_at_filter
|
|
126
|
+
|
|
127
|
+
if filters.expired_at is not None:
|
|
128
|
+
expired_at_filter = 'AND ('
|
|
129
|
+
for i, or_list in enumerate(filters.expired_at):
|
|
130
|
+
for j, date_filter in enumerate(or_list):
|
|
131
|
+
filter_params['expired_at_' + str(j)] = date_filter.date
|
|
132
|
+
|
|
133
|
+
and_filters = [
|
|
134
|
+
'(r.expired_at ' + date_filter.comparison_operator.value + f' $expired_at_{j})'
|
|
135
|
+
for j, date_filter in enumerate(or_list)
|
|
136
|
+
]
|
|
137
|
+
and_filter_query = ''
|
|
138
|
+
for j, and_filter in enumerate(and_filters):
|
|
139
|
+
and_filter_query += and_filter
|
|
140
|
+
if j != len(and_filter_query) - 1:
|
|
141
|
+
and_filter_query += ' AND '
|
|
142
|
+
|
|
143
|
+
expired_at_filter += and_filter_query
|
|
144
|
+
|
|
145
|
+
if i == len(or_list) - 1:
|
|
146
|
+
expired_at_filter += ')'
|
|
147
|
+
else:
|
|
148
|
+
expired_at_filter += ' OR '
|
|
149
|
+
|
|
150
|
+
filter_query += expired_at_filter
|
|
151
|
+
|
|
152
|
+
return filter_query, filter_params
|
|
@@ -38,6 +38,7 @@ from graphiti_core.nodes import (
|
|
|
38
38
|
get_community_node_from_record,
|
|
39
39
|
get_entity_node_from_record,
|
|
40
40
|
)
|
|
41
|
+
from graphiti_core.search.search_filters import SearchFilters, search_filter_query_constructor
|
|
41
42
|
|
|
42
43
|
logger = logging.getLogger(__name__)
|
|
43
44
|
|
|
@@ -136,6 +137,7 @@ async def get_communities_by_nodes(
|
|
|
136
137
|
async def edge_fulltext_search(
|
|
137
138
|
driver: AsyncDriver,
|
|
138
139
|
query: str,
|
|
140
|
+
search_filter: SearchFilters,
|
|
139
141
|
group_ids: list[str] | None = None,
|
|
140
142
|
limit=RELEVANT_SCHEMA_LIMIT,
|
|
141
143
|
) -> list[EntityEdge]:
|
|
@@ -144,28 +146,36 @@ async def edge_fulltext_search(
|
|
|
144
146
|
if fuzzy_query == '':
|
|
145
147
|
return []
|
|
146
148
|
|
|
147
|
-
|
|
149
|
+
filter_query, filter_params = search_filter_query_constructor(search_filter)
|
|
150
|
+
|
|
151
|
+
cypher_query = Query(
|
|
152
|
+
"""
|
|
148
153
|
CALL db.index.fulltext.queryRelationships("edge_name_and_fact", $query, {limit: $limit})
|
|
149
|
-
YIELD relationship AS
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
154
|
+
YIELD relationship AS rel, score
|
|
155
|
+
MATCH (:ENTITY)-[r:RELATES_TO]->(:ENTITY)
|
|
156
|
+
WHERE r.group_id IN $group_ids"""
|
|
157
|
+
+ filter_query
|
|
158
|
+
+ """\nWITH r, score, startNode(r) AS n, endNode(r) AS m
|
|
159
|
+
RETURN
|
|
160
|
+
r.uuid AS uuid,
|
|
161
|
+
r.group_id AS group_id,
|
|
162
|
+
n.uuid AS source_node_uuid,
|
|
163
|
+
m.uuid AS target_node_uuid,
|
|
164
|
+
r.created_at AS created_at,
|
|
165
|
+
r.name AS name,
|
|
166
|
+
r.fact AS fact,
|
|
167
|
+
r.fact_embedding AS fact_embedding,
|
|
168
|
+
r.episodes AS episodes,
|
|
169
|
+
r.expired_at AS expired_at,
|
|
170
|
+
r.valid_at AS valid_at,
|
|
171
|
+
r.invalid_at AS invalid_at
|
|
172
|
+
ORDER BY score DESC LIMIT $limit
|
|
173
|
+
"""
|
|
174
|
+
)
|
|
166
175
|
|
|
167
176
|
records, _, _ = await driver.execute_query(
|
|
168
177
|
cypher_query,
|
|
178
|
+
filter_params,
|
|
169
179
|
query=fuzzy_query,
|
|
170
180
|
group_ids=group_ids,
|
|
171
181
|
limit=limit,
|
|
@@ -183,6 +193,7 @@ async def edge_similarity_search(
|
|
|
183
193
|
search_vector: list[float],
|
|
184
194
|
source_node_uuid: str | None,
|
|
185
195
|
target_node_uuid: str | None,
|
|
196
|
+
search_filter: SearchFilters,
|
|
186
197
|
group_ids: list[str] | None = None,
|
|
187
198
|
limit: int = RELEVANT_SCHEMA_LIMIT,
|
|
188
199
|
min_score: float = DEFAULT_MIN_SCORE,
|
|
@@ -194,6 +205,9 @@ async def edge_similarity_search(
|
|
|
194
205
|
|
|
195
206
|
query_params: dict[str, Any] = {}
|
|
196
207
|
|
|
208
|
+
filter_query, filter_params = search_filter_query_constructor(search_filter)
|
|
209
|
+
query_params.update(filter_params)
|
|
210
|
+
|
|
197
211
|
group_filter_query: LiteralString = ''
|
|
198
212
|
if group_ids is not None:
|
|
199
213
|
group_filter_query += 'WHERE r.group_id IN $group_ids'
|
|
@@ -209,9 +223,10 @@ async def edge_similarity_search(
|
|
|
209
223
|
|
|
210
224
|
query: LiteralString = (
|
|
211
225
|
"""
|
|
212
|
-
|
|
213
|
-
|
|
226
|
+
MATCH (n:Entity)-[r:RELATES_TO]->(m:Entity)
|
|
227
|
+
"""
|
|
214
228
|
+ group_filter_query
|
|
229
|
+
+ filter_query
|
|
215
230
|
+ """\nWITH DISTINCT r, vector.similarity.cosine(r.fact_embedding, $search_vector) AS score
|
|
216
231
|
WHERE score > $min_score
|
|
217
232
|
RETURN
|
|
@@ -254,17 +269,25 @@ async def edge_bfs_search(
|
|
|
254
269
|
driver: AsyncDriver,
|
|
255
270
|
bfs_origin_node_uuids: list[str] | None,
|
|
256
271
|
bfs_max_depth: int,
|
|
272
|
+
search_filter: SearchFilters,
|
|
257
273
|
limit: int,
|
|
258
274
|
) -> list[EntityEdge]:
|
|
259
275
|
# vector similarity search over embedded facts
|
|
260
276
|
if bfs_origin_node_uuids is None:
|
|
261
277
|
return []
|
|
262
278
|
|
|
263
|
-
|
|
279
|
+
filter_query, filter_params = search_filter_query_constructor(search_filter)
|
|
280
|
+
|
|
281
|
+
query = Query(
|
|
282
|
+
"""
|
|
264
283
|
UNWIND $bfs_origin_node_uuids AS origin_uuid
|
|
265
284
|
MATCH path = (origin:Entity|Episodic {uuid: origin_uuid})-[:RELATES_TO|MENTIONS]->{1,3}(n:Entity)
|
|
266
285
|
UNWIND relationships(path) AS rel
|
|
267
|
-
MATCH ()-[r:RELATES_TO
|
|
286
|
+
MATCH ()-[r:RELATES_TO]-()
|
|
287
|
+
WHERE r.uuid = rel.uuid
|
|
288
|
+
"""
|
|
289
|
+
+ filter_query
|
|
290
|
+
+ """
|
|
268
291
|
RETURN DISTINCT
|
|
269
292
|
r.uuid AS uuid,
|
|
270
293
|
r.group_id AS group_id,
|
|
@@ -279,10 +302,12 @@ async def edge_bfs_search(
|
|
|
279
302
|
r.valid_at AS valid_at,
|
|
280
303
|
r.invalid_at AS invalid_at
|
|
281
304
|
LIMIT $limit
|
|
282
|
-
"""
|
|
305
|
+
"""
|
|
306
|
+
)
|
|
283
307
|
|
|
284
308
|
records, _, _ = await driver.execute_query(
|
|
285
309
|
query,
|
|
310
|
+
filter_params,
|
|
286
311
|
bfs_origin_node_uuids=bfs_origin_node_uuids,
|
|
287
312
|
depth=bfs_max_depth,
|
|
288
313
|
limit=limit,
|
|
@@ -626,6 +651,7 @@ async def get_relevant_edges(
|
|
|
626
651
|
edge.fact_embedding,
|
|
627
652
|
source_node_uuid,
|
|
628
653
|
target_node_uuid,
|
|
654
|
+
SearchFilters(),
|
|
629
655
|
[edge.group_id],
|
|
630
656
|
limit,
|
|
631
657
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/cross_encoder/bge_reranker_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/cross_encoder/openai_reranker_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/llm_client/openai_generic_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/community_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/edge_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/graph_data_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/node_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.5.2 → graphiti_core-0.5.3}/graphiti_core/utils/maintenance/temporal_operations.py
RENAMED
|
File without changes
|
|
File without changes
|