graphiti-core 0.20.1__py3-none-any.whl → 0.20.3__py3-none-any.whl

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/graphiti.py CHANGED
@@ -89,7 +89,6 @@ from graphiti_core.utils.maintenance.edge_operations import (
89
89
  )
90
90
  from graphiti_core.utils.maintenance.graph_data_operations import (
91
91
  EPISODE_WINDOW_LEN,
92
- build_dynamic_indexes,
93
92
  build_indices_and_constraints,
94
93
  retrieve_episodes,
95
94
  )
@@ -114,6 +113,15 @@ class AddEpisodeResults(BaseModel):
114
113
  community_edges: list[CommunityEdge]
115
114
 
116
115
 
116
+ class AddBulkEpisodeResults(BaseModel):
117
+ episodes: list[EpisodicNode]
118
+ episodic_edges: list[EpisodicEdge]
119
+ nodes: list[EntityNode]
120
+ edges: list[EntityEdge]
121
+ communities: list[CommunityNode]
122
+ community_edges: list[CommunityEdge]
123
+
124
+
117
125
  class Graphiti:
118
126
  def __init__(
119
127
  self,
@@ -451,7 +459,6 @@ class Graphiti:
451
459
 
452
460
  validate_excluded_entity_types(excluded_entity_types, entity_types)
453
461
  validate_group_id(group_id)
454
- await build_dynamic_indexes(self.driver, group_id)
455
462
 
456
463
  previous_episodes = (
457
464
  await self.retrieve_episodes(
@@ -574,7 +581,6 @@ class Graphiti:
574
581
  except Exception as e:
575
582
  raise e
576
583
 
577
- ##### EXPERIMENTAL #####
578
584
  async def add_episode_bulk(
579
585
  self,
580
586
  bulk_episodes: list[RawEpisode],
@@ -583,7 +589,7 @@ class Graphiti:
583
589
  excluded_entity_types: list[str] | None = None,
584
590
  edge_types: dict[str, type[BaseModel]] | None = None,
585
591
  edge_type_map: dict[tuple[str, str], list[str]] | None = None,
586
- ):
592
+ ) -> AddBulkEpisodeResults:
587
593
  """
588
594
  Process multiple episodes in bulk and update the graph.
589
595
 
@@ -599,7 +605,7 @@ class Graphiti:
599
605
 
600
606
  Returns
601
607
  -------
602
- None
608
+ AddBulkEpisodeResults
603
609
 
604
610
  Notes
605
611
  -----
@@ -851,6 +857,15 @@ class Graphiti:
851
857
  end = time()
852
858
  logger.info(f'Completed add_episode_bulk in {(end - start) * 1000} ms')
853
859
 
860
+ return AddBulkEpisodeResults(
861
+ episodes=episodes,
862
+ episodic_edges=resolved_episodic_edges,
863
+ nodes=final_hydrated_nodes,
864
+ edges=resolved_edges + invalidated_edges,
865
+ communities=[],
866
+ community_edges=[],
867
+ )
868
+
854
869
  except Exception as e:
855
870
  raise e
856
871
 
@@ -52,7 +52,6 @@ def get_episode_node_save_query(provider: GraphProvider) -> str:
52
52
  case _: # Neo4j
53
53
  return """
54
54
  MERGE (n:Episodic {uuid: $uuid})
55
- SET n:$($group_label)
56
55
  SET n = {uuid: $uuid, name: $name, group_id: $group_id, source_description: $source_description, source: $source, content: $content,
57
56
  entity_edges: $entity_edges, created_at: $created_at, valid_at: $valid_at}
58
57
  RETURN n.uuid AS uuid
@@ -96,7 +95,6 @@ def get_episode_node_save_bulk_query(provider: GraphProvider) -> str:
96
95
  return """
97
96
  UNWIND $episodes AS episode
98
97
  MERGE (n:Episodic {uuid: episode.uuid})
99
- SET n:$(episode.group_label)
100
98
  SET n = {uuid: episode.uuid, name: episode.name, group_id: episode.group_id, source_description: episode.source_description, source: episode.source, content: episode.content,
101
99
  entity_edges: episode.entity_edges, created_at: episode.created_at, valid_at: episode.valid_at}
102
100
  RETURN n.uuid AS uuid
graphiti_core/nodes.py CHANGED
@@ -299,9 +299,6 @@ class EpisodicNode(Node):
299
299
  'source': self.source.value,
300
300
  }
301
301
 
302
- if driver.provider == GraphProvider.NEO4J:
303
- episode_args['group_label'] = 'Episodic_' + self.group_id.replace('-', '')
304
-
305
302
  result = await driver.execute_query(
306
303
  get_episode_node_save_query(driver.provider), **episode_args
307
304
  )
@@ -471,7 +468,7 @@ class EntityNode(Node):
471
468
  )
472
469
  else:
473
470
  entity_data.update(self.attributes or {})
474
- labels = ':'.join(self.labels + ['Entity', 'Entity_' + self.group_id.replace('-', '')])
471
+ labels = ':'.join(self.labels + ['Entity'])
475
472
 
476
473
  if driver.provider == GraphProvider.NEPTUNE:
477
474
  driver.save_to_aoss('node_name_and_summary', [entity_data]) # pyright: ignore reportAttributeAccessIssue
@@ -325,9 +325,7 @@ async def node_search(
325
325
  search_tasks = []
326
326
  if NodeSearchMethod.bm25 in config.search_methods:
327
327
  search_tasks.append(
328
- node_fulltext_search(
329
- driver, query, search_filter, group_ids, 2 * limit, config.use_local_indexes
330
- )
328
+ node_fulltext_search(driver, query, search_filter, group_ids, 2 * limit)
331
329
  )
332
330
  if NodeSearchMethod.cosine_similarity in config.search_methods:
333
331
  search_tasks.append(
@@ -338,7 +336,6 @@ async def node_search(
338
336
  group_ids,
339
337
  2 * limit,
340
338
  config.sim_min_score,
341
- config.use_local_indexes,
342
339
  )
343
340
  )
344
341
  if NodeSearchMethod.bfs in config.search_methods:
@@ -434,9 +431,7 @@ async def episode_search(
434
431
  search_results: list[list[EpisodicNode]] = list(
435
432
  await semaphore_gather(
436
433
  *[
437
- episode_fulltext_search(
438
- driver, query, search_filter, group_ids, 2 * limit, config.use_local_indexes
439
- ),
434
+ episode_fulltext_search(driver, query, search_filter, group_ids, 2 * limit),
440
435
  ]
441
436
  )
442
437
  )
@@ -24,7 +24,6 @@ from graphiti_core.search.search_utils import (
24
24
  DEFAULT_MIN_SCORE,
25
25
  DEFAULT_MMR_LAMBDA,
26
26
  MAX_SEARCH_DEPTH,
27
- USE_HNSW,
28
27
  )
29
28
 
30
29
  DEFAULT_SEARCH_LIMIT = 10
@@ -92,7 +91,6 @@ class NodeSearchConfig(BaseModel):
92
91
  sim_min_score: float = Field(default=DEFAULT_MIN_SCORE)
93
92
  mmr_lambda: float = Field(default=DEFAULT_MMR_LAMBDA)
94
93
  bfs_max_depth: int = Field(default=MAX_SEARCH_DEPTH)
95
- use_local_indexes: bool = Field(default=USE_HNSW)
96
94
 
97
95
 
98
96
  class EpisodeSearchConfig(BaseModel):
@@ -101,7 +99,6 @@ class EpisodeSearchConfig(BaseModel):
101
99
  sim_min_score: float = Field(default=DEFAULT_MIN_SCORE)
102
100
  mmr_lambda: float = Field(default=DEFAULT_MMR_LAMBDA)
103
101
  bfs_max_depth: int = Field(default=MAX_SEARCH_DEPTH)
104
- use_local_indexes: bool = Field(default=USE_HNSW)
105
102
 
106
103
 
107
104
  class CommunitySearchConfig(BaseModel):
@@ -110,7 +107,6 @@ class CommunitySearchConfig(BaseModel):
110
107
  sim_min_score: float = Field(default=DEFAULT_MIN_SCORE)
111
108
  mmr_lambda: float = Field(default=DEFAULT_MMR_LAMBDA)
112
109
  bfs_max_depth: int = Field(default=MAX_SEARCH_DEPTH)
113
- use_local_indexes: bool = Field(default=USE_HNSW)
114
110
 
115
111
 
116
112
  class SearchConfig(BaseModel):
@@ -15,7 +15,6 @@ limitations under the License.
15
15
  """
16
16
 
17
17
  import logging
18
- import os
19
18
  from collections import defaultdict
20
19
  from time import time
21
20
  from typing import Any
@@ -57,7 +56,6 @@ from graphiti_core.search.search_filters import (
57
56
  )
58
57
 
59
58
  logger = logging.getLogger(__name__)
60
- USE_HNSW = os.getenv('USE_HNSW', '').lower() in ('true', '1', 'yes')
61
59
 
62
60
  RELEVANT_SCHEMA_LIMIT = 10
63
61
  DEFAULT_MIN_SCORE = 0.6
@@ -210,11 +208,11 @@ async def edge_fulltext_search(
210
208
  # Match the edge ids and return the values
211
209
  query = (
212
210
  """
213
- UNWIND $ids as id
214
- MATCH (n:Entity)-[e:RELATES_TO]->(m:Entity)
215
- WHERE e.group_id IN $group_ids
216
- AND id(e)=id
217
- """
211
+ UNWIND $ids as id
212
+ MATCH (n:Entity)-[e:RELATES_TO]->(m:Entity)
213
+ WHERE e.group_id IN $group_ids
214
+ AND id(e)=id
215
+ """
218
216
  + filter_query
219
217
  + """
220
218
  AND id(e)=id
@@ -320,8 +318,8 @@ async def edge_similarity_search(
320
318
  if driver.provider == GraphProvider.NEPTUNE:
321
319
  query = (
322
320
  """
323
- MATCH (n:Entity)-[e:RELATES_TO]->(m:Entity)
324
- """
321
+ MATCH (n:Entity)-[e:RELATES_TO]->(m:Entity)
322
+ """
325
323
  + filter_query
326
324
  + """
327
325
  RETURN DISTINCT id(e) as id, e.fact_embedding as embedding
@@ -540,7 +538,6 @@ async def node_fulltext_search(
540
538
  search_filter: SearchFilters,
541
539
  group_ids: list[str] | None = None,
542
540
  limit=RELEVANT_SCHEMA_LIMIT,
543
- use_local_indexes: bool = False,
544
541
  ) -> list[EntityNode]:
545
542
  # BM25 search to get top nodes
546
543
  fuzzy_query = fulltext_query(query, group_ids, driver)
@@ -574,11 +571,11 @@ async def node_fulltext_search(
574
571
  # Match the edge ides and return the values
575
572
  query = (
576
573
  """
577
- UNWIND $ids as i
578
- MATCH (n:Entity)
579
- WHERE n.uuid=i.id
580
- RETURN
581
- """
574
+ UNWIND $ids as i
575
+ MATCH (n:Entity)
576
+ WHERE n.uuid=i.id
577
+ RETURN
578
+ """
582
579
  + get_entity_node_return_query(driver.provider)
583
580
  + """
584
581
  ORDER BY i.score DESC
@@ -596,14 +593,10 @@ async def node_fulltext_search(
596
593
  else:
597
594
  return []
598
595
  else:
599
- index_name = (
600
- 'node_name_and_summary'
601
- if not use_local_indexes
602
- else 'node_name_and_summary_'
603
- + (group_ids[0].replace('-', '') if group_ids is not None else '')
604
- )
605
596
  query = (
606
- get_nodes_query(index_name, '$query', limit=limit, provider=driver.provider)
597
+ get_nodes_query(
598
+ 'node_name_and_summary', '$query', limit=limit, provider=driver.provider
599
+ )
607
600
  + yield_query
608
601
  + filter_query
609
602
  + """
@@ -635,7 +628,6 @@ async def node_similarity_search(
635
628
  group_ids: list[str] | None = None,
636
629
  limit=RELEVANT_SCHEMA_LIMIT,
637
630
  min_score: float = DEFAULT_MIN_SCORE,
638
- use_local_indexes: bool = False,
639
631
  ) -> list[EntityNode]:
640
632
  filter_queries, filter_params = node_search_filter_query_constructor(
641
633
  search_filter, driver.provider
@@ -656,8 +648,8 @@ async def node_similarity_search(
656
648
  if driver.provider == GraphProvider.NEPTUNE:
657
649
  query = (
658
650
  """
659
- MATCH (n:Entity)
660
- """
651
+ MATCH (n:Entity)
652
+ """
661
653
  + filter_query
662
654
  + """
663
655
  RETURN DISTINCT id(n) as id, n.name_embedding as embedding
@@ -686,11 +678,11 @@ async def node_similarity_search(
686
678
  # Match the edge ides and return the values
687
679
  query = (
688
680
  """
689
- UNWIND $ids as i
690
- MATCH (n:Entity)
691
- WHERE id(n)=i.id
692
- RETURN
693
- """
681
+ UNWIND $ids as i
682
+ MATCH (n:Entity)
683
+ WHERE id(n)=i.id
684
+ RETURN
685
+ """
694
686
  + get_entity_node_return_query(driver.provider)
695
687
  + """
696
688
  ORDER BY i.score DESC
@@ -708,40 +700,11 @@ async def node_similarity_search(
708
700
  )
709
701
  else:
710
702
  return []
711
- elif driver.provider == GraphProvider.NEO4J and use_local_indexes:
712
- index_name = 'group_entity_vector_' + (
713
- group_ids[0].replace('-', '') if group_ids is not None else ''
714
- )
715
- query = (
716
- f"""
717
- CALL db.index.vector.queryNodes('{index_name}', {limit}, $search_vector) YIELD node AS n, score
718
- """
719
- + filter_query
720
- + """
721
- AND score > $min_score
722
- RETURN
723
- """
724
- + get_entity_node_return_query(driver.provider)
725
- + """
726
- ORDER BY score DESC
727
- LIMIT $limit
728
- """
729
- )
730
-
731
- records, _, _ = await driver.execute_query(
732
- query,
733
- search_vector=search_vector,
734
- limit=limit,
735
- min_score=min_score,
736
- routing_='r',
737
- **filter_params,
738
- )
739
-
740
703
  else:
741
704
  query = (
742
705
  """
743
- MATCH (n:Entity)
744
- """
706
+ MATCH (n:Entity)
707
+ """
745
708
  + filter_query
746
709
  + """
747
710
  WITH n, """
@@ -865,7 +828,6 @@ async def episode_fulltext_search(
865
828
  _search_filter: SearchFilters,
866
829
  group_ids: list[str] | None = None,
867
830
  limit=RELEVANT_SCHEMA_LIMIT,
868
- use_local_indexes: bool = False,
869
831
  ) -> list[EpisodicNode]:
870
832
  # BM25 search to get top episodes
871
833
  fuzzy_query = fulltext_query(query, group_ids, driver)
@@ -915,14 +877,8 @@ async def episode_fulltext_search(
915
877
  else:
916
878
  return []
917
879
  else:
918
- index_name = (
919
- 'episode_content'
920
- if not use_local_indexes
921
- else 'episode_content_'
922
- + (group_ids[0].replace('-', '') if group_ids is not None else '')
923
- )
924
880
  query = (
925
- get_nodes_query(index_name, '$query', limit=limit, provider=driver.provider)
881
+ get_nodes_query('episode_content', '$query', limit=limit, provider=driver.provider)
926
882
  + """
927
883
  YIELD node AS episode, score
928
884
  MATCH (e:Episodic)
@@ -1047,8 +1003,8 @@ async def community_similarity_search(
1047
1003
  if driver.provider == GraphProvider.NEPTUNE:
1048
1004
  query = (
1049
1005
  """
1050
- MATCH (n:Community)
1051
- """
1006
+ MATCH (n:Community)
1007
+ """
1052
1008
  + group_filter_query
1053
1009
  + """
1054
1010
  RETURN DISTINCT id(n) as id, n.name_embedding as embedding
@@ -1107,8 +1063,8 @@ async def community_similarity_search(
1107
1063
 
1108
1064
  query = (
1109
1065
  """
1110
- MATCH (c:Community)
1111
- """
1066
+ MATCH (c:Community)
1067
+ """
1112
1068
  + group_filter_query
1113
1069
  + """
1114
1070
  WITH c,
@@ -1250,9 +1206,9 @@ async def get_relevant_nodes(
1250
1206
  # FIXME: Kuzu currently does not support using variables such as `node.fulltext_query` as an input to FTS, which means `get_relevant_nodes()` won't work with Kuzu as the graph driver.
1251
1207
  query = (
1252
1208
  """
1253
- UNWIND $nodes AS node
1254
- MATCH (n:Entity {group_id: $group_id})
1255
- """
1209
+ UNWIND $nodes AS node
1210
+ MATCH (n:Entity {group_id: $group_id})
1211
+ """
1256
1212
  + filter_query
1257
1213
  + """
1258
1214
  WITH node, n, """
@@ -1297,9 +1253,9 @@ async def get_relevant_nodes(
1297
1253
  else:
1298
1254
  query = (
1299
1255
  """
1300
- UNWIND $nodes AS node
1301
- MATCH (n:Entity {group_id: $group_id})
1302
- """
1256
+ UNWIND $nodes AS node
1257
+ MATCH (n:Entity {group_id: $group_id})
1258
+ """
1303
1259
  + filter_query
1304
1260
  + """
1305
1261
  WITH node, n, """
@@ -1388,9 +1344,9 @@ async def get_relevant_edges(
1388
1344
  if driver.provider == GraphProvider.NEPTUNE:
1389
1345
  query = (
1390
1346
  """
1391
- UNWIND $edges AS edge
1392
- MATCH (n:Entity {uuid: edge.source_node_uuid})-[e:RELATES_TO {group_id: edge.group_id}]-(m:Entity {uuid: edge.target_node_uuid})
1393
- """
1347
+ UNWIND $edges AS edge
1348
+ MATCH (n:Entity {uuid: edge.source_node_uuid})-[e:RELATES_TO {group_id: edge.group_id}]-(m:Entity {uuid: edge.target_node_uuid})
1349
+ """
1394
1350
  + filter_query
1395
1351
  + """
1396
1352
  WITH e, edge
@@ -1460,9 +1416,9 @@ async def get_relevant_edges(
1460
1416
 
1461
1417
  query = (
1462
1418
  """
1463
- UNWIND $edges AS edge
1464
- MATCH (n:Entity {uuid: edge.source_node_uuid})-[:RELATES_TO]-(e:RelatesToNode_ {group_id: edge.group_id})-[:RELATES_TO]-(m:Entity {uuid: edge.target_node_uuid})
1465
- """
1419
+ UNWIND $edges AS edge
1420
+ MATCH (n:Entity {uuid: edge.source_node_uuid})-[:RELATES_TO]-(e:RelatesToNode_ {group_id: edge.group_id})-[:RELATES_TO]-(m:Entity {uuid: edge.target_node_uuid})
1421
+ """
1466
1422
  + filter_query
1467
1423
  + """
1468
1424
  WITH e, edge, n, m, """
@@ -1498,9 +1454,9 @@ async def get_relevant_edges(
1498
1454
  else:
1499
1455
  query = (
1500
1456
  """
1501
- UNWIND $edges AS edge
1502
- MATCH (n:Entity {uuid: edge.source_node_uuid})-[e:RELATES_TO {group_id: edge.group_id}]-(m:Entity {uuid: edge.target_node_uuid})
1503
- """
1457
+ UNWIND $edges AS edge
1458
+ MATCH (n:Entity {uuid: edge.source_node_uuid})-[e:RELATES_TO {group_id: edge.group_id}]-(m:Entity {uuid: edge.target_node_uuid})
1459
+ """
1504
1460
  + filter_query
1505
1461
  + """
1506
1462
  WITH e, edge, """
@@ -1573,10 +1529,10 @@ async def get_edge_invalidation_candidates(
1573
1529
  if driver.provider == GraphProvider.NEPTUNE:
1574
1530
  query = (
1575
1531
  """
1576
- UNWIND $edges AS edge
1577
- MATCH (n:Entity)-[e:RELATES_TO {group_id: edge.group_id}]->(m:Entity)
1578
- WHERE n.uuid IN [edge.source_node_uuid, edge.target_node_uuid] OR m.uuid IN [edge.target_node_uuid, edge.source_node_uuid]
1579
- """
1532
+ UNWIND $edges AS edge
1533
+ MATCH (n:Entity)-[e:RELATES_TO {group_id: edge.group_id}]->(m:Entity)
1534
+ WHERE n.uuid IN [edge.source_node_uuid, edge.target_node_uuid] OR m.uuid IN [edge.target_node_uuid, edge.source_node_uuid]
1535
+ """
1580
1536
  + filter_query
1581
1537
  + """
1582
1538
  WITH e, edge
@@ -1646,10 +1602,10 @@ async def get_edge_invalidation_candidates(
1646
1602
 
1647
1603
  query = (
1648
1604
  """
1649
- UNWIND $edges AS edge
1650
- MATCH (n:Entity)-[:RELATES_TO]->(e:RelatesToNode_ {group_id: edge.group_id})-[:RELATES_TO]->(m:Entity)
1651
- WHERE (n.uuid IN [edge.source_node_uuid, edge.target_node_uuid] OR m.uuid IN [edge.target_node_uuid, edge.source_node_uuid])
1652
- """
1605
+ UNWIND $edges AS edge
1606
+ MATCH (n:Entity)-[:RELATES_TO]->(e:RelatesToNode_ {group_id: edge.group_id})-[:RELATES_TO]->(m:Entity)
1607
+ WHERE (n.uuid IN [edge.source_node_uuid, edge.target_node_uuid] OR m.uuid IN [edge.target_node_uuid, edge.source_node_uuid])
1608
+ """
1653
1609
  + filter_query
1654
1610
  + """
1655
1611
  WITH edge, e, n, m, """
@@ -1685,10 +1641,10 @@ async def get_edge_invalidation_candidates(
1685
1641
  else:
1686
1642
  query = (
1687
1643
  """
1688
- UNWIND $edges AS edge
1689
- MATCH (n:Entity)-[e:RELATES_TO {group_id: edge.group_id}]->(m:Entity)
1690
- WHERE n.uuid IN [edge.source_node_uuid, edge.target_node_uuid] OR m.uuid IN [edge.target_node_uuid, edge.source_node_uuid]
1691
- """
1644
+ UNWIND $edges AS edge
1645
+ MATCH (n:Entity)-[e:RELATES_TO {group_id: edge.group_id}]->(m:Entity)
1646
+ WHERE n.uuid IN [edge.source_node_uuid, edge.target_node_uuid] OR m.uuid IN [edge.target_node_uuid, edge.source_node_uuid]
1647
+ """
1692
1648
  + filter_query
1693
1649
  + """
1694
1650
  WITH edge, e, """
@@ -119,8 +119,6 @@ async def add_nodes_and_edges_bulk_tx(
119
119
  for episode in episodes:
120
120
  episode['source'] = str(episode['source'].value)
121
121
  episode.pop('labels', None)
122
- if driver.provider == GraphProvider.NEO4J:
123
- episode['group_label'] = 'Episodic_' + episode['group_id'].replace('-', '')
124
122
 
125
123
  nodes = []
126
124
 
@@ -143,9 +141,6 @@ async def add_nodes_and_edges_bulk_tx(
143
141
  entity_data['attributes'] = json.dumps(attributes)
144
142
  else:
145
143
  entity_data.update(node.attributes or {})
146
- entity_data['labels'] = list(
147
- set(node.labels + ['Entity', 'Entity_' + node.group_id.replace('-', '')])
148
- )
149
144
 
150
145
  nodes.append(entity_data)
151
146
 
@@ -149,9 +149,9 @@ async def retrieve_episodes(
149
149
 
150
150
  query: LiteralString = (
151
151
  """
152
- MATCH (e:Episodic)
153
- WHERE e.valid_at <= $reference_time
154
- """
152
+ MATCH (e:Episodic)
153
+ WHERE e.valid_at <= $reference_time
154
+ """
155
155
  + query_filter
156
156
  + """
157
157
  RETURN
@@ -175,44 +175,3 @@ async def retrieve_episodes(
175
175
 
176
176
  episodes = [get_episodic_node_from_record(record) for record in result]
177
177
  return list(reversed(episodes)) # Return in chronological order
178
-
179
-
180
- async def build_dynamic_indexes(driver: GraphDriver, group_id: str):
181
- # Make sure indices exist for this group_id in Neo4j
182
- if driver.provider == GraphProvider.NEO4J:
183
- await driver.execute_query(
184
- """CREATE FULLTEXT INDEX $episode_content IF NOT EXISTS
185
- FOR (e:"""
186
- + 'Episodic_'
187
- + group_id.replace('-', '')
188
- + """) ON EACH [e.content, e.source, e.source_description, e.group_id]""",
189
- episode_content='episode_content_' + group_id.replace('-', ''),
190
- )
191
- await driver.execute_query(
192
- """CREATE FULLTEXT INDEX $node_name_and_summary IF NOT EXISTS FOR (n:"""
193
- + 'Entity_'
194
- + group_id.replace('-', '')
195
- + """) ON EACH [n.name, n.summary, n.group_id]""",
196
- node_name_and_summary='node_name_and_summary_' + group_id.replace('-', ''),
197
- )
198
- await driver.execute_query(
199
- """CREATE FULLTEXT INDEX $community_name IF NOT EXISTS
200
- FOR (n:"""
201
- + 'Community_'
202
- + group_id.replace('-', '')
203
- + """) ON EACH [n.name, n.group_id]""",
204
- community_name='Community_' + group_id.replace('-', ''),
205
- )
206
- await driver.execute_query(
207
- """CREATE VECTOR INDEX $group_entity_vector IF NOT EXISTS
208
- FOR (n:"""
209
- + 'Entity_'
210
- + group_id.replace('-', '')
211
- + """)
212
- ON n.embedding
213
- OPTIONS { indexConfig: {
214
- `vector.dimensions`: 1024,
215
- `vector.similarity_function`: 'cosine'
216
- }}""",
217
- group_entity_vector='group_entity_vector_' + group_id.replace('-', ''),
218
- )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphiti-core
3
- Version: 0.20.1
3
+ Version: 0.20.3
4
4
  Summary: A temporal graph building library
5
5
  Project-URL: Homepage, https://help.getzep.com/graphiti/graphiti/overview
6
6
  Project-URL: Repository, https://github.com/getzep/graphiti
@@ -2,10 +2,10 @@ graphiti_core/__init__.py,sha256=e5SWFkRiaUwfprYIeIgVIh7JDedNiloZvd3roU-0aDY,55
2
2
  graphiti_core/edges.py,sha256=O-WqtqR9w6ZO5nbi4VRveXVrinfTcZmDJ6PcjudDAsY,18821
3
3
  graphiti_core/errors.py,sha256=cH_v9TPgEPeQE6GFOHIg5TvejpUCBddGarMY2Whxbwc,2707
4
4
  graphiti_core/graph_queries.py,sha256=9DWMiFTB-OmodMDaOws0lwzgiD7EUDNO7mAFJ1nxusE,6624
5
- graphiti_core/graphiti.py,sha256=7c1xwZav1OdPqtEZ3lNlM_wqrQtZ1otdgRoFhaca4KY,40924
5
+ graphiti_core/graphiti.py,sha256=yLDI8l95DwNe6NtggwsqLKG92ShkIh3JAIXzNYOp2J8,41413
6
6
  graphiti_core/graphiti_types.py,sha256=C_p2XwScQlCzo7ets097TrSLs9ATxPZQ4WCsxDS7QHc,1066
7
7
  graphiti_core/helpers.py,sha256=6q_wpiOW3_j28EfZ7FgWW7Hl5pONj_5zvVXZGW9FxTU,5175
8
- graphiti_core/nodes.py,sha256=N1Qy-cv1CGyjXWgjT_EWl6M4IT0zWrm8uJK9PZShh9I,26582
8
+ graphiti_core/nodes.py,sha256=sJGCaEWroCL7rL7rUPqFw_NjTY-aNdc44fFOsvKZpdw,26399
9
9
  graphiti_core/py.typed,sha256=vlmmzQOt7bmeQl9L3XJP4W6Ry0iiELepnOrinKz5KQg,79
10
10
  graphiti_core/cross_encoder/__init__.py,sha256=hry59vz21x-AtGZ0MJ7ugw0HTwJkXiddpp_Yqnwsen0,723
11
11
  graphiti_core/cross_encoder/bge_reranker_client.py,sha256=y3TfFxZh0Yvj6HUShmfUm6MC7OPXwWUlv1Qe5HF3S3I,1797
@@ -37,12 +37,11 @@ graphiti_core/llm_client/openai_client.py,sha256=AuaCFQFMJEGzBkFVouccq3XentmWRIK
37
37
  graphiti_core/llm_client/openai_generic_client.py,sha256=WElMnPqdb1CxzYH4p2-m_9rVMr5M93-eXnc3yVxBgFg,7001
38
38
  graphiti_core/llm_client/utils.py,sha256=zKpxXEbKa369m4W7RDEf-m56kH46V1Mx3RowcWZEWWs,1000
39
39
  graphiti_core/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
- graphiti_core/migrations/neo4j_node_group_labels.py,sha256=5RHs4Y_losWh5WaK-f5AqhPlTquoB2e6xdLiktIjInE,3759
41
40
  graphiti_core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
41
  graphiti_core/models/edges/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
42
  graphiti_core/models/edges/edge_db_queries.py,sha256=s6NwbiaZwcvMJjyOtfw4KmtFHqckOaXMrUluONmkS3w,10442
44
43
  graphiti_core/models/nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- graphiti_core/models/nodes/node_db_queries.py,sha256=6VoBx6t6FGzfhjhrNB9UImYchAAuFDPOFpbZkvMCCUo,12391
44
+ graphiti_core/models/nodes/node_db_queries.py,sha256=c5wyAxChbqRaTf_v8Ffqts61yZYyLSTxm78U_eSvRYk,12308
46
45
  graphiti_core/prompts/__init__.py,sha256=EA-x9xUki9l8wnu2l8ek_oNf75-do5tq5hVq7Zbv8Kw,101
47
46
  graphiti_core/prompts/dedupe_edges.py,sha256=WRXQi7JQZdIfKDICWyU7Wbs5WyD_KBblLBSeKdbLyuk,5914
48
47
  graphiti_core/prompts/dedupe_nodes.py,sha256=eYDk0axHEKLjZS2tKlT4Zy1fW9EJkn6EnrJLSN0fvAY,8235
@@ -56,26 +55,26 @@ graphiti_core/prompts/models.py,sha256=NgxdbPHJpBEcpbXovKyScgpBc73Q-GIW-CBDlBtDj
56
55
  graphiti_core/prompts/prompt_helpers.py,sha256=gMDDNqBpxcnTO9psJQm7QU7M6OQgRumFq4oGYiycrfM,795
57
56
  graphiti_core/prompts/summarize_nodes.py,sha256=tn6LPEv_nNFLjKuT_FB_st7TAIYOEUOg9QR5YG7PpMA,4437
58
57
  graphiti_core/search/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- graphiti_core/search/search.py,sha256=Lm3tRrz5JuaJF3-_yYRy5UbcHDuUq-H3PNr-g023paA,18549
60
- graphiti_core/search/search_config.py,sha256=ju6m5iET3CYdoMK4RNiVA7CQge0qm7jG6mBtAR9FAmg,4341
58
+ graphiti_core/search/search.py,sha256=2kj7fybSFv6Fnf_cfEUhJhrpfzNtmkPPZ0hV3BQCDqg,18387
59
+ graphiti_core/search/search_config.py,sha256=v_rUHsu1yo5OuPfEm21lSuXexQs-o8qYwSSemW2QWhU,4165
61
60
  graphiti_core/search/search_config_recipes.py,sha256=4GquRphHhJlpXQhAZOySYnCzBWYoTwxlJj44eTOavZQ,7443
62
61
  graphiti_core/search/search_filters.py,sha256=adPBV51T5CVoOXMNFnVABByEwqX4QfS7t_pT1dDZyjg,8328
63
62
  graphiti_core/search/search_helpers.py,sha256=wj3ARlCNnZixNNntgCdAqzGoE4de4lW3r4rSG-3WyGw,2877
64
- graphiti_core/search/search_utils.py,sha256=mgsX2eZW2J8BvX0_ee1ilfkyGba-ymFWuVCg0D7jWks,67439
63
+ graphiti_core/search/search_utils.py,sha256=261Y1ZMcA3S5-sCPkfKuEHDjlA2zINhGCkJoCiXgcWI,66333
65
64
  graphiti_core/telemetry/__init__.py,sha256=5kALLDlU9bb2v19CdN7qVANsJWyfnL9E60J6FFgzm3o,226
66
65
  graphiti_core/telemetry/telemetry.py,sha256=47LrzOVBCcZxsYPsnSxWFiztHoxYKKxPwyRX0hnbDGc,3230
67
66
  graphiti_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
- graphiti_core/utils/bulk_utils.py,sha256=daHqAEjbOz0T2MBrBljnua8BSeUtxghCKV3S2OqWznU,16867
67
+ graphiti_core/utils/bulk_utils.py,sha256=cwkYeFuozoi-FWG_3cyoGLa5ctfOlmTl9Ig-4aWG3rU,16582
69
68
  graphiti_core/utils/datetime_utils.py,sha256=J-zYSq7-H-2n9hYOXNIun12kM10vNX9mMATGR_egTmY,1806
70
69
  graphiti_core/utils/maintenance/__init__.py,sha256=vW4H1KyapTl-OOz578uZABYcpND4wPx3Vt6aAPaXh78,301
71
70
  graphiti_core/utils/maintenance/community_operations.py,sha256=XMiokEemn96GlvjkOvbo9hIX04Fea3eVj408NHG5P4o,11042
72
71
  graphiti_core/utils/maintenance/edge_operations.py,sha256=yxL5rc8eZh0GyduF_Vn04cqdmQQtCFwrbXEuoNF6G6E,20242
73
- graphiti_core/utils/maintenance/graph_data_operations.py,sha256=t4nbYp78teMTYtwuON5niQDyEj8TI7_pbe9xYSulH_o,7756
72
+ graphiti_core/utils/maintenance/graph_data_operations.py,sha256=Uryz5g-Bao548_gmrbd27Ealk_5C9PgPe61YE-nLFb8,5899
74
73
  graphiti_core/utils/maintenance/node_operations.py,sha256=r9ilkA01eq1z-nF8P_s1EXG6A6j15qmnfIqetnzqF50,13644
75
74
  graphiti_core/utils/maintenance/temporal_operations.py,sha256=IIaVtShpVkOYe6haxz3a1x3v54-MzaEXG8VsxFUNeoY,3582
76
75
  graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
76
  graphiti_core/utils/ontology_utils/entity_types_utils.py,sha256=4eVgxLWY6Q8k9cRJ5pW59IYF--U4nXZsZIGOVb_yHfQ,1285
78
- graphiti_core-0.20.1.dist-info/METADATA,sha256=USbyOsCoNZzCt20hZuYHiw-yDp8de2w4TNQ21M2scwg,26773
79
- graphiti_core-0.20.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
- graphiti_core-0.20.1.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
81
- graphiti_core-0.20.1.dist-info/RECORD,,
77
+ graphiti_core-0.20.3.dist-info/METADATA,sha256=fDuytcZeJ0ypHOmoIgSBhUxsqleAKnz4Yf5AkBcmJEE,26773
78
+ graphiti_core-0.20.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
79
+ graphiti_core-0.20.3.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
80
+ graphiti_core-0.20.3.dist-info/RECORD,,
@@ -1,114 +0,0 @@
1
- import asyncio
2
- import csv
3
- import os
4
-
5
- from graphiti_core.driver.driver import GraphDriver
6
- from graphiti_core.driver.neo4j_driver import Neo4jDriver
7
- from graphiti_core.helpers import validate_group_id
8
- from graphiti_core.utils.maintenance.graph_data_operations import build_dynamic_indexes
9
-
10
-
11
- async def neo4j_node_group_labels(driver: GraphDriver, group_id: str, batch_size: int = 100):
12
- validate_group_id(group_id)
13
- await build_dynamic_indexes(driver, group_id)
14
-
15
- episode_query = """
16
- MATCH (n:Episodic {group_id: $group_id})
17
- CALL {
18
- WITH n
19
- SET n:$($group_label)
20
- } IN TRANSACTIONS OF $batch_size ROWS"""
21
-
22
- entity_query = """
23
- MATCH (n:Entity {group_id: $group_id})
24
- CALL {
25
- WITH n
26
- SET n:$($group_label)
27
- } IN TRANSACTIONS OF $batch_size ROWS"""
28
-
29
- community_query = """
30
- MATCH (n:Community {group_id: $group_id})
31
- CALL {
32
- WITH n
33
- SET n:$($group_label)
34
- } IN TRANSACTIONS OF $batch_size ROWS"""
35
-
36
- async with driver.session() as session:
37
- await session.run(
38
- episode_query,
39
- group_id=group_id,
40
- group_label='Episodic_' + group_id.replace('-', ''),
41
- batch_size=batch_size,
42
- )
43
-
44
- async with driver.session() as session:
45
- await session.run(
46
- entity_query,
47
- group_id=group_id,
48
- group_label='Entity_' + group_id.replace('-', ''),
49
- batch_size=batch_size,
50
- )
51
-
52
- async with driver.session() as session:
53
- await session.run(
54
- community_query,
55
- group_id=group_id,
56
- group_label='Community_' + group_id.replace('-', ''),
57
- batch_size=batch_size,
58
- )
59
-
60
-
61
- def pop_last_n_group_ids(csv_file: str = 'group_ids.csv', count: int = 10):
62
- with open(csv_file) as file:
63
- reader = csv.reader(file)
64
- group_ids = [row[0] for row in reader]
65
-
66
- total_count = len(group_ids)
67
- popped = group_ids[-count:]
68
- remaining = group_ids[:-count]
69
-
70
- with open(csv_file, 'w', newline='') as file:
71
- writer = csv.writer(file)
72
- for gid in remaining:
73
- writer.writerow([gid])
74
-
75
- return popped, total_count
76
-
77
-
78
- async def get_group_ids(driver: GraphDriver):
79
- query = """MATCH (n:Episodic)
80
- RETURN DISTINCT n.group_id AS group_id"""
81
-
82
- results, _, _ = await driver.execute_query(query)
83
- group_ids = [result['group_id'] for result in results]
84
-
85
- with open('group_ids.csv', 'w', newline='') as file:
86
- writer = csv.writer(file)
87
- for gid in group_ids:
88
- writer.writerow([gid])
89
-
90
-
91
- async def neo4j_node_label_migration(driver: GraphDriver, batch_size: int = 10):
92
- group_ids, total = pop_last_n_group_ids(csv_file='group_ids.csv', count=batch_size)
93
- while len(group_ids) > 0:
94
- await asyncio.gather(*[neo4j_node_group_labels(driver, group_id) for group_id in group_ids])
95
- group_ids, _ = pop_last_n_group_ids(csv_file='group_ids.csv', count=batch_size)
96
-
97
-
98
- async def main():
99
- neo4j_uri = os.environ.get('NEO4J_URI') or 'bolt://localhost:7687'
100
- neo4j_user = os.environ.get('NEO4J_USER') or 'neo4j'
101
- neo4j_password = os.environ.get('NEO4J_PASSWORD') or 'password'
102
-
103
- driver = Neo4jDriver(
104
- uri=neo4j_uri,
105
- user=neo4j_user,
106
- password=neo4j_password,
107
- )
108
- await get_group_ids(driver)
109
- await neo4j_node_label_migration(driver)
110
- await driver.close()
111
-
112
-
113
- if __name__ == '__main__':
114
- asyncio.run(main())