diff --git a/trustgraph-flow/trustgraph/direct/cassandra_kg.py b/trustgraph-flow/trustgraph/direct/cassandra_kg.py index 4c0f9c4f..e2704350 100644 --- a/trustgraph-flow/trustgraph/direct/cassandra_kg.py +++ b/trustgraph-flow/trustgraph/direct/cassandra_kg.py @@ -24,16 +24,10 @@ class KnowledgeGraph: self.keyspace = keyspace self.username = username - # Multi-table schema design for optimal performance - self.use_legacy = os.getenv('CASSANDRA_USE_LEGACY', 'false').lower() == 'true' - - if self.use_legacy: - self.table = "triples" # Legacy single table - else: - # New optimized tables - self.subject_table = "triples_s" - self.po_table = "triples_p" - self.object_table = "triples_o" + # Optimized multi-table schema + self.subject_table = "triples_s" + self.po_table = "triples_p" + self.object_table = "triples_o" if username and password: ssl_context = SSLContext(PROTOCOL_TLSv1_2) @@ -47,9 +41,7 @@ class KnowledgeGraph: _active_clusters.append(self.cluster) self.init() - - if not self.use_legacy: - self.prepare_statements() + self.prepare_statements() def clear(self): @@ -70,38 +62,8 @@ class KnowledgeGraph: """); self.session.set_keyspace(self.keyspace) + self.init_optimized_schema() - if self.use_legacy: - self.init_legacy_schema() - else: - self.init_optimized_schema() - - def init_legacy_schema(self): - """Initialize legacy single-table schema for backward compatibility""" - self.session.execute(f""" - create table if not exists {self.table} ( - collection text, - s text, - p text, - o text, - PRIMARY KEY (collection, s, p, o) - ); - """); - - self.session.execute(f""" - create index if not exists {self.table}_s - ON {self.table} (s); - """); - - self.session.execute(f""" - create index if not exists {self.table}_p - ON {self.table} (p); - """); - - self.session.execute(f""" - create index if not exists {self.table}_o - ON {self.table} (o); - """); def init_optimized_schema(self): """Initialize optimized multi-table schema for performance""" @@ -192,152 +154,91 @@ class KnowledgeGraph: logger.info("Prepared statements initialized for optimal performance") def insert(self, collection, s, p, o): + # Batch write to all three tables for consistency + batch = BatchStatement() - if self.use_legacy: - self.session.execute( - f"insert into {self.table} (collection, s, p, o) values (%s, %s, %s, %s)", - (collection, s, p, o) - ) - else: - # Batch write to all three tables for consistency - batch = BatchStatement() + # Insert into subject table + batch.add(self.insert_subject_stmt, (collection, s, p, o)) - # Insert into subject table - batch.add(self.insert_subject_stmt, (collection, s, p, o)) + # Insert into predicate-object table (column order: collection, p, o, s) + batch.add(self.insert_po_stmt, (collection, p, o, s)) - # Insert into predicate-object table (column order: collection, p, o, s) - batch.add(self.insert_po_stmt, (collection, p, o, s)) + # Insert into object table (column order: collection, o, s, p) + batch.add(self.insert_object_stmt, (collection, o, s, p)) - # Insert into object table (column order: collection, o, s, p) - batch.add(self.insert_object_stmt, (collection, o, s, p)) - - self.session.execute(batch) + self.session.execute(batch) def get_all(self, collection, limit=50): - if self.use_legacy: - return self.session.execute( - f"select s, p, o from {self.table} where collection = %s limit {limit}", - (collection,) - ) - else: - # Use subject table for get_all queries - return self.session.execute( - self.get_all_stmt, - (collection, limit) - ) + # Use subject table for get_all queries + return self.session.execute( + self.get_all_stmt, + (collection, limit) + ) def get_s(self, collection, s, limit=10): - if self.use_legacy: - return self.session.execute( - f"select p, o from {self.table} where collection = %s and s = %s limit {limit}", - (collection, s) - ) - else: - # Optimized: Direct partition access with (collection, s) - return self.session.execute( - self.get_s_stmt, - (collection, s, limit) - ) + # Optimized: Direct partition access with (collection, s) + return self.session.execute( + self.get_s_stmt, + (collection, s, limit) + ) def get_p(self, collection, p, limit=10): - if self.use_legacy: - return self.session.execute( - f"select s, o from {self.table} where collection = %s and p = %s limit {limit}", - (collection, p) - ) - else: - # Optimized: Use po_table for direct partition access - return self.session.execute( - self.get_p_stmt, - (collection, p, limit) - ) + # Optimized: Use po_table for direct partition access + return self.session.execute( + self.get_p_stmt, + (collection, p, limit) + ) def get_o(self, collection, o, limit=10): - if self.use_legacy: - return self.session.execute( - f"select s, p from {self.table} where collection = %s and o = %s limit {limit}", - (collection, o) - ) - else: - # Optimized: Use object_table for direct partition access - return self.session.execute( - self.get_o_stmt, - (collection, o, limit) - ) + # Optimized: Use object_table for direct partition access + return self.session.execute( + self.get_o_stmt, + (collection, o, limit) + ) def get_sp(self, collection, s, p, limit=10): - if self.use_legacy: - return self.session.execute( - f"select o from {self.table} where collection = %s and s = %s and p = %s limit {limit}", - (collection, s, p) - ) - else: - # Optimized: Use subject_table with clustering key access - return self.session.execute( - self.get_sp_stmt, - (collection, s, p, limit) - ) + # Optimized: Use subject_table with clustering key access + return self.session.execute( + self.get_sp_stmt, + (collection, s, p, limit) + ) def get_po(self, collection, p, o, limit=10): - if self.use_legacy: - return self.session.execute( - f"select s from {self.table} where collection = %s and p = %s and o = %s limit {limit} allow filtering", - (collection, p, o) - ) - else: - # CRITICAL OPTIMIZATION: Use po_table - NO MORE ALLOW FILTERING! - return self.session.execute( - self.get_po_stmt, - (collection, p, o, limit) - ) + # CRITICAL OPTIMIZATION: Use po_table - NO MORE ALLOW FILTERING! + return self.session.execute( + self.get_po_stmt, + (collection, p, o, limit) + ) def get_os(self, collection, o, s, limit=10): - if self.use_legacy: - return self.session.execute( - f"select p from {self.table} where collection = %s and o = %s and s = %s limit {limit} allow filtering", - (collection, o, s) - ) - else: - # Optimized: Use subject_table with clustering access (no more ALLOW FILTERING) - return self.session.execute( - self.get_os_stmt, - (collection, s, o, limit) - ) + # Optimized: Use subject_table with clustering access (no more ALLOW FILTERING) + return self.session.execute( + self.get_os_stmt, + (collection, s, o, limit) + ) def get_spo(self, collection, s, p, o, limit=10): - if self.use_legacy: - return self.session.execute( - f"""select s as x from {self.table} where collection = %s and s = %s and p = %s and o = %s limit {limit}""", - (collection, s, p, o) - ) - else: - # Optimized: Use subject_table for exact key lookup - return self.session.execute( - self.get_spo_stmt, - (collection, s, p, o, limit) - ) + # Optimized: Use subject_table for exact key lookup + return self.session.execute( + self.get_spo_stmt, + (collection, s, p, o, limit) + ) def delete_collection(self, collection): """Delete all triples for a specific collection""" - if self.use_legacy: - self.session.execute( - f"delete from {self.table} where collection = %s", - (collection,) - ) - else: - # Delete from all three tables - self.session.execute( - f"delete from {self.subject_table} where collection = %s", - (collection,) - ) - self.session.execute( - f"delete from {self.po_table} where collection = %s", - (collection,) - ) - self.session.execute( - f"delete from {self.object_table} where collection = %s", - (collection,) - ) + # Delete from all three tables + self.session.execute( + f"delete from {self.subject_table} where collection = %s", + (collection,) + ) + self.session.execute( + f"delete from {self.po_table} where collection = %s", + (collection,) + ) + self.session.execute( + f"delete from {self.object_table} where collection = %s", + (collection,) + ) def close(self): """Close the Cassandra session and cluster connections properly"""