mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-13 04:04:09 +00:00
Update Graph Store module documentation and notebooks
- Enhanced Graph Store notebook with comprehensive examples and clean formatting - Fixed GraphStore API usage across all documentation files - Updated examples to use keyword arguments (labels, properties, start_node_id, end_node_id, rel_type) - Removed emojis and links from notebook for cleaner markdown - Made summary section more concise - Ensured consistency across cookbook notebooks, docs, and module code
This commit is contained in:
@@ -189,26 +189,42 @@
|
||||
"graph_store = GraphStore(backend=\"kuzu\", database_path=\"./analytics_graph_db\")\n",
|
||||
"graph_store.connect()\n",
|
||||
"\n",
|
||||
"# Store entities as nodes\n",
|
||||
"# Store entities as nodes and track node ID mapping\n",
|
||||
"node_id_map = {}\n",
|
||||
"for entity in entities:\n",
|
||||
" node = graph_store.create_node(\n",
|
||||
" labels=[entity[\"type\"]],\n",
|
||||
" properties={\"name\": entity[\"name\"], \"original_id\": entity[\"id\"]}\n",
|
||||
" )\n",
|
||||
" print(f\"Stored node: {entity['name']}\")\n",
|
||||
" node_id_map[entity[\"id\"]] = node.get(\"id\")\n",
|
||||
" print(f\"Stored node: {entity['name']} (ID: {node.get('id')})\")\n",
|
||||
"\n",
|
||||
"# Store relationships\n",
|
||||
"# Store relationships using mapped node IDs\n",
|
||||
"for rel in relationships:\n",
|
||||
" # In a real scenario, you'd lookup node IDs first\n",
|
||||
" print(f\"Relationship: {rel['source']} -{rel['type']}-> {rel['target']}\")\n",
|
||||
" source_id = node_id_map.get(rel[\"source\"])\n",
|
||||
" target_id = node_id_map.get(rel[\"target\"])\n",
|
||||
" \n",
|
||||
" if source_id is not None and target_id is not None:\n",
|
||||
" relationship = graph_store.create_relationship(\n",
|
||||
" start_node_id=source_id,\n",
|
||||
" end_node_id=target_id,\n",
|
||||
" rel_type=rel[\"type\"],\n",
|
||||
" properties=rel.get(\"properties\", {})\n",
|
||||
" )\n",
|
||||
" print(f\"Stored relationship: {rel['source']} -{rel['type']}-> {rel['target']}\")\n",
|
||||
" else:\n",
|
||||
" print(f\"Warning: Could not find node IDs for relationship {rel['source']} -> {rel['target']}\")\n",
|
||||
"\n",
|
||||
"# Query using Cypher\n",
|
||||
"results = graph_store.execute_query(\"MATCH (n) RETURN n.name, labels(n) LIMIT 10\")\n",
|
||||
"print(f\"\\nStored {len(results.get('records', []))} nodes in graph store\")\n",
|
||||
"print(f\"\\nQuery results: {len(results.get('records', []))} nodes\")\n",
|
||||
"\n",
|
||||
"# Get statistics\n",
|
||||
"stats = graph_store.get_stats()\n",
|
||||
"print(f\"Graph store stats: {stats}\")\n",
|
||||
"print(f\"\\nGraph store statistics:\")\n",
|
||||
"print(f\" Node count: {stats.get('node_count', 'N/A')}\")\n",
|
||||
"print(f\" Relationship count: {stats.get('relationship_count', 'N/A')}\")\n",
|
||||
"print(f\" Label counts: {stats.get('label_counts', {})}\")\n",
|
||||
"\n",
|
||||
"graph_store.close()\n"
|
||||
]
|
||||
|
||||
@@ -246,8 +246,20 @@
|
||||
"from semantica.graph_store import GraphStore\n",
|
||||
"store = GraphStore(backend=\"kuzu\", database_path=\"./my_graph_db\")\n",
|
||||
"store.connect()\n",
|
||||
"node = store.create_node([\"Person\"], {\"name\": \"John\", \"age\": 30})\n",
|
||||
"store.create_relationship(node[\"id\"], other_id, \"KNOWS\", {\"since\": 2020})\n",
|
||||
"node1 = store.create_node(\n",
|
||||
" labels=[\"Person\"],\n",
|
||||
" properties={\"name\": \"John\", \"age\": 30}\n",
|
||||
")\n",
|
||||
"node2 = store.create_node(\n",
|
||||
" labels=[\"Person\"],\n",
|
||||
" properties={\"name\": \"Jane\", \"age\": 28}\n",
|
||||
")\n",
|
||||
"store.create_relationship(\n",
|
||||
" start_node_id=node1[\"id\"],\n",
|
||||
" end_node_id=node2[\"id\"],\n",
|
||||
" rel_type=\"KNOWS\",\n",
|
||||
" properties={\"since\": 2020}\n",
|
||||
")\n",
|
||||
"results = store.execute_query(\"MATCH (p:Person) RETURN p.name\")\n",
|
||||
"store.close()\n",
|
||||
"```\n",
|
||||
|
||||
@@ -4,50 +4,84 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/10_Graph_Store.ipynb)\n",
|
||||
"\n",
|
||||
"# Graph Store\n",
|
||||
"# Graph Store Module\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates how to store and query property graphs using Semantica's graph store modules. You'll learn to use `GraphStore` with multiple backends including Neo4j, KuzuDB, and FalkorDB.\n",
|
||||
"The Graph Store module provides a unified interface for working with property graph databases. It supports multiple backends (Neo4j, KuzuDB, FalkorDB) and offers comprehensive features for storing, querying, and analyzing graph data.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/graph_store/)\n",
|
||||
"### Key Features\n",
|
||||
"\n",
|
||||
"- **Multi-Backend Support**: Neo4j (Enterprise), KuzuDB (Embedded), FalkorDB (Redis-based)\n",
|
||||
"- **Full CRUD Operations**: Create, read, update, delete nodes and relationships\n",
|
||||
"- **Cypher Query Language**: Execute complex graph queries with OpenCypher support\n",
|
||||
"- **Graph Analytics**: Built-in algorithms for centrality, community detection, path finding\n",
|
||||
"- **Batch Operations**: Optimized bulk data loading with progress tracking\n",
|
||||
"- **Transaction Support**: ACID transactions with rollback capabilities\n",
|
||||
"- **Index Management**: Create and manage indexes for performance optimization\n",
|
||||
"- **Convenience Functions**: Simple function-based API for common operations\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"\n",
|
||||
"- Use `GraphStore` to store nodes and relationships\n",
|
||||
"- Execute Cypher queries for graph retrieval\n",
|
||||
"- Use graph analytics (shortest path, neighbors)\n",
|
||||
"- Compare different graph database backends\n",
|
||||
"By the end of this notebook, you will be able to:\n",
|
||||
"\n",
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"Install Semantica from PyPI:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install semantica\n",
|
||||
"# Or with all optional dependencies:\n",
|
||||
"pip install semantica[all]\n",
|
||||
"```\n",
|
||||
"1. Initialize and configure GraphStore with different backends\n",
|
||||
"2. Perform CRUD operations on nodes and relationships\n",
|
||||
"3. Execute Cypher queries for complex graph operations\n",
|
||||
"4. Use graph analytics algorithms (shortest path, neighbors, centrality)\n",
|
||||
"5. Update and delete graph data\n",
|
||||
"6. Use batch operations for efficient data loading\n",
|
||||
"7. Work with convenience functions and configuration management\n",
|
||||
"8. Choose the right backend for your use case\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Prerequisites\n",
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"Install the required graph database client:\n",
|
||||
"### Core Installation\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"# For Neo4j\n",
|
||||
"# Install Semantica\n",
|
||||
"pip install semantica\n",
|
||||
"\n",
|
||||
"# Or install with all optional dependencies\n",
|
||||
"pip install semantica[all]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Backend-Specific Dependencies\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"# For Neo4j (requires Neo4j server)\n",
|
||||
"pip install neo4j\n",
|
||||
"\n",
|
||||
"# For KuzuDB (embedded - no server required)\n",
|
||||
"pip install kuzu\n",
|
||||
"\n",
|
||||
"# For FalkorDB\n",
|
||||
"# For FalkorDB (requires Redis/FalkorDB server)\n",
|
||||
"pip install falkordb\n",
|
||||
"# And run: docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb\n",
|
||||
"```\n"
|
||||
"```\n",
|
||||
"\n",
|
||||
"### Docker Setup (Optional)\n",
|
||||
"\n",
|
||||
"For FalkorDB, you can run it in Docker:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"docker run -p 6379:6379 -p 3000:3000 -it --rm \\\n",
|
||||
" -v ./data:/var/lib/falkordb/data \\\n",
|
||||
" falkordb/falkordb\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Backend Comparison\n",
|
||||
"\n",
|
||||
"| Backend | Best For | Deployment | Features |\n",
|
||||
"|---------|----------|------------|----------|\n",
|
||||
"| **Neo4j** | Enterprise applications, production systems | Server/Cloud | Full Cypher, APOC procedures, multi-database |\n",
|
||||
"| **KuzuDB** | Analytics, embedded applications, development | Embedded (no server) | Fast analytical queries, zero-config |\n",
|
||||
"| **FalkorDB** | LLM applications, real-time systems, high performance | Redis-based | Ultra-fast, sparse matrix operations |\n",
|
||||
"\n",
|
||||
"**Recommendation**: Start with **KuzuDB** for development and learning (no setup required), then move to **Neo4j** or **FalkorDB** for production.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -56,7 +90,7 @@
|
||||
"source": [
|
||||
"## Step 1: Initialize Graph Store\n",
|
||||
"\n",
|
||||
"Create a graph store with your preferred backend.\n"
|
||||
"Initialize a `GraphStore` instance with your preferred backend. For this tutorial, we'll use **KuzuDB** (embedded, no server setup required).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -67,7 +101,7 @@
|
||||
"source": [
|
||||
"from semantica.graph_store import GraphStore\n",
|
||||
"\n",
|
||||
"# Option 1: Neo4j (requires Neo4j server)\n",
|
||||
"# Option 1: Neo4j (requires Neo4j server running)\n",
|
||||
"# store = GraphStore(\n",
|
||||
"# backend=\"neo4j\",\n",
|
||||
"# uri=\"bolt://localhost:7687\",\n",
|
||||
@@ -75,7 +109,7 @@
|
||||
"# password=\"password\"\n",
|
||||
"# )\n",
|
||||
"\n",
|
||||
"# Option 2: KuzuDB (embedded - no server required)\n",
|
||||
"# Option 2: KuzuDB (embedded - no server required) - Recommended for learning\n",
|
||||
"store = GraphStore(\n",
|
||||
" backend=\"kuzu\",\n",
|
||||
" database_path=\"./demo_graph_db\"\n",
|
||||
@@ -90,16 +124,21 @@
|
||||
"# )\n",
|
||||
"\n",
|
||||
"# Connect to the database\n",
|
||||
"store.connect()\n"
|
||||
"store.connect()\n",
|
||||
"print(\"Connected to graph database successfully!\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Create Nodes\n",
|
||||
"## Step 2: Node Operations\n",
|
||||
"\n",
|
||||
"Create nodes with labels and properties.\n"
|
||||
"### Creating Nodes\n",
|
||||
"\n",
|
||||
"Nodes represent entities in your graph. Each node can have:\n",
|
||||
"- **Labels**: Categories/types (e.g., `Person`, `Company`, `Location`)\n",
|
||||
"- **Properties**: Key-value pairs (e.g., `{\"name\": \"Alice\", \"age\": 30}`)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -108,24 +147,24 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Create individual nodes\n",
|
||||
"# Create individual nodes with labels and properties\n",
|
||||
"apple = store.create_node(\n",
|
||||
" labels=[\"Company\"],\n",
|
||||
" properties={\"name\": \"Apple Inc.\", \"founded\": 1976, \"industry\": \"Technology\"}\n",
|
||||
")\n",
|
||||
"print(f\"Created company node: {apple}\")\n",
|
||||
"print(f\"Created company node: {apple.get('properties', {}).get('name')} (ID: {apple.get('id')})\")\n",
|
||||
"\n",
|
||||
"tim_cook = store.create_node(\n",
|
||||
" labels=[\"Person\"],\n",
|
||||
" properties={\"name\": \"Tim Cook\", \"title\": \"CEO\", \"age\": 63}\n",
|
||||
")\n",
|
||||
"print(f\"Created person node: {tim_cook}\")\n",
|
||||
"print(f\"Created person node: {tim_cook.get('properties', {}).get('name')} (ID: {tim_cook.get('id')})\")\n",
|
||||
"\n",
|
||||
"cupertino = store.create_node(\n",
|
||||
" labels=[\"Location\"],\n",
|
||||
" properties={\"name\": \"Cupertino\", \"state\": \"California\", \"country\": \"USA\"}\n",
|
||||
")\n",
|
||||
"print(f\"Created location node: {cupertino}\")\n"
|
||||
"print(f\"Created location node: {cupertino.get('properties', {}).get('name')} (ID: {cupertino.get('id')})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -134,7 +173,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Create multiple nodes in batch\n",
|
||||
"# Create multiple nodes in batch (more efficient for large datasets)\n",
|
||||
"other_companies = store.create_nodes([\n",
|
||||
" {\"labels\": [\"Company\"], \"properties\": {\"name\": \"Microsoft\", \"founded\": 1975}},\n",
|
||||
" {\"labels\": [\"Company\"], \"properties\": {\"name\": \"Google\", \"founded\": 1998}},\n",
|
||||
@@ -147,9 +186,14 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Create Relationships\n",
|
||||
"## Step 3: Relationship Operations\n",
|
||||
"\n",
|
||||
"Create relationships between nodes.\n"
|
||||
"### Creating Relationships\n",
|
||||
"\n",
|
||||
"Relationships connect nodes and represent connections between entities. Each relationship has:\n",
|
||||
"- **Type**: The relationship type (e.g., `CEO_OF`, `LOCATED_IN`, `KNOWS`)\n",
|
||||
"- **Properties**: Key-value pairs (e.g., `{\"since\": 2011}`)\n",
|
||||
"- **Direction**: From `start_node_id` to `end_node_id`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -158,14 +202,14 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Create relationships\n",
|
||||
"# Create relationships between nodes\n",
|
||||
"ceo_rel = store.create_relationship(\n",
|
||||
" start_node_id=tim_cook[\"id\"],\n",
|
||||
" end_node_id=apple[\"id\"],\n",
|
||||
" rel_type=\"CEO_OF\",\n",
|
||||
" properties={\"since\": 2011}\n",
|
||||
")\n",
|
||||
"print(f\"Created CEO relationship: {ceo_rel}\")\n",
|
||||
"print(f\"Created relationship: {ceo_rel.get('type')} (ID: {ceo_rel.get('id')})\")\n",
|
||||
"\n",
|
||||
"location_rel = store.create_relationship(\n",
|
||||
" start_node_id=apple[\"id\"],\n",
|
||||
@@ -173,16 +217,18 @@
|
||||
" rel_type=\"HEADQUARTERED_IN\",\n",
|
||||
" properties={\"since\": 1977}\n",
|
||||
")\n",
|
||||
"print(f\"Created location relationship: {location_rel}\")\n"
|
||||
"print(f\"Created relationship: {location_rel.get('type')} (ID: {location_rel.get('id')})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Query Nodes and Relationships\n",
|
||||
"## Step 4: Querying Nodes and Relationships\n",
|
||||
"\n",
|
||||
"Retrieve nodes and relationships from the graph.\n"
|
||||
"### Retrieving Nodes\n",
|
||||
"\n",
|
||||
"You can query nodes by labels, properties, or node IDs.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -191,11 +237,18 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Get all Company nodes\n",
|
||||
"# Get nodes by label\n",
|
||||
"companies = store.get_nodes(labels=[\"Company\"], limit=10)\n",
|
||||
"print(f\"Found {len(companies)} companies:\")\n",
|
||||
"for company in companies:\n",
|
||||
" print(f\" - {company.get('properties', {}).get('name', 'Unknown')}\")\n"
|
||||
" name = company.get('properties', {}).get('name', 'Unknown')\n",
|
||||
" founded = company.get('properties', {}).get('founded', 'N/A')\n",
|
||||
" print(f\" - {name} (founded: {founded})\")\n",
|
||||
"\n",
|
||||
"# Get a specific node by ID\n",
|
||||
"if apple.get('id'):\n",
|
||||
" node = store.get_node(node_id=apple[\"id\"])\n",
|
||||
" print(f\"\\nRetrieved node by ID: {node.get('properties', {}).get('name')}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -208,16 +261,29 @@
|
||||
"relationships = store.get_relationships(node_id=apple[\"id\"], direction=\"both\")\n",
|
||||
"print(f\"Found {len(relationships)} relationships for Apple:\")\n",
|
||||
"for rel in relationships:\n",
|
||||
" print(f\" - Type: {rel.get('type')}, Properties: {rel.get('properties')}\")\n"
|
||||
" rel_type = rel.get('type', 'Unknown')\n",
|
||||
" props = rel.get('properties', {})\n",
|
||||
" print(f\" - {rel_type}: {props}\")\n",
|
||||
"\n",
|
||||
"# Get relationships by type and direction\n",
|
||||
"if tim_cook.get('id'):\n",
|
||||
" outgoing = store.get_relationships(\n",
|
||||
" node_id=tim_cook[\"id\"],\n",
|
||||
" rel_type=\"CEO_OF\",\n",
|
||||
" direction=\"out\"\n",
|
||||
" )\n",
|
||||
" print(f\"\\nOutgoing CEO_OF relationships: {len(outgoing)}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Execute Cypher Queries\n",
|
||||
"## Step 5: Cypher Query Execution\n",
|
||||
"\n",
|
||||
"Use Cypher queries for complex graph operations.\n"
|
||||
"### Executing Cypher Queries\n",
|
||||
"\n",
|
||||
"Cypher is a powerful graph query language that allows you to express complex graph patterns and operations. The Graph Store module supports **OpenCypher** syntax across all backends.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -226,14 +292,18 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Execute a Cypher query\n",
|
||||
"# Execute a Cypher query to find CEO relationships\n",
|
||||
"results = store.execute_query(\"\"\"\n",
|
||||
" MATCH (p:Person)-[r:CEO_OF]->(c:Company)\n",
|
||||
" RETURN p.name as person, c.name as company, r.since as since\n",
|
||||
"\"\"\")\n",
|
||||
"\n",
|
||||
"print(\"CEO Relationships:\")\n",
|
||||
"for record in results.get(\"records\", []):\n",
|
||||
" print(f\" {record}\")\n"
|
||||
" person = record.get('person', 'Unknown')\n",
|
||||
" company = record.get('company', 'Unknown')\n",
|
||||
" since = record.get('since', 'N/A')\n",
|
||||
" print(f\" - {person} is CEO of {company} since {since}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -242,14 +312,17 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Parameterized query\n",
|
||||
"# Parameterized query (safer and more efficient)\n",
|
||||
"results = store.execute_query(\n",
|
||||
" \"MATCH (c:Company) WHERE c.founded > $year RETURN c.name, c.founded\",\n",
|
||||
" \"MATCH (c:Company) WHERE c.founded > $year RETURN c.name, c.founded ORDER BY c.founded\",\n",
|
||||
" parameters={\"year\": 1990}\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Companies founded after 1990:\")\n",
|
||||
"for record in results.get(\"records\", []):\n",
|
||||
" print(f\" {record}\")\n"
|
||||
" name = record.get('c.name', 'Unknown')\n",
|
||||
" founded = record.get('c.founded', 'N/A')\n",
|
||||
" print(f\" - {name} (founded: {founded})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -258,7 +331,9 @@
|
||||
"source": [
|
||||
"## Step 6: Graph Analytics\n",
|
||||
"\n",
|
||||
"Use built-in graph analytics functions.\n"
|
||||
"### Built-in Analytics Algorithms\n",
|
||||
"\n",
|
||||
"The Graph Store module provides several graph analytics algorithms for analyzing your graph structure.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -267,16 +342,19 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Get neighbors of a node\n",
|
||||
"neighbors = store.get_neighbors(\n",
|
||||
" node_id=apple[\"id\"],\n",
|
||||
" direction=\"both\",\n",
|
||||
" depth=2\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Found {len(neighbors)} neighbors (up to depth 2):\")\n",
|
||||
"for neighbor in neighbors:\n",
|
||||
" print(f\" - {neighbor.get('properties', {}).get('name', 'Unknown')}\")\n"
|
||||
"# Get neighbors of a node (traverse the graph)\n",
|
||||
"if apple.get('id'):\n",
|
||||
" neighbors = store.get_neighbors(\n",
|
||||
" node_id=apple[\"id\"],\n",
|
||||
" direction=\"both\",\n",
|
||||
" depth=2\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" print(f\"Found {len(neighbors)} neighbors (up to depth 2) for Apple:\")\n",
|
||||
" for neighbor in neighbors:\n",
|
||||
" name = neighbor.get('properties', {}).get('name', 'Unknown')\n",
|
||||
" labels = neighbor.get('labels', [])\n",
|
||||
" print(f\" - {name} ({', '.join(labels)})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -285,26 +363,32 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Find shortest path (if nodes are connected)\n",
|
||||
"path = store.shortest_path(\n",
|
||||
" start_node_id=tim_cook[\"id\"],\n",
|
||||
" end_node_id=cupertino[\"id\"],\n",
|
||||
" max_depth=5\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if path:\n",
|
||||
" print(f\"Shortest path length: {path.get('length')}\")\n",
|
||||
" print(f\"Nodes in path: {len(path.get('nodes', []))}\")\n",
|
||||
"else:\n"
|
||||
"# Find shortest path between two nodes\n",
|
||||
"if tim_cook.get('id') and cupertino.get('id'):\n",
|
||||
" path = store.shortest_path(\n",
|
||||
" start_node_id=tim_cook[\"id\"],\n",
|
||||
" end_node_id=cupertino[\"id\"],\n",
|
||||
" max_depth=5\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" if path:\n",
|
||||
" print(f\"Shortest path found:\")\n",
|
||||
" print(f\" - Path length: {path.get('length')}\")\n",
|
||||
" print(f\" - Nodes in path: {len(path.get('nodes', []))}\")\n",
|
||||
" print(f\" - Relationships: {len(path.get('relationships', []))}\")\n",
|
||||
" else:\n",
|
||||
" print(\"No path found between the nodes\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 7: Get Graph Statistics\n",
|
||||
"## Step 7: Update and Delete Operations\n",
|
||||
"\n",
|
||||
"Get statistics about the graph.\n"
|
||||
"### Updating Nodes\n",
|
||||
"\n",
|
||||
"You can update node properties using the `update_node` method.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -313,21 +397,173 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Update node properties (merge mode - adds/updates properties)\n",
|
||||
"if tim_cook.get('id'):\n",
|
||||
" updated = store.update_node(\n",
|
||||
" node_id=tim_cook[\"id\"],\n",
|
||||
" properties={\"age\": 64, \"title\": \"CEO & President\"},\n",
|
||||
" merge=True # Merge with existing properties\n",
|
||||
" )\n",
|
||||
" print(f\"Updated node: {updated.get('properties', {}).get('name')}\")\n",
|
||||
" print(f\" New age: {updated.get('properties', {}).get('age')}\")\n",
|
||||
" print(f\" New title: {updated.get('properties', {}).get('title')}\")\n",
|
||||
"\n",
|
||||
"# Example: Replace all properties (merge=False)\n",
|
||||
"# updated = store.update_node(\n",
|
||||
"# node_id=node_id,\n",
|
||||
"# properties={\"name\": \"New Name\"},\n",
|
||||
"# merge=False # Replace all properties\n",
|
||||
"# )\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 8: Delete Operations\n",
|
||||
"\n",
|
||||
"### Deleting Nodes and Relationships\n",
|
||||
"\n",
|
||||
"You can delete nodes and relationships when needed.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Delete a relationship\n",
|
||||
"if location_rel.get('id'):\n",
|
||||
" deleted = store.delete_relationship(rel_id=location_rel[\"id\"])\n",
|
||||
" if deleted:\n",
|
||||
" print(f\"Deleted relationship (ID: {location_rel['id']})\")\n",
|
||||
"\n",
|
||||
"# Delete a node (with detach=True to also delete its relationships)\n",
|
||||
"# WARNING: This will delete the node and all its relationships\n",
|
||||
"# Uncomment to test:\n",
|
||||
"# if cupertino.get('id'):\n",
|
||||
"# deleted = store.delete_node(node_id=cupertino[\"id\"], detach=True)\n",
|
||||
"# if deleted:\n",
|
||||
"# print(f\"Deleted node: {cupertino.get('properties', {}).get('name')}\")\n",
|
||||
"\n",
|
||||
"print(\"\\nTip: Use detach=True to delete a node and all its relationships\")\n",
|
||||
"print(\" Use detach=False to only delete the node (fails if relationships exist)\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 9: Graph Statistics\n",
|
||||
"\n",
|
||||
"Get comprehensive statistics about your graph.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Get comprehensive graph statistics\n",
|
||||
"stats = store.get_stats()\n",
|
||||
"\n",
|
||||
"print(f\" Node count: {stats.get('node_count', 'N/A')}\")\n",
|
||||
"print(f\" Relationship count: {stats.get('relationship_count', 'N/A')}\")\n",
|
||||
"print(f\" Label counts: {stats.get('label_counts', {})}\")\n",
|
||||
"print(f\" Relationship types: {stats.get('relationship_type_counts', {})}\")\n"
|
||||
"print(\"Graph Statistics:\")\n",
|
||||
"print(f\" Total nodes: {stats.get('node_count', 'N/A')}\")\n",
|
||||
"print(f\" Total relationships: {stats.get('relationship_count', 'N/A')}\")\n",
|
||||
"print(f\"\\nNode labels:\")\n",
|
||||
"for label, count in stats.get('label_counts', {}).items():\n",
|
||||
" print(f\" - {label}: {count} nodes\")\n",
|
||||
"print(f\"\\nRelationship types:\")\n",
|
||||
"for rel_type, count in stats.get('relationship_type_counts', {}).items():\n",
|
||||
" print(f\" - {rel_type}: {count} relationships\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 8: Clean Up\n",
|
||||
"## Step 10: Convenience Functions\n",
|
||||
"\n",
|
||||
"Close the connection when done.\n"
|
||||
"The Graph Store module provides convenience functions for simpler, function-based operations.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Using convenience functions (alternative to class methods)\n",
|
||||
"from semantica.graph_store import (\n",
|
||||
" create_node,\n",
|
||||
" create_relationship,\n",
|
||||
" get_nodes,\n",
|
||||
" execute_query,\n",
|
||||
" shortest_path\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# These functions work with a default store instance\n",
|
||||
"# For this example, we'll continue using the store instance we created\n",
|
||||
"\n",
|
||||
"# Example: Using convenience functions\n",
|
||||
"# node = create_node(\n",
|
||||
"# labels=[\"Person\"],\n",
|
||||
"# properties={\"name\": \"Alice\", \"age\": 30}\n",
|
||||
"# )\n",
|
||||
"\n",
|
||||
"print(\"Convenience functions available:\")\n",
|
||||
"print(\" - create_node, create_nodes\")\n",
|
||||
"print(\" - create_relationship, create_relationships\")\n",
|
||||
"print(\" - get_nodes, get_relationships\")\n",
|
||||
"print(\" - update_node, delete_node\")\n",
|
||||
"print(\" - execute_query, shortest_path, get_neighbors\")\n",
|
||||
"print(\" - run_analytics\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 11: Index Management\n",
|
||||
"\n",
|
||||
"Create indexes to improve query performance, especially for large graphs.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Create an index on a node property for faster lookups\n",
|
||||
"# This is especially useful for frequently queried properties\n",
|
||||
"\n",
|
||||
"index_created = store.create_index(\n",
|
||||
" label=\"Company\",\n",
|
||||
" property_name=\"name\",\n",
|
||||
" index_type=\"btree\" # Default index type\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if index_created:\n",
|
||||
" print(\"Created index on Company.name for faster queries\")\n",
|
||||
"else:\n",
|
||||
" print(\"Index may already exist or not be supported by this backend\")\n",
|
||||
"\n",
|
||||
"# Note: Index creation support varies by backend\n",
|
||||
"# Neo4j: Full support for various index types\n",
|
||||
"# KuzuDB: Automatic indexing on primary keys\n",
|
||||
"# FalkorDB: Limited index support\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 12: Clean Up\n",
|
||||
"\n",
|
||||
"Always close the connection when you're done to free up resources.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -337,7 +573,8 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Close the connection\n",
|
||||
"store.close()\n"
|
||||
"store.close()\n",
|
||||
"print(\"Connection closed successfully\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -346,24 +583,21 @@
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You've learned how to use graph stores:\n",
|
||||
"This notebook covered the Graph Store module, a unified interface for property graph databases supporting Neo4j, KuzuDB, and FalkorDB.\n",
|
||||
"\n",
|
||||
"- **GraphStore**: Unified interface for property graph databases\n",
|
||||
"- **Multiple Backends**: Neo4j, KuzuDB, FalkorDB support\n",
|
||||
"- **Node Operations**: Create, read, update, delete nodes\n",
|
||||
"- **Relationship Operations**: Create and query relationships\n",
|
||||
"- **Cypher Queries**: Execute powerful graph queries\n",
|
||||
"- **Graph Analytics**: Shortest path, neighbors, centrality\n",
|
||||
"### What You Learned\n",
|
||||
"\n",
|
||||
"### Backend Comparison\n",
|
||||
"- **CRUD Operations**: Create, read, update, and delete nodes and relationships\n",
|
||||
"- **Cypher Queries**: Execute complex graph queries with OpenCypher syntax\n",
|
||||
"- **Graph Analytics**: Shortest path, neighbor traversal, and centrality algorithms\n",
|
||||
"- **Batch Operations**: Efficient bulk data loading for large datasets\n",
|
||||
"- **Index Management**: Performance optimization through indexing\n",
|
||||
"\n",
|
||||
"| Backend | Best For | Deployment |\n",
|
||||
"|---------|----------|------------|\n",
|
||||
"| **Neo4j** | Enterprise, full features | Server/Cloud |\n",
|
||||
"| **KuzuDB** | Analytics, embedded | Embedded (no server) |\n",
|
||||
"| **FalkorDB** | LLM apps, real-time | Redis-based |\n",
|
||||
"### Key Takeaways\n",
|
||||
"\n",
|
||||
"Next: Learn how to visualize graphs in the Visualization notebook.\n"
|
||||
"- **Backend Selection**: Use KuzuDB for development, Neo4j for production, FalkorDB for high-performance applications\n",
|
||||
"- **Best Practices**: Use batch operations, parameterized queries, and proper connection management\n",
|
||||
"- **Next Steps**: Explore advanced analytics, graph quality, and visualization modules\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -732,7 +732,34 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Optional: Store graph in persistent graph database# Uncomment to use KuzuDB (embedded, no server required)# graph_store = GraphStore(backend=\"kuzu\", database_path=\"./graphrag_db\")# graph_store.connect()# # # Store nodes# for node_id, node_data in knowledge_graph.nodes(data=True):# labels = [node_data.get('type', 'Entity')]# properties = {k: v for k, v in node_data.items() if k != 'type'}# graph_store.create_node(labels, properties)# # # Store relationships# for source, target, edge_data in knowledge_graph.edges(data=True):# rel_type = edge_data.get('type', 'RELATED_TO')# properties = {k: v for k, v in edge_data.items() if k != 'type'}# graph_store.create_relationship(source, target, rel_type, properties)# # graph_store.close()# print(\"Knowledge graph stored in database\")print(\"Graph storage is optional. The in-memory graph is ready for GraphRAG.\")\n"
|
||||
"# Optional: Store graph in persistent graph database\n",
|
||||
"# Uncomment to use KuzuDB (embedded, no server required)\n",
|
||||
"# graph_store = GraphStore(backend=\"kuzu\", database_path=\"./graphrag_db\")\n",
|
||||
"# graph_store.connect()\n",
|
||||
"# \n",
|
||||
"# # Store nodes and track node ID mapping\n",
|
||||
"# node_id_map = {}\n",
|
||||
"# for node_id, node_data in knowledge_graph.nodes(data=True):\n",
|
||||
"# labels = [node_data.get('type', 'Entity')]\n",
|
||||
"# properties = {k: v for k, v in node_data.items() if k != 'type'}\n",
|
||||
"# created_node = graph_store.create_node(labels, properties)\n",
|
||||
"# node_id_map[node_id] = created_node.get(\"id\")\n",
|
||||
"# \n",
|
||||
"# # Store relationships using mapped node IDs\n",
|
||||
"# for source, target, edge_data in knowledge_graph.edges(data=True):\n",
|
||||
"# if source in node_id_map and target in node_id_map:\n",
|
||||
"# rel_type = edge_data.get('type', 'RELATED_TO')\n",
|
||||
"# properties = {k: v for k, v in edge_data.items() if k != 'type'}\n",
|
||||
"# graph_store.create_relationship(\n",
|
||||
"# start_node_id=node_id_map[source],\n",
|
||||
"# end_node_id=node_id_map[target],\n",
|
||||
"# rel_type=rel_type,\n",
|
||||
"# properties=properties\n",
|
||||
"# )\n",
|
||||
"# \n",
|
||||
"# graph_store.close()\n",
|
||||
"# print(\"Knowledge graph stored in database\")\n",
|
||||
"print(\"Graph storage is optional. The in-memory graph is ready for GraphRAG.\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+13
-3
@@ -185,9 +185,19 @@ store = GraphStore(
|
||||
store.connect()
|
||||
|
||||
# Create nodes and relationships
|
||||
apple = store.create_node(["Company"], {"name": "Apple Inc."})
|
||||
tim = store.create_node(["Person"], {"name": "Tim Cook"})
|
||||
store.create_relationship(tim["id"], apple["id"], "CEO_OF")
|
||||
apple = store.create_node(
|
||||
labels=["Company"],
|
||||
properties={"name": "Apple Inc."}
|
||||
)
|
||||
tim = store.create_node(
|
||||
labels=["Person"],
|
||||
properties={"name": "Tim Cook"}
|
||||
)
|
||||
store.create_relationship(
|
||||
start_node_id=tim["id"],
|
||||
end_node_id=apple["id"],
|
||||
rel_type="CEO_OF"
|
||||
)
|
||||
|
||||
store.close()
|
||||
```
|
||||
|
||||
+14
-3
@@ -541,9 +541,20 @@ store = GraphStore(backend="neo4j", uri="bolt://localhost:7687")
|
||||
store.connect()
|
||||
|
||||
# Create nodes and relationships
|
||||
alice = store.create_node(["Person"], {"name": "Alice", "age": 30})
|
||||
bob = store.create_node(["Person"], {"name": "Bob", "age": 25})
|
||||
store.create_relationship(alice["id"], bob["id"], "KNOWS", {"since": 2020})
|
||||
alice = store.create_node(
|
||||
labels=["Person"],
|
||||
properties={"name": "Alice", "age": 30}
|
||||
)
|
||||
bob = store.create_node(
|
||||
labels=["Person"],
|
||||
properties={"name": "Bob", "age": 25}
|
||||
)
|
||||
store.create_relationship(
|
||||
start_node_id=alice["id"],
|
||||
end_node_id=bob["id"],
|
||||
rel_type="KNOWS",
|
||||
properties={"since": 2020}
|
||||
)
|
||||
|
||||
# Query with Cypher
|
||||
results = store.execute_query("MATCH (p:Person) RETURN p.name")
|
||||
|
||||
+249
-17
@@ -74,7 +74,9 @@
|
||||
|
||||
## Main Classes
|
||||
|
||||
### GraphStore
|
||||
### Core Classes
|
||||
|
||||
#### GraphStore
|
||||
|
||||
The main facade for graph operations.
|
||||
|
||||
@@ -82,9 +84,28 @@ The main facade for graph operations.
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `execute_query(query, params)` | Run Cypher query |
|
||||
| `create_node(labels, props)` | Add node |
|
||||
| `create_relationship(start, end, type)` | Add edge |
|
||||
| `connect(**options)` | Connect to the graph database |
|
||||
| `close()` | Close connection to the graph database |
|
||||
| `create_node(labels, properties, **options)` | Create a single node |
|
||||
| `create_nodes(nodes, **options)` | Create multiple nodes in batch |
|
||||
| `get_node(node_id, **options)` | Get a node by ID |
|
||||
| `get_nodes(labels, properties, limit, **options)` | Get nodes matching criteria |
|
||||
| `update_node(node_id, properties, merge, **options)` | Update node properties |
|
||||
| `delete_node(node_id, detach, **options)` | Delete a node |
|
||||
| `create_relationship(start_node_id, end_node_id, rel_type, properties, **options)` | Create a relationship |
|
||||
| `get_relationships(node_id, rel_type, direction, limit, **options)` | Get relationships |
|
||||
| `delete_relationship(rel_id, **options)` | Delete a relationship |
|
||||
| `execute_query(query, parameters, **options)` | Execute a Cypher/OpenCypher query |
|
||||
| `shortest_path(start_node_id, end_node_id, rel_type, max_depth, **options)` | Find shortest path between nodes |
|
||||
| `get_neighbors(node_id, rel_type, direction, depth, **options)` | Get neighboring nodes |
|
||||
| `get_stats()` | Get graph statistics |
|
||||
| `create_index(label, property_name, index_type, **options)` | Create an index |
|
||||
|
||||
**Properties:**
|
||||
- `nodes` - Access to NodeManager
|
||||
- `relationships` - Access to RelationshipManager
|
||||
- `query_engine` - Access to QueryEngine
|
||||
- `analytics` - Access to GraphAnalytics
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -92,51 +113,262 @@ The main facade for graph operations.
|
||||
from semantica.graph_store import GraphStore
|
||||
|
||||
store = GraphStore(backend="neo4j")
|
||||
store.connect()
|
||||
store.execute_query(
|
||||
"MATCH (n:Person {name: $name}) RETURN n",
|
||||
params={"name": "Alice"}
|
||||
parameters={"name": "Alice"}
|
||||
)
|
||||
store.close()
|
||||
```
|
||||
|
||||
### Neo4jAdapter
|
||||
#### GraphManager
|
||||
|
||||
Enterprise-grade backend.
|
||||
Manager for graph store operations. Provides access to node, relationship, query, and analytics managers.
|
||||
|
||||
**Methods:**
|
||||
- `get_stats()` - Get graph statistics
|
||||
- `create_index(label, property_name, index_type, **options)` - Create an index
|
||||
|
||||
#### NodeManager
|
||||
|
||||
Manager for node CRUD operations.
|
||||
|
||||
**Methods:**
|
||||
- `create(labels, properties, **options)` - Create a node
|
||||
- `create_batch(nodes, **options)` - Create multiple nodes
|
||||
- `get(node_id, labels, properties, limit, **options)` - Get node(s)
|
||||
- `update(node_id, properties, merge, **options)` - Update a node
|
||||
- `delete(node_id, detach, **options)` - Delete a node
|
||||
|
||||
#### RelationshipManager
|
||||
|
||||
Manager for relationship CRUD operations.
|
||||
|
||||
**Methods:**
|
||||
- `create(start_node_id, end_node_id, rel_type, properties, **options)` - Create a relationship
|
||||
- `get(node_id, rel_type, direction, limit, **options)` - Get relationships
|
||||
- `delete(rel_id, **options)` - Delete a relationship
|
||||
|
||||
#### QueryEngine
|
||||
|
||||
Engine for query execution and optimization.
|
||||
|
||||
**Methods:**
|
||||
- `execute(query, parameters, use_cache, **options)` - Execute a Cypher/OpenCypher query
|
||||
- `clear_cache()` - Clear query cache
|
||||
- `enable_cache()` - Enable query caching
|
||||
- `disable_cache()` - Disable query caching
|
||||
|
||||
#### GraphAnalytics
|
||||
|
||||
Graph analytics and algorithms.
|
||||
|
||||
**Methods:**
|
||||
- `shortest_path(start_node_id, end_node_id, rel_type, max_depth, **options)` - Find shortest path
|
||||
- `get_neighbors(node_id, rel_type, direction, depth, **options)` - Get neighboring nodes
|
||||
- `degree_centrality(labels, rel_type, direction, **options)` - Calculate degree centrality
|
||||
- `connected_components(labels, **options)` - Find connected components
|
||||
|
||||
### Adapter Classes
|
||||
|
||||
#### Neo4jAdapter
|
||||
|
||||
Enterprise-grade Neo4j backend adapter.
|
||||
|
||||
**Features:**
|
||||
- Bolt protocol support
|
||||
- Cluster awareness
|
||||
- APOC procedure integration
|
||||
- Multi-database support
|
||||
- Transaction support
|
||||
|
||||
### KuzuAdapter
|
||||
**Related Classes:**
|
||||
- `Neo4jDriver` - Neo4j driver wrapper
|
||||
- `Neo4jSession` - Session management wrapper
|
||||
- `Neo4jTransaction` - Transaction wrapper
|
||||
|
||||
Embedded, in-process backend.
|
||||
#### KuzuAdapter
|
||||
|
||||
Embedded, in-process KuzuDB backend adapter.
|
||||
|
||||
**Features:**
|
||||
- No external server required
|
||||
- Columnar storage for speed
|
||||
- Zero-copy integration with Arrow
|
||||
- Schema-based node and relationship tables
|
||||
- High-performance analytical queries
|
||||
|
||||
### FalkorDBAdapter
|
||||
**Related Classes:**
|
||||
- `KuzuDatabase` - Database wrapper
|
||||
- `KuzuConnection` - Connection wrapper
|
||||
- `KuzuQuery` - Query execution wrapper
|
||||
|
||||
High-performance Redis module.
|
||||
**Special Methods:**
|
||||
- `create_node_table(table_name, properties, primary_key, **options)` - Create node table with schema
|
||||
- `create_rel_table(table_name, from_table, to_table, properties, **options)` - Create relationship table
|
||||
- `bulk_load_nodes(table_name, file_path, **options)` - Bulk load nodes from CSV
|
||||
|
||||
#### FalkorDBAdapter
|
||||
|
||||
High-performance Redis-based FalkorDB backend adapter.
|
||||
|
||||
**Features:**
|
||||
- Sparse matrix representation
|
||||
- Ultra-low latency
|
||||
- Redis protocol
|
||||
- Multi-graph support
|
||||
- Linear algebra based querying
|
||||
|
||||
**Related Classes:**
|
||||
- `FalkorDBClient` - Client wrapper
|
||||
- `FalkorDBGraph` - Graph wrapper with operations
|
||||
- `FalkorDBQuery` - Query execution wrapper
|
||||
|
||||
**Special Methods:**
|
||||
- `select_graph(graph_name)` - Select or create a graph
|
||||
- `list_graphs()` - List all available graphs
|
||||
- `delete_graph(graph_name)` - Delete a graph
|
||||
|
||||
### Configuration and Registry Classes
|
||||
|
||||
#### GraphStoreConfig
|
||||
|
||||
Configuration manager for graph store module. Supports environment variables, config files (YAML, JSON, TOML), and programmatic configuration.
|
||||
|
||||
**Methods:**
|
||||
- `get(key, default)` - Get configuration value
|
||||
- `set(key, value)` - Set configuration value
|
||||
- `update(config)` - Update configuration with dictionary
|
||||
- `get_method_config(method_name)` - Get method-specific configuration
|
||||
- `set_method_config(method_name, config)` - Set method-specific configuration
|
||||
- `get_all()` - Get all configuration
|
||||
- `get_neo4j_config()` - Get Neo4j-specific configuration
|
||||
- `get_kuzu_config()` - Get KuzuDB-specific configuration
|
||||
- `get_falkordb_config()` - Get FalkorDB-specific configuration
|
||||
- `reset()` - Reset configuration to defaults
|
||||
|
||||
**Global Instance:**
|
||||
- `graph_store_config` - Global configuration instance
|
||||
|
||||
#### MethodRegistry
|
||||
|
||||
Registry for custom graph store methods, enabling extensibility.
|
||||
|
||||
**Methods:**
|
||||
- `register(task, method_name, method_func, **metadata)` - Register a method
|
||||
- `unregister(task, method_name)` - Unregister a method
|
||||
- `get(task, method_name)` - Get a registered method
|
||||
- `list_all(task)` - List all registered methods
|
||||
- `has(task, method_name)` - Check if a method is registered
|
||||
- `get_metadata(task, method_name)` - Get metadata for a registered method
|
||||
|
||||
**Supported Task Types:**
|
||||
- `node` - Node CRUD methods
|
||||
- `relationship` - Relationship CRUD methods
|
||||
- `query` - Query execution methods
|
||||
- `traversal` - Graph traversal methods
|
||||
- `analytics` - Graph analytics methods
|
||||
- `bulk` - Bulk operation methods
|
||||
|
||||
**Global Instance:**
|
||||
- `method_registry` - Global method registry instance
|
||||
|
||||
---
|
||||
|
||||
## Convenience Functions
|
||||
|
||||
```python
|
||||
from semantica.graph_store import execute_query, create_node
|
||||
The module provides convenience functions for common graph operations. These functions use a global GraphStore instance and support method registration for extensibility.
|
||||
|
||||
# Quick query
|
||||
results = execute_query("MATCH (n) RETURN count(n) as count")
|
||||
### Node Operations
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `create_node(labels, properties, method, **options)` | Create a single node |
|
||||
| `create_nodes(nodes, method, **options)` | Create multiple nodes in batch |
|
||||
| `get_nodes(labels, properties, limit, method, **options)` | Get nodes matching criteria |
|
||||
| `update_node(node_id, properties, merge, method, **options)` | Update node properties |
|
||||
| `delete_node(node_id, detach, method, **options)` | Delete a node |
|
||||
|
||||
### Relationship Operations
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `create_relationship(start_id, end_id, rel_type, properties, method, **options)` | Create a relationship |
|
||||
| `create_relationships(relationships, method, **options)` | Create multiple relationships in batch |
|
||||
| `get_relationships(node_id, rel_type, direction, limit, method, **options)` | Get relationships matching criteria |
|
||||
| `update_relationship(rel_id, properties, method, **options)` | Update relationship properties |
|
||||
| `delete_relationship(rel_id, method, **options)` | Delete a relationship |
|
||||
|
||||
### Query Operations
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `execute_query(query, parameters, method, **options)` | Execute a Cypher/OpenCypher query |
|
||||
|
||||
### Analytics Operations
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `shortest_path(start_node_id, end_node_id, rel_type, max_depth, method, **options)` | Find shortest path between nodes |
|
||||
| `get_neighbors(node_id, rel_type, direction, depth, method, **options)` | Get neighboring nodes |
|
||||
| `run_analytics(algorithm, method, **options)` | Run graph analytics algorithm |
|
||||
|
||||
### Utility Functions
|
||||
|
||||
| Function | Description |
|
||||
|----------|-------------|
|
||||
| `get_graph_store_method(task, method_name)` | Get graph store method by task and name |
|
||||
| `list_available_methods(task)` | List all available graph store methods |
|
||||
|
||||
**Example:**
|
||||
|
||||
```python
|
||||
from semantica.graph_store import (
|
||||
create_node,
|
||||
create_nodes,
|
||||
create_relationship,
|
||||
execute_query,
|
||||
shortest_path,
|
||||
get_neighbors,
|
||||
run_analytics
|
||||
)
|
||||
|
||||
# Quick node creation
|
||||
create_node(["Person"], {"name": "Bob"})
|
||||
alice = create_node(["Person"], {"name": "Alice", "age": 30})
|
||||
bob = create_node(["Person"], {"name": "Bob", "age": 25})
|
||||
|
||||
# Batch node creation
|
||||
people = create_nodes([
|
||||
{"labels": ["Person"], "properties": {"name": "Charlie"}},
|
||||
{"labels": ["Person"], "properties": {"name": "Diana"}}
|
||||
])
|
||||
|
||||
# Create relationship
|
||||
rel = create_relationship(
|
||||
start_id=alice["id"],
|
||||
end_id=bob["id"],
|
||||
rel_type="KNOWS",
|
||||
properties={"since": 2020}
|
||||
)
|
||||
|
||||
# Quick query
|
||||
results = execute_query("MATCH (n:Person) RETURN count(n) as count")
|
||||
|
||||
# Find shortest path
|
||||
path = shortest_path(
|
||||
start_node_id=alice["id"],
|
||||
end_node_id=bob["id"],
|
||||
max_depth=5
|
||||
)
|
||||
|
||||
# Get neighbors
|
||||
neighbors = get_neighbors(node_id=alice["id"], depth=2)
|
||||
|
||||
# Run analytics
|
||||
centrality = run_analytics(
|
||||
algorithm="degree_centrality",
|
||||
labels=["Person"]
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -189,7 +421,7 @@ MATCH (n)-[r]-(m)
|
||||
WHERE elementId(n) IN $ids
|
||||
RETURN n, r, m
|
||||
"""
|
||||
subgraph = graph_store.execute_query(query, params={"ids": node_ids})
|
||||
subgraph = graph_store.execute_query(query, parameters={"ids": node_ids})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -84,7 +84,7 @@ Example Usage:
|
||||
>>> from semantica.graph_store import GraphStore, create_node, create_relationship, execute_query
|
||||
>>> # Using convenience functions
|
||||
>>> node_id = create_node(labels=["Person"], properties={"name": "Alice", "age": 30})
|
||||
>>> rel_id = create_relationship(start_id=node1_id, end_id=node2_id, type="KNOWS", properties={"since": 2020})
|
||||
>>> rel_id = create_relationship(start_id=node1_id, end_id=node2_id, rel_type="KNOWS", properties={"since": 2020})
|
||||
>>> results = execute_query("MATCH (p:Person) WHERE p.age > 25 RETURN p.name")
|
||||
>>> # Using classes directly
|
||||
>>> store = GraphStore(backend="neo4j", uri="bolt://localhost:7687")
|
||||
|
||||
@@ -455,6 +455,81 @@ from semantica.graph_store import (
|
||||
)
|
||||
```
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Using GraphStoreConfig
|
||||
|
||||
The `GraphStoreConfig` class provides centralized configuration management:
|
||||
|
||||
```python
|
||||
from semantica.graph_store import GraphStoreConfig, graph_store_config
|
||||
|
||||
# Get configuration value
|
||||
default_backend = graph_store_config.get("default_backend", default="neo4j")
|
||||
|
||||
# Set configuration value
|
||||
graph_store_config.set("default_backend", "falkordb")
|
||||
|
||||
# Update multiple values
|
||||
graph_store_config.update({
|
||||
"batch_size": 2000,
|
||||
"timeout": 60
|
||||
})
|
||||
|
||||
# Get backend-specific configuration
|
||||
neo4j_config = graph_store_config.get_neo4j_config()
|
||||
kuzu_config = graph_store_config.get_kuzu_config()
|
||||
falkordb_config = graph_store_config.get_falkordb_config()
|
||||
|
||||
# Get all configuration
|
||||
all_config = graph_store_config.get_all()
|
||||
|
||||
# Reset to defaults
|
||||
graph_store_config.reset()
|
||||
```
|
||||
|
||||
### Method Registry
|
||||
|
||||
The `MethodRegistry` class allows you to register custom methods for extensibility:
|
||||
|
||||
```python
|
||||
from semantica.graph_store import MethodRegistry, method_registry
|
||||
|
||||
# Register a custom node creation method
|
||||
def validated_create_node(labels, properties, **options):
|
||||
"""Custom node creation with validation."""
|
||||
if "name" not in properties:
|
||||
raise ValueError("name is required")
|
||||
|
||||
from semantica.graph_store import _get_store
|
||||
store = _get_store()
|
||||
return store.create_node(labels, properties, **options)
|
||||
|
||||
# Register the custom method
|
||||
method_registry.register("node", "validated", validated_create_node)
|
||||
|
||||
# Use the custom method
|
||||
from semantica.graph_store import create_node
|
||||
node = create_node(
|
||||
labels=["Person"],
|
||||
properties={"name": "Alice"},
|
||||
method="validated"
|
||||
)
|
||||
|
||||
# List available methods
|
||||
available = method_registry.list_all("node")
|
||||
# Returns: {"node": ["validated"]}
|
||||
|
||||
# Check if a method exists
|
||||
exists = method_registry.has("node", "validated")
|
||||
|
||||
# Get method metadata
|
||||
metadata = method_registry.get_metadata("node", "validated")
|
||||
|
||||
# Unregister a method
|
||||
method_registry.unregister("node", "validated")
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Context Manager
|
||||
@@ -470,7 +545,7 @@ with GraphStore(backend="neo4j", uri="bolt://localhost:7687") as store:
|
||||
### Custom Method Registration
|
||||
|
||||
```python
|
||||
from semantica.graph_store import method_registry
|
||||
from semantica.graph_store import method_registry, GraphStore
|
||||
|
||||
def custom_create_node(labels, properties, **options):
|
||||
"""Custom node creation with validation."""
|
||||
@@ -479,9 +554,12 @@ def custom_create_node(labels, properties, **options):
|
||||
raise ValueError("name is required")
|
||||
|
||||
# Call default implementation
|
||||
from semantica.graph_store import _get_store
|
||||
store = _get_store()
|
||||
return store.create_node(labels, properties, **options)
|
||||
store = GraphStore()
|
||||
store.connect()
|
||||
try:
|
||||
return store.create_node(labels, properties, **options)
|
||||
finally:
|
||||
store.close()
|
||||
|
||||
# Register custom method
|
||||
method_registry.register("node", "validated", custom_create_node)
|
||||
|
||||
@@ -54,7 +54,7 @@ Main Functions:
|
||||
Example Usage:
|
||||
>>> from semantica.graph_store.methods import create_node, create_relationship, execute_query
|
||||
>>> node_id = create_node(labels=["Person"], properties={"name": "Alice"})
|
||||
>>> rel = create_relationship(start_id=node1_id, end_id=node2_id, type="KNOWS")
|
||||
>>> rel = create_relationship(start_id=node1_id, end_id=node2_id, rel_type="KNOWS")
|
||||
>>> results = execute_query("MATCH (p:Person) RETURN p.name")
|
||||
"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user