Labeled Meta Property Graphs (LMPG): A Property-Centric Approach to Graph Database Architecture
Discover how LMPG transforms graph databases by treating properties as first-class citizens rather than simple node attributes. This comprehensive technical guide explores RushDB's groundbreaking architecture that enables automatic schema evolution, property-first queries, and cross-domain analytics impossible in traditional property graphs or RDF systems.
In the evolving landscape of database technologies, graph databases have emerged as powerful solutions for managing interconnected data. However, most graph databases still require developers to think in terms of nodes, edges, and complex query languages. RushDB introduces a paradigm shift with its Labeled Meta Property Graph (LMPG) architecture – a revolutionary approach that makes properties first-class citizens and enables unprecedented flexibility in data modeling and querying.
What sets LMPG apart is its unified query interface that allows a single Data Transfer Object (DTO) to query Records, Labels, Properties, Relationships, and Available Values across any subgraph perspective. This creates what we call "database self-awareness" – the ability for the system to introspect and optimize queries dynamically based on the property-centric architecture.
Traditional property graphs, while powerful, force developers into rigid thinking patterns:
Schema-first mindset: You must define your data structure before storing data
Query complexity: Learning Cypher, Gremlin, or other graph query languages
Relationship overhead: Manually defining and maintaining relationships
Type constraints: Rigid type systems that don't adapt to evolving data
Consider a typical e-commerce scenario in a traditional property graph:
cypher
// Traditional approach - you must know the schema
MATCH (product:Product)-[:BELONGS_TO]->(category:Category)
WHERE product.price > 100 AND category.name = 'Electronics'
RETURN product.name, product.price
RushDB employs a sophisticated Breadth-First Search (BFS) algorithm to automatically convert hierarchical JSON data into LMPG structures. This process eliminates the need for manual schema design while preserving data relationships.
// Find all items with price > 1000 across different types
MATCH (n)
WHERE (n:Car OR n:House OR n:Jewelry)
AND n.price > 1000
RETURN n.name, n.price, labels(n)
# Same query in RushDB - discover ANY record with price > 1000
from rushdb import RushDB
db = RushDB("RUSHDB_API_TOKEN")
results = db.records.find({
"where": {
"price": { "$gt": 1000 }
}
})
Advantages:
Automatically finds all records regardless of type
Traditional database performance degrades with data size and query complexity. LMPG maintains consistent performance through its revolutionary perforating query architecture that skips expensive operations by leveraging properties as dynamic indices.
1. Property-First Indexing:
Text
Traditional JOIN: O(n × m × log(k))
LMPG Traversal: O(p + r)
Where:
n, m, k = table/node sizes
p = number of properties
r = number of relevant records
2. Perforating Query Execution:
Diagram
3. Dynamic Index Management:
Properties act as living indices that:
Self-organize with controllable overhead
Adapt to data distribution in real-time
4. Handful Index Optimization:
sql
-- Auto-generated Neo4j indexes for each property
CREATE INDEX property_name_string FOR (n:__RUSHDB__LABEL__PROPERTY__)
ON (n.name, n.type, n.projectId, n.metadata);
CREATE INDEX record_lookup FOR (n:__RUSHDB__LABEL__RECORD__)
ON (n.__RUSHDB__KEY__ID__, n.__RUSHDB__KEY__PROJECT__ID__);
RushDB's revolutionary graph perforating architecture achieves unprecedented data observability through a single unified query interface. Unlike traditional databases that require separate APIs for different data perspectives, LMPG enables one query to simultaneously access Records, Labels, Properties, Values, and Relationships.
# Get actual department records matching criteria
records = db.records.find(QUERY)
Generated Cypher Query:
cypher
MATCH (record:__RUSHDB__LABEL__RECORD__:`DEPARTMENT` { __RUSHDB__KEY__PROJECT__ID__: $projectId })
WHERE (any(value IN record.name WHERE value =~ "(?i).*e.*"))
OPTIONAL MATCH (record)--(record1:PROJECT)
WHERE ((any(value IN record1.budget WHERE value <= 10000000) XOR
any(value IN record1.budget WHERE value >= 15000000)))
OPTIONAL MATCH (record1)--(record2:EMPLOYEE)
WHERE (any(value IN record2.salary WHERE value >= 300000))
WITH record, record1, record2
WHERE record IS NOT NULL AND (record1 IS NOT NULL AND record2 IS NOT NULL)
RETURN record
SKIP 0 LIMIT 1000
# Discover all entity types matching the criteria
labels = db.labels.find(QUERY)
Generated Cypher Query:
cypher
MATCH (record:__RUSHDB__LABEL__RECORD__ { __RUSHDB__KEY__PROJECT__ID__: $projectId })
WHERE (any(value IN record.name WHERE value =~ "(?i).*e.*"))
OPTIONAL MATCH (record)--(record1:PROJECT)
WHERE ((any(value IN record1.budget WHERE value <= 10000000) XOR
any(value IN record1.budget WHERE value >= 15000000)))
OPTIONAL MATCH (record1)--(record2:EMPLOYEE)
WHERE (any(value IN record2.salary WHERE value >= 300000))
WITH record, record1, record2
WHERE record IS NOT NULL AND (record1 IS NOT NULL AND record2 IS NOT NULL)
WITH DISTINCT record, [label IN labels(record) WHERE label <> "__RUSHDB__LABEL__RECORD__"] as recordLabels
RETURN count(recordLabels) as total, recordLabels[0] as label
# Discover available properties across matching entities
properties = db.properties.find(QUERY)
Generated Cypher Queries:
cypher
-- Get entity-specific properties
MATCH (record:__RUSHDB__LABEL__RECORD__:`DEPARTMENT` { __RUSHDB__KEY__PROJECT__ID__: $projectId })
WHERE (any(value IN record.name WHERE value =~ "(?i).*e.*"))
OPTIONAL MATCH (record)--(record1:PROJECT)
WHERE ((any(value IN record1.budget WHERE value <= 10000000) XOR
any(value IN record1.budget WHERE value >= 15000000)))
OPTIONAL MATCH (record1)--(record2:EMPLOYEE)
WHERE (any(value IN record2.salary WHERE value >= 300000))
WITH record, record1, record2
WHERE record IS NOT NULL AND (record1 IS NOT NULL AND record2 IS NOT NULL)
UNWIND keys(record) as propertyName
RETURN collect(DISTINCT propertyName) as fields
-- Get global property metadata
MATCH (property:__RUSHDB__LABEL__PROPERTY__ { projectId: $id })
RETURN collect(DISTINCT property { .id, .metadata, .name, .type, .projectId }) as properties
# Get distinct values and ranges for specific properties
values = db.properties.values(property_id, QUERY)
Generated Cypher Query:
cypher
MATCH (record:__RUSHDB__LABEL__RECORD__:`DEPARTMENT` { __RUSHDB__KEY__PROJECT__ID__: $projectId })
<-[value:__RUSHDB__RELATION__VALUE__]-(property:__RUSHDB__LABEL__PROPERTY__ { id: $id })
WHERE (any(value IN record.name WHERE value =~ "(?i).*e.*"))
OPTIONAL MATCH (record)--(record1:PROJECT)
WHERE ((any(value IN record1.budget WHERE value <= 10000000) XOR
any(value IN record1.budget WHERE value >= 15000000)))
OPTIONAL MATCH (record1)--(record2:EMPLOYEE)
WHERE (any(value IN record2.salary WHERE value >= 300000))
AND record[property.name] IS NOT NULL AND property.type <> 'vector'
WITH property, record, record1, record2
WHERE record IS NOT NULL AND (record1 IS NOT NULL AND record2 IS NOT NULL)
WITH record[property.name] AS propValue, property.type AS propType
ORDER BY record.__RUSHDB__KEY__ID__
WITH apoc.coll.toSet(apoc.coll.flatten(collect(DISTINCT propValue))) AS values, propType as type
UNWIND values AS v
WITH values, type,
min(CASE type WHEN 'datetime' THEN datetime(v) ELSE toFloatOrNull(v) END) AS minValue,
max(CASE type WHEN 'datetime' THEN datetime(v) ELSE toFloatOrNull(v) END) AS maxValue
RETURN {
values: values[0..1000],
min: CASE type WHEN 'datetime' THEN toString(minValue) ELSE minValue END,
max: CASE type WHEN 'datetime' THEN toString(maxValue) ELSE maxValue END,
type: type
} AS result
# Discover relationships between matching entities
relationships = db.relationships.find(QUERY)
Generated Cypher Queries:
cypher
-- Get relationship details
MATCH (record:__RUSHDB__LABEL__RECORD__:`DEPARTMENT` { __RUSHDB__KEY__PROJECT__ID__: $projectId })
WHERE (any(value IN record.name WHERE value =~ "(?i).*e.*"))
OPTIONAL MATCH (record)--(record1:PROJECT)
WHERE ((any(value IN record1.budget WHERE value <= 10000000) XOR
any(value IN record1.budget WHERE value >= 15000000)))
OPTIONAL MATCH (record1)--(record2:EMPLOYEE)
WHERE (any(value IN record2.salary WHERE value >= 300000))
WITH record, record1, record2
WHERE record IS NOT NULL AND (record1 IS NOT NULL AND record2 IS NOT NULL)
MATCH (record)-[rel]-(neighbor:__RUSHDB__LABEL__RECORD__)
SKIP 0 LIMIT 1000
RETURN DISTINCT
CASE
WHEN startNode(rel) = record THEN {
sourceId: record.__RUSHDB__KEY__ID__,
sourceLabel: [label IN labels(record) WHERE label <> "__RUSHDB__LABEL__RECORD__"][0],
targetId: neighbor.__RUSHDB__KEY__ID__,
targetLabel: [label IN labels(neighbor) WHERE label <> "__RUSHDB__LABEL__RECORD__"][0],
type: type(rel)
}
ELSE {
sourceId: neighbor.__RUSHDB__KEY__ID__,
sourceLabel: [label IN labels(neighbor) WHERE label <> "__RUSHDB__LABEL__RECORD__"][0],
targetId: record.__RUSHDB__KEY__ID__,
targetLabel: [label IN labels(record) WHERE label <> "__RUSHDB__LABEL__RECORD__"][0],
type: type(rel)
}
END AS relation
-- Get relationship count
MATCH (record:__RUSHDB__LABEL__RECORD__:`DEPARTMENT` { __RUSHDB__KEY__PROJECT__ID__: $projectId })
WHERE (any(value IN record.name WHERE value =~ "(?i).*e.*"))
OPTIONAL MATCH (record)--(record1:PROJECT)
WHERE ((any(value IN record1.budget WHERE value <= 10000000) XOR
any(value IN record1.budget WHERE value >= 15000000)))
OPTIONAL MATCH (record1)--(record2:EMPLOYEE)
WHERE (any(value IN record2.salary WHERE value >= 300000))
WITH record, record1, record2
WHERE record IS NOT NULL AND (record1 IS NOT NULL AND record2 IS NOT NULL)
MATCH (record)-[rel]-(target:__RUSHDB__LABEL__RECORD__)
RETURN count(DISTINCT rel) as total
The key insight is that RushDB's property-centric architecture allows the same filtered record set to be analyzed from multiple perspectives without re-executing the expensive traversal logic. The WHERE clauses are shared across all perspective queries, enabling massive optimization through result set reuse.
The most transformative aspect of LMPG is its unified query interface that eliminates the complexity of traditional database interactions:
Diagram
Key Benefits of the Unified Interface:
Single DTO, infinite perspectives: One query interface for all data aspects
Properties as dynamic indices: Self-optimizing performance without manual tuning
Database self-awareness: Automatic adaptation to data patterns and usage
Perforating query architecture: Skip expensive operations for consistent performance
Cross-domain insights: Discover relationships across unrelated data domains
This revolutionary approach means developers no longer need to learn separate APIs for different database operations. Whether you need records, schema information, property metadata, value ranges, or relationship mappings - it all comes from the same intuitive JSON query structure demonstrated in the Graph Perforating section above.
The unified query interface opens up entirely new possibilities across multiple domains, enabling sophisticated applications without writing complex database code:
1. Cataloging Indeterminate Data
Challenge: Scientific datasets, IoT streams, and user-generated content often have unpredictable schemas and evolving structures.
LMPG Solution: Automatic schema adaptation with unified querying across all data perspectives.
# Automatically catalog any scientific data structure
research_data = db.records.create({
"label": "Experiment",
"data": {
"experiment_id": "EXP-2024-001",
"temperature": 23.5,
"unexpected_compound": "C8H10N4O2", # New discovery
"readings": [1.2, 3.4, 5.6],
"metadata": {
"researcher": "Dr. Smith",
"equipment": "Spectrometer-X200"
}
}
})
# Later, discover all experiments with any temperature data
temperature_studies = db.records.find({
"where": {
"temperature": { "$exists": True }
}
})
# Automatically discover new property types
new_properties = db.properties.find() # Finds "unexpected_compound" property
property_values = db.properties.values(compound_property_id) # Get all compound values
Result: Zero-configuration data cataloging that automatically adapts to new discoveries.
2. AI-Driven Scientific Research Loops
Challenge: Modern AI research requires iterative data exploration, hypothesis generation, and validation across evolving datasets.
LMPG Solution: Unified interface enables AI agents to autonomously explore data relationships and generate research hypotheses.
# AI research agent workflow
class ResearchAgent:
def explore_correlations(self):
# Discover all numeric properties
numeric_props = db.properties.find({"where": {"type": "number"}})
for prop in numeric_props["data"]:
# Get value distributions
distribution = db.properties.values(prop["id"])
# Find correlating entities
correlated_records = db.records.find({
"where": {prop["name"]: {"$gte": distribution["data"]["min"]}}
})
# Discover relationship patterns
relationships = db.relationships.find(correlated_records["query"])
# Generate hypothesis based on discovered patterns
yield self.generate_hypothesis(prop, distribution, relationships)
def validate_hypothesis(self, hypothesis):
# Use unified interface to test hypothesis across all data perspectives
validation_query = {
"where": hypothesis["conditions"]
}
results = {
"records": db.records.find(validation_query),
"patterns": db.relationships.find(validation_query),
"distributions": [db.properties.values(p) for p in hypothesis["properties"]]
}
return self.analyze_validation(results)
Result: AI agents can autonomously discover patterns, generate hypotheses, and validate theories through iterative data exploration.
3. Unbeatable E-commerce Filtering (Zero Code)
Challenge: Building sophisticated product filtering requires complex database queries and extensive frontend logic.
LMPG Solution: Unified interface automatically generates filters from data, requires zero manual configuration.
# Auto-generate complete filtering interface
class AutoFilter:
def __init__(self, category="Product"):
self.category = category
def get_filter_options(self):
# Single query gets all filter possibilities
base_query = {"labels": [self.category]}
return {
# Available products
"products": db.records.find(base_query),
# Auto-discovered filter categories
"categories": db.labels.find(base_query),
# All filterable properties
"properties": db.properties.find(base_query),
# Value ranges for each property
"ranges": {
prop["name"]: db.properties.values(prop["id"], base_query)
for prop in db.properties.find(base_query)["data"]
}
}
def apply_filters(self, user_filters):
# User filters automatically become query conditions
filtered_query = {
"labels": [self.category],
"where": user_filters # Direct mapping from UI
}
return {
"products": db.records.find(filtered_query),
"updated_ranges": self.get_updated_ranges(filtered_query),
"related_categories": db.labels.find(filtered_query)
}
# Frontend automatically adapts to any product catalog
auto_filter = AutoFilter("Product")
filter_ui = auto_filter.get_filter_options()
# User applies filters - no backend code needed
user_selection = {
"price": {"$gte": 100, "$lte": 500},
"rating": {"$gte": 4.0},
"brand": {"$in": ["Nike", "Adidas"]},
"CATEGORY": {
"trending": True
}
}
filtered_results = auto_filter.apply_filters(user_selection)
Result: Complete e-commerce filtering interface that automatically adapts to any product catalog without writing filtering logic.
4. Real-Time Analytical Workloads
Challenge: Traditional analytical queries require complex aggregations, joins, and pre-computed views.
LMPG Solution: Unified interface enables real-time analytics across any data dimension without pre-configuration.
# Real-time business intelligence dashboard
class RealTimeAnalytics:
def __init__(self):
self.metrics = {}
def get_sales_insights(self, time_range):
base_query = {
"labels": ["Sale"],
"where": {
"timestamp": {
"$gte": time_range["start"],
"$lte": time_range["end"]
}
}
}
# Single unified call gets all analytics
return {
# Core sales data
"sales": db.records.find(base_query),
# Auto-discovered segments
"segments": db.labels.find(base_query),
# All sales dimensions
"dimensions": db.properties.find(base_query),
# Value distributions per dimension
"distributions": {
"revenue": db.properties.values("revenue", base_query),
"products": db.properties.values("product_id", base_query),
"regions": db.properties.values("region", base_query),
"channels": db.properties.values("channel", base_query)
},
# Relationship insights
"correlations": db.relationships.find(base_query)
}
def drill_down(self, dimension, value):
# Dynamic drill-down without predefined hierarchies
drill_query = {
"where": {
dimension: value,
"timestamp": {"$gte": "2024-01-01"}
}
}
return {
"details": db.records.find(drill_query),
"related_dimensions": db.properties.find(drill_query),
"cross_correlations": db.relationships.find(drill_query)
}
# Usage: Real-time dashboard that adapts to any business
analytics = RealTimeAnalytics()
# Get comprehensive sales insights
insights = analytics.get_sales_insights({
"start": "2024-01-01",
"end": "2024-12-31"
})
# Dynamic drill-down based on user clicks
region_details = analytics.drill_down("region", "North America")
product_details = analytics.drill_down("product_category", "Electronics")
Result: Real-time analytics dashboards that automatically discover and visualize any business dimension without pre-configuration.
5. Healthcare Data Integration
Challenge: Medical data comes from disparate systems with different schemas and requires complex integration.
LMPG Solution: Automatic schema harmonization enables unified patient views across all medical systems.
# Unified patient data across all medical systems
class MedicalDataIntegration:
def integrate_patient_data(self, patient_id):
# Query across all medical record types
base_query = {
"where": {
"patient_id": patient_id
}
}
return {
# All medical records
"records": db.records.find(base_query),
# Auto-discovered record types
"record_types": db.labels.find(base_query),
# All medical properties
"medical_fields": db.properties.find(base_query),
# Value ranges for medical metrics
"vital_ranges": {
field["name"]: db.properties.values(field["id"], base_query)
for field in db.properties.find(base_query)["data"]
if field["name"] in ["blood_pressure", "heart_rate", "temperature"]
},
# Medical relationships
"care_relationships": db.relationships.find(base_query)
}
def find_similar_cases(self, symptoms, demographics):
# Cross-system case similarity without predefined schemas
similarity_query = {
"where": {
**symptoms, # Any symptom properties
**demographics, # Any demographic properties
}
}
return {
"similar_patients": db.records.find(similarity_query),
"common_patterns": db.relationships.find(similarity_query),
"outcome_distributions": db.properties.values("outcome", similarity_query)
}
# Usage: Instant integration across any medical system
medical = MedicalDataIntegration()
# Complete patient view from all systems
patient_data = medical.integrate_patient_data("PAT-12345")
# Find similar cases for treatment planning
similar_cases = medical.find_similar_cases(
symptoms={"chest_pain": True, "shortness_of_breath": True},
demographics={"age": {"$between": [45, 65]}, "gender": "male"}
)
Result: Unified patient views and intelligent case matching across any medical system without manual integration work.
These examples demonstrate how LMPG's unified query interface eliminates the complexity barrier that typically prevents sophisticated data applications. Developers can now build AI-driven research tools, zero-code filtering interfaces, real-time analytics, and cross-system integrations using the same simple JSON query structure, enabling unprecedented innovation across all domains.
SELECT p.name, p.price, c.name as category
FROM products p
JOIN categories c ON p.category_id = c.id
JOIN product_attributes pa ON p.id = pa.product_id
JOIN attributes a ON pa.attribute_id = a.id
WHERE p.price > 100
AND a.name = 'color'
AND pa.value = 'red';
The Labeled Meta Property Graph represents a fundamental shift toward property-centric data modeling. As data becomes increasingly interconnected and diverse, LMPG's ability to:
Automatically discover relationships through shared properties
Adapt to evolving schemas without migration overhead
Enable cross-domain insights through property traversal
Simplify complex queries with intuitive JSON syntax
Integrate vector operations for AI-powered applications
Provide unified query interface across all data perspectives
Self-optimize through property-based indexing for massive scale
...makes it the ideal architecture for the next generation of data-intensive applications.
RushDB's Labeled Meta Property Graph architecture represents a paradigm shift in database design. By making properties first-class citizens, LMPG enables:
Zero-configuration data modeling with automatic schema inference
Automatic relationship discovery through property overlap analysis
Cross-domain query capabilities with unified interface
Simplified development workflows using intuitive JSON syntax
AI-ready data structures with native vector support
Database self-awareness through dynamic property indexing
Perforating query performance that skips expensive operations
Multi-perspective data access from single query interface
The future of databases is not about forcing data into predefined structures, but about letting the data define its own relationships while providing intelligent optimization. LMPG makes this vision a reality, enabling developers to focus on building features rather than fighting with database schemas.
As applications become increasingly complex and data sources multiply, LMPG's property-centric approach will become the standard for managing interconnected data at scale. The question isn't whether to adopt this architecture – it's how quickly you can start leveraging its power for your applications.
Key Takeaways:
Single DTO, infinite perspectives: One query interface for all data aspects
Properties as dynamic indices: Self-optimizing performance without manual tuning
Database self-awareness: Automatic adaptation to data patterns and usage
Perforating query architecture: Skip expensive operations for consistent performance
Cross-domain insights: Discover relationships across unrelated data domains