Sub Stores Guide
Complete guide to using sub stores for advanced memory partitioning and optimization.
Overview
Sub stores allow you to partition memory data into separate vector tables, each with:
- Independent routing rules: Automatically route data based on metadata
- Different embedding services: Use different models and dimensions
- Custom storage configuration: Different index types, database parameters, etc.
- Independent performance optimization: Optimize for different data characteristics
Note: Sub stores are currently only supported with OceanBase vector store.
Quick Start
Basic Configuration
from powermem import Memory
config = {
"vector_store": {
"provider": "oceanbase",
"config": {
"collection_name": "main_memories",
"embedding_model_dims": 1536,
"host": "127.0.0.1",
"port": "2881",
"user": "root@test",
"password": "password",
"db_name": "test_db",
}
},
"embedding": {
"provider": "openai",
"config": {
"api_key": "your-api-key",
"model": "text-embedding-3-large",
"embedding_dims": 1536,
}
},
# Configure sub stores
"sub_stores": [
{
# Sub store 1: Inherits main config
"routing_filter": {"type": "semantic"}
},
{
# Sub store 2: Uses different embedding
"routing_filter": {"type": "working"},
"embedding_model_dims": 768,
"embedding": {
"provider": "qwen",
"config": {
"model": "text-embedding-v4",
"embedding_dims": 768,
"api_key": "your-qwen-key",
}
}
}
]
}
memory = Memory(config=config)
Initialize Sub Store Routing
Important: Before using sub store routing, you must run migration at least once to activate the routing functionality, even if there's no data to migrate:
# Initialize sub store routing (required before first use)
memory.migrate_all_sub_stores(delete_source=False)
This ensures that sub store migration status is properly initialized in the database, enabling automatic routing.
Using Sub Stores
Once initialized, data is automatically routed to the appropriate sub store based on metadata:
# Add data - automatically routed to sub stores
memory.add(
"Python is a programming language",
metadata={"type": "semantic"} # Routes to sub store 1
)
memory.add(
"Buy milk today",
metadata={"type": "working"} # Routes to sub store 2
)
# Search from specific sub store
results = memory.search(
"programming concepts",
filters={"type": "semantic"}, # Searches in sub store 1
limit=5
)
Configuration Options
Required Parameters
routing_filter
Defines which data should be routed to this sub store:
"routing_filter": {
"type": "working", # Single condition
"priority": "high" # Multiple conditions (AND logic)
}
Optional Parameters
collection_name
Custom table name. Defaults to {main_table_name}_sub_{index}:
"collection_name": "memories_important"
embedding_model_dims
Vector dimensions. Defaults to main store dimensions:
"embedding_model_dims": 768
embedding
Sub store specific embedding service:
"embedding": {
"provider": "qwen",
"config": {
"model": "text-embedding-v4",
"embedding_dims": 768,
"api_key": "your-api-key",
}
}
Important: embedding.config.embedding_dims must match embedding_model_dims.
vector_store
Override main store's vector_store configuration:
"vector_store": {
"index_type": "HNSW", # Use HNSW index
"vector_weight": 0.7, # Vector search weight
"fts_weight": 0.3, # Full-text search weight
"host": "different-host", # Use different database
# Any vector_store parameter can be overridden
}
index_type
Index type for this sub store:
"index_type": "HNSW" # Options: "HNSW", "IVF_FLAT", "IVF_PQ"
Data Migration
Migrate Data to Sub Store
# Method 1: Migrate by index
count = memory.migrate_to_sub_store(
sub_store_index=0, # Sub store index
delete_source=False # Keep source data
)
# Method 2: Migrate by name
count = memory.migrate_to_sub_store(
sub_store_name="memories_sub_0",
delete_source=True # Delete source after migration
)
# Method 3: Migrate all sub stores
count = memory.migrate_all_sub_stores(delete_source=False)
Monitor Migration Status
# Check migration status
status = memory.get_sub_store_migration_status("memories_sub_0")
print(f"Status: {status['status']}") # PENDING/MIGRATING/COMPLETED/FAILED
print(f"Progress: {status['migrated_count']}/{status['total_count']}")
print(f"Percentage: {status['progress']}%")
Migration Process
During migration:
- Queries matching records based on
routing_filter - Re-generates vectors using sub store's
embedding_service - Inserts new vectors and payload into sub store
- Optionally deletes source data
Advanced Configuration
Multiple Embedding Dimensions
config = {
"vector_store": {"config": {"embedding_model_dims": 1536}},
"embedding": {
"provider": "openai",
"config": {"model": "text-embedding-3-large", "embedding_dims": 1536}
},
"sub_stores": [
{
"routing_filter": {"priority": "low"},
"embedding_model_dims": 384, # Smaller dimension
"embedding": {
"provider": "qwen",
"config": {"model": "text-embedding-v4", "embedding_dims": 384}
}
},
{
"routing_filter": {"priority": "high"},
"embedding_model_dims": 3072, # Larger dimension
"embedding": {
"provider": "openai",
"config": {"model": "text-embedding-3-large", "embedding_dims": 3072}
}
}
]
}
Different Index Types
config = {
"vector_store": {
"config": {"index_type": "IVF_FLAT"} # Main store: balanced
},
"sub_stores": [
{
"routing_filter": {"access_pattern": "hot"},
"vector_store": {
"index_type": "HNSW", # Fast retrieval
"vector_weight": 0.8,
"fts_weight": 0.2,
}
},
{
"routing_filter": {"access_pattern": "cold"},
"vector_store": {
"index_type": "IVF_PQ" # Compressed storage
}
}
]
}
Custom Database Configuration
config = {
"vector_store": {...},
"sub_stores": [
{
"routing_filter": {"tenant": "enterprise_a"},
"collection_name": "memories_enterprise_a",
"vector_store": {
"database": "tenant_a_db", # Different database
"host": "db-a.example.com", # Different host
}
}
]
}
Common Patterns
Pattern 1: By Memory Type
"sub_stores": [
{
"routing_filter": {"type": "episodic"},
"embedding_model_dims": 1536,
},
{
"routing_filter": {"type": "semantic"},
"embedding_model_dims": 768,
"embedding": {...} # Different model
}
]
Pattern 2: By Priority Level
"sub_stores": [
{
"routing_filter": {"priority": "high"},
"vector_store": {
"index_type": "HNSW" # Fast queries
}
},
{
"routing_filter": {"priority": "low"},
"vector_store": {
"index_type": "IVF_PQ" # Save resources
}
}
]
Pattern 3: By Access Frequency
"sub_stores": [
{
"routing_filter": {"frequency": "hot"},
"vector_store": {
"index_type": "HNSW",
"vector_weight": 0.7,
"fts_weight": 0.3
}
},
{
"routing_filter": {"frequency": "cold"},
"vector_store": {
"index_type": "IVF_FLAT"
}
}
]
Important Notes
Initialize Before Use
Critical: Before using sub store routing, you must initialize the migration system at least once:
memory.migrate_all_sub_stores(delete_source=False)
This is required even if you have no existing data to migrate. It initializes the sub store status in the database, which enables the routing mechanism. Without this step, all data will continue to go to the main store.
Dimension Consistency
Ensure both dimension parameters match:
{
"embedding_model_dims": 768, # Database table structure
"embedding": {
"config": {
"embedding_dims": 768, # API returns this dimension
}
}
}
Mismatched dimensions will cause errors: "expected 1536 dimensions, not 768"
Routing Rules
- Sub store
routing_filtermatches against memorymetadata - All filter conditions must match (AND logic)
- If no sub store matches, data goes to main store
- Only exact matches are supported (no OR/NOT logic)
Related Documentation
- Getting Started - Quick start
- Configuration Guide - Basic configuration
- Integrations Guide - Embedding services
Examples
See complete examples:
examples/sub_store_simple.py- Basic sub store usageexamples/multi_agent.py- Multi-agent with sub stores