Lightweight, Embedded, Dual-interface Graph Knowledge Base
- Support CLI
- Support python API
- Embedded (in-process) database including in memory and on-disk
- Core functions
- CRUD: Create, Read, Update, Delete Nodes, Relationships
- Search: BM25, Cypher, Filter by properties, Filter by labels, etc.
- Schema: Generate Graph Schema
- Stats: Collect graph statistics
- Graph Manipulation: Subgraph extraction, composition, and analysis
git clone https://github.com/locchh/gkb.git
cd gkb
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e .- Define use cases and core components
- Define Python API interface
- Define core data models
- Implement core CRUD operations
- Implement search functionality (BM25, Cypher, Hybrid)
- Implement graph manipulation and composition
- Implement schema generation
- Implement stats collection
- Support CLI
- CLI:
# Help
gkb -h|--help
# Node operations
gkb -d mydb.gkb node add -l Person,Developer -p '{"name": "Alice", "age": 30}'
gkb -d mydb.gkb node list -l Person
gkb -d mydb.gkb node get 0
# Relationship operations
gkb -d mydb.gkb rel add -f 0 -t 1 -T KNOWS
gkb -d mydb.gkb rel list -T KNOWS
# Search
gkb -d mydb.gkb search --text "Alice"
gkb -d mydb.gkb search --cypher "MATCH (n:Node) RETURN n"
# Graph operations
gkb -d mydb.gkb neighborhood 0 --hops 2
gkb -d mydb.gkb schema
gkb -d mydb.gkb stats
# Export/Import
gkb -d mydb.gkb export -o backup.json
gkb -d mydb.gkb import backup.json- Python API:
from gkb import GKB,create_gkb, connect_gkb
# ============================================
# 1. Initialize knowledge base
# ============================================
# Create file database
kb = create_gkb("my_knowledge.gkb")
# Create in memory database
kb = create_gkb()
# Connect to existing database
kb = connect_gkb("my_knowledge.gkb")
# ============================================
# 2. Create Nodes, Relationship
# ============================================
# Create node
res = kb.add_node(labels=["Person", "Developer"], properties={"name": "Alice", "age": 30})
# Upsert node (find by unique property or create if not exists)
res = kb.upsert_node(labels=["File"], properties={"path": "src/main.py", "type": "code"})
# Create relationship by id
res = kb.add_rel_by_id(from_id=1, to_id=2, type="CAUSES", properties={"confidence": 0.9})
# Create relationship by label
res = kb.add_rel_by_label(from_label="Worker", to_label="Company", type="WORKS_FOR", properties={"since": "2023-01-01"})
# Create relationship by matching properties
res = kb.add_rel_by_property(
from_prop={"name": "Alice"},
to_prop={"name": "Bob"},
type="KNOWS"
)
# ============================================
# 3. Read Nodes, Relationship, Extract subgraph
# ============================================
# Get node by ID
node = kb.get_node_by_id(1)
# Get nodes by specific property (Exact match)
# Without specific conditions, this will get all nodes (use limit to control)
nodes = kb.get_nodes_by_property(properties={"name": "Alice"}, limit=100)
# Get nodes by label
# Without specific conditions, this will get all nodes with this label (use limit to control)
nodes = kb.get_nodes_by_label("Person", limit=100)
# Get all relationships connected to a node
# This will get all relationships for the node (use limit to control)
rels = kb.get_rels_of_node(1, limit=100)
# Get relationships by type
# Without specific conditions, this will get all relationships of this type (use limit to control)
causal_rels = kb.get_rels_by_type("CAUSES", limit=100)
# Get relationships by property
# Without specific conditions, this will get all relationships (use limit to control)
strong_rels = kb.get_rels_by_property(properties={"confidence": 0.9}, limit=100)
# Extract neighborhood (subgraph) around a node with specified hops
subgraph: Graph = kb.get_neighborhood(1, hops=2)
# Find paths between two nodes (Causal chain) by ID
paths: Graph = kb.get_paths(from_id=1, to_id=5, max_hops=3)
# ============================================
# 4. Update Nodes, Relationship
# ============================================
# Update node properties by ID (Merge/Patch)
kb.update_node_by_id(1, properties={"status": "active", "last_updated": "2023-12-30"})
# Update node labels by ID (Add/Remove)
kb.update_node_labels(1, add_labels=["Verified"], remove_labels=["Pending"])
# Update relationship properties by ID
kb.update_rel_by_id(from_id=1, to_id=2, type="CAUSES", properties={"confidence": 0.95})
# ============================================
# 5. Delete Nodes, Relationship
# ============================================
# Delete node by id
kb.delete_node_by_id(1)
# Delete relationship by id
kb.delete_rel_by_id(from_id=1, to_id=2, type="CAUSES")
# Delete node by label
kb.delete_nodes_by_label("Person")
# Delete relationship by type
kb.delete_rels_by_type("CAUSES")
# Delete node by match property condition (Support AND, OR)
kb.delete_nodes_by_property(properties={"status": "inactive"})
# Delete relationship by match property condition (Support AND, OR)
kb.delete_rels_by_property(properties={"confidence": 0.1})
# Delete all nodes
kb.clear_nodes()
# Delete all relationships
kb.clear_rels()
# ============================================
# 6. Search
# ============================================
# Search by cypher (returns Graph object)
results: Graph = kb.cypher_query("MATCH (a:Person)-[r:CAUSES]->(b:Person) RETURN a, r, b")
# Search by bm25 (Full-text search across node/relationship properties)
results: Graph = kb.search_text("Alice engineering background")
# Hybrid retrieval (Graph-enhanced: Cypher + BM25)
results: Graph = kb.hybrid_retrieval(
query="Alice engineering background",
cypher="MATCH (n)-[r:CAUSES]->(m) RETURN n, r, m",
top_k=5,
alpha=0.6 # 60% graph structure, 40% text similarity
)
# ============================================
# 7. Generate Graph Schema
# ============================================
schema: dict = kb.get_schema()
# ============================================
# 8. Stats
# ============================================
stats: dict = kb.get_stats()
# ============================================
# 9. Graph Manipulation
# ============================================
# Work with Graph objects returned from search/extraction
subgraph: Graph = kb.get_neighborhood(1, hops=2)
# Graph objects support the same API as KB
nodes = subgraph.get_nodes_by_label("Person")
rels = subgraph.get_rels_by_type("CAUSES")
nested_subgraph: Graph = subgraph.get_neighborhood(1, hops=1)
# Load Graph into new KB for further analysis
new_kb = create_gkb("analysis.gkb")
new_kb.load_graph(subgraph)
# Merge multiple graphs
combined: Graph = Graph.merge([graph1, graph2, graph3])
# Export/import for persistence
graph_data = subgraph.export()
restored_graph: Graph = Graph.from_data(graph_data)