OQL Query Guide: 20 Real Examples
OQL (Ontology Query Language) is the declarative query language of the coomia-dip platform, purpose-built for the Ontology data model. It is more business-semantic than SQL, supporting joint queries across objects, relations, and properties, as well as graph traversal, aggregation, and reasoning integration. This article covers OQL's full query capabilities through 20 real-world examples, from basics to advanced patterns.
“Series: S12 Developer Tutorials · Article 6 | Level: Intermediate | Reading Time: 15 min
OQL Query Guide: 20 Real Examples
#TL;DR
OQL (Ontology Query Language) is the declarative query language of the coomia-dip platform, purpose-built for the Ontology data model. It is more business-semantic than SQL, supporting joint queries across objects, relations, and properties, as well as graph traversal, aggregation, and reasoning integration. This article covers OQL's full query capabilities through 20 real-world examples, from basics to advanced patterns.
#1. OQL Overview
#1.1 What is OQL?
OQL is the native query language of the coomia-dip platform, running on the Control Layer (Control Layer). Unlike traditional SQL, OQL uses Ontology as its core abstraction: you query "objects" and "relations," not "tables" and "rows."
SQL: SELECT * FROM projects WHERE status = 'active'
OQL: FIND Project WHERE status = 'active'
#1.2 Key Differences Between OQL and SQL
| Feature | SQL | OQL |
|---|---|---|
| Query Target | Tables / Rows | Objects / Relations |
| Join Method | JOIN | TRAVERSE |
| Data Model | Relational | Ontology |
| Graph Traversal | Multi-level JOIN | Native TRAVERSE |
| Permission Filtering | Manual WHERE | Automatic ABAC Integration |
| Type Safety | Weak | Schema-enforced |
#1.3 OQL Execution Architecture
Client (SDK / API)
│
▼
Control Layer (gRPC)
│ ① Parse OQL → AST
│ ② Schema Validation
│ ③ Permission Filter Injection
│ ④ Query Optimization
▼
Data Layer (Doris / Iceberg)
│ ⑤ Execute Query
▼
Result Set → Object Mapping
#2. Environment Setup
#2.1 Install the SDK
pip install ontology-sdk>=1.0.0
#2.2 Initialize Connection
from ontology_sdk import OntoPlatform
platform = OntoPlatform(
control_plane_url="localhost:50051",
data_plane_url="localhost:50052",
auth_token="your-token"
)
# Get OQL client
oql = platform.oql
#2.3 Sample Data Model
All examples in this article are based on the following Ontology model:
object_types:
- Employee:
properties: [name, email, department, salary, hire_date, level]
- Project:
properties: [name, status, priority, budget, start_date, end_date]
- Department:
properties: [name, code, location, head_count]
- Task:
properties: [title, status, assignee_rid, due_date, story_points]
- Customer:
properties: [name, industry, region, annual_revenue, tier]
relations:
- works_in: Employee -> Department
- participates_in: Employee -> Project
- owns_project: Department -> Project
- has_task: Project -> Task
- assigned_to: Task -> Employee
- serves: Project -> Customer
#3. Basic Queries (Examples 1-5)
#Example 1: Simple Object Query
Find all in-progress projects:
results = oql.execute("""
FIND Project
WHERE status = 'in_progress'
SELECT name, priority, budget
ORDER BY priority DESC
""")
for project in results:
print(f"{project.name} | Priority: {project.priority} | Budget: {project.budget}")
Output:
Smart Factory Monitoring | Priority: critical | Budget: 5000000
Supply Chain Optimization | Priority: high | Budget: 3200000
Customer 360 Profile | Priority: medium | Budget: 1800000
#Example 2: Multi-Condition Filtering
Find high-salary senior employees:
results = oql.execute("""
FIND Employee
WHERE salary > 30000
AND level IN ('senior', 'staff', 'principal')
AND department != 'HR'
SELECT name, level, salary, department
ORDER BY salary DESC
LIMIT 20
""")
Supported OQL Operators:
- Comparison:
=,!=,>,<,>=,<= - Set:
IN,NOT IN - Pattern:
LIKE,CONTAINS,STARTS_WITH - Null:
IS NULL,IS NOT NULL - Logical:
AND,OR,NOT
#Example 3: Property Projection and Aliases
results = oql.execute("""
FIND Project
WHERE status = 'in_progress'
SELECT
name AS project_name,
budget AS total_budget,
(end_date - start_date) AS duration_days,
priority
""")
#Example 4: Paginated Queries
# Page 1
page1 = oql.execute("""
FIND Employee
WHERE department = 'Engineering'
SELECT name, email, level
ORDER BY hire_date ASC
LIMIT 20 OFFSET 0
""")
# Page 2
page2 = oql.execute("""
FIND Employee
WHERE department = 'Engineering'
SELECT name, email, level
ORDER BY hire_date ASC
LIMIT 20 OFFSET 20
""")
# SDK-wrapped pagination
paginator = oql.paginate(
query="FIND Employee WHERE department = 'Engineering'",
page_size=20
)
for page in paginator:
for emp in page.results:
print(emp.name)
print(f"--- Page {page.page_number} of {page.total_pages} ---")
#Example 5: Fuzzy Search and Full-Text Retrieval
# Property pattern matching
results = oql.execute("""
FIND Project
WHERE name LIKE '%supply chain%'
OR description CONTAINS 'optimization'
SELECT name, description
""")
# Full-text search mode
results = oql.execute("""
FIND Project
SEARCH 'supply chain risk warning'
SELECT name, description, _score
ORDER BY _score DESC
LIMIT 10
""")
#4. Relation Traversal Queries (Examples 6-10)
#Example 6: Single-Level Relation Traversal
Find all employees in a specific department:
results = oql.execute("""
FIND Employee
TRAVERSE works_in -> Department
WHERE Department.name = 'Engineering'
SELECT Employee.name, Employee.level, Employee.salary
""")
Equivalent gRPC call via SDK:
dept = platform.objects.get("Department", filters={"name": "Engineering"})
employees = platform.relations.get_related(
source_rid=dept.rid,
relation_type="works_in",
direction="inbound"
)
#Example 7: Multi-Level Relation Traversal
Find all employees involved in projects for a specific customer:
results = oql.execute("""
FIND Employee
TRAVERSE participates_in -> Project
TRAVERSE serves -> Customer
WHERE Customer.name = 'Huawei Technologies'
SELECT
Employee.name AS employee_name,
Project.name AS project_name,
Customer.name AS customer_name
""")
#Example 8: Reverse Relation Traversal
Find all tasks assigned to an employee and their parent projects:
results = oql.execute("""
FIND Task
TRAVERSE assigned_to -> Employee
WHERE Employee.name = 'John Smith'
INCLUDE
TRAVERSE has_task <- Project
SELECT Project.name AS project_name
SELECT Task.title, Task.status, Task.due_date, project_name
ORDER BY Task.due_date ASC
""")
#Example 9: Relation Property Filtering
results = oql.execute("""
FIND Employee
TRAVERSE participates_in -> Project
WHERE participates_in.role = 'tech_lead'
AND Project.status = 'in_progress'
SELECT
Employee.name,
participates_in.role,
participates_in.joined_date,
Project.name AS project_name
""")
#Example 10: Graph Path Query
Find connection paths between two objects:
results = oql.execute("""
PATH FROM Employee WHERE name = 'John Smith'
TO Customer WHERE name = 'Huawei Technologies'
MAX_DEPTH 4
VIA [participates_in, serves, owns_project, works_in]
""")
for path in results:
print(" -> ".join([node.type_name + ":" + node.name for node in path.nodes]))
Output:
Employee:John Smith -> Project:Smart Factory Monitoring -> Customer:Huawei Technologies
Employee:John Smith -> Department:Engineering -> Project:Supply Chain Optimization -> Customer:Huawei Technologies
#5. Aggregation and Analytics Queries (Examples 11-15)
#Example 11: Basic Aggregation
results = oql.execute("""
FIND Employee
GROUP BY department
AGGREGATE
COUNT(*) AS total_count,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary
ORDER BY avg_salary DESC
""")
for row in results:
print(f"{row.department}: {row.total_count} employees, "
f"avg salary: {row.avg_salary:.0f}")
#Example 12: Multi-Dimensional Aggregation
results = oql.execute("""
FIND Task
TRAVERSE has_task <- Project
GROUP BY Project.name, Task.status
AGGREGATE
COUNT(*) AS task_count,
SUM(Task.story_points) AS total_points
ORDER BY Project.name, Task.status
""")
#Example 13: Time-Series Aggregation
results = oql.execute("""
FIND Employee
GROUP BY DATE_TRUNC('month', hire_date) AS hire_month
AGGREGATE
COUNT(*) AS new_hires
WHERE hire_date >= '2025-01-01'
ORDER BY hire_month ASC
""")
for row in results:
bar = '#' * row.new_hires
print(f"{row.hire_month}: {bar} ({row.new_hires})")
#Example 14: HAVING Clause Filtering
results = oql.execute("""
FIND Project
TRAVERSE has_task -> Task
GROUP BY Project.name
AGGREGATE
COUNT(*) AS total_tasks,
COUNT(CASE WHEN Task.status = 'done' THEN 1 END) AS done_tasks,
ROUND(
COUNT(CASE WHEN Task.status = 'done' THEN 1 END) * 100.0
/ COUNT(*), 1
) AS completion_rate
HAVING total_tasks > 5 AND completion_rate < 50
ORDER BY completion_rate ASC
""")
print("=== Projects Behind Schedule ===")
for row in results:
print(f"{row.project_name}: {row.completion_rate}% "
f"({row.done_tasks}/{row.total_tasks})")
#Example 15: Cross-Object Statistics
results = oql.execute("""
FIND Department
INCLUDE
TRAVERSE works_in <- Employee
AGGREGATE COUNT(*) AS emp_count, AVG(Employee.salary) AS avg_salary
INCLUDE
TRAVERSE owns_project <- Project
WHERE Project.status = 'in_progress'
AGGREGATE COUNT(*) AS active_projects, SUM(Project.budget) AS total_budget
SELECT
Department.name,
Department.location,
emp_count,
avg_salary,
active_projects,
total_budget
ORDER BY total_budget DESC
""")
#6. Advanced Queries (Examples 16-20)
#Example 16: Subqueries
results = oql.execute("""
FIND Employee
WHERE salary > (
FIND Employee
WHERE department = $self.department
AGGREGATE AVG(salary)
)
SELECT name, department, salary
ORDER BY department, salary DESC
""")
#Example 17: WITH Precomputation (CTE Equivalent)
results = oql.execute("""
WITH dept_stats AS (
FIND Employee
GROUP BY department
AGGREGATE
AVG(salary) AS avg_salary,
COUNT(*) AS emp_count
)
FIND Employee
JOIN dept_stats ON Employee.department = dept_stats.department
WHERE Employee.salary > dept_stats.avg_salary * 1.5
SELECT
Employee.name,
Employee.department,
Employee.salary,
dept_stats.avg_salary AS dept_avg,
ROUND(Employee.salary / dept_stats.avg_salary * 100, 1) AS ratio_pct
ORDER BY ratio_pct DESC
""")
#Example 18: Conditional Expressions
results = oql.execute("""
FIND Project
SELECT
name,
budget,
CASE
WHEN budget > 5000000 THEN 'Large'
WHEN budget > 2000000 THEN 'Medium'
WHEN budget > 500000 THEN 'Small'
ELSE 'Micro'
END AS project_scale,
CASE
WHEN end_date < NOW() AND status != 'done' THEN 'Overdue'
WHEN end_date < NOW() + INTERVAL '7 days' THEN 'Due Soon'
ELSE 'On Track'
END AS deadline_status
ORDER BY budget DESC
""")
#Example 19: Parameterized Queries and Injection Prevention
# Parameterized query — prevents OQL injection
results = oql.execute(
"""
FIND Employee
WHERE department = :dept
AND level IN :levels
AND hire_date >= :start_date
SELECT name, level, salary
ORDER BY salary DESC
LIMIT :page_size OFFSET :offset
""",
params={
"dept": "Engineering",
"levels": ["senior", "staff", "principal"],
"start_date": "2024-01-01",
"page_size": 20,
"offset": 0
}
)
# Batch parameterized execution
batch_results = oql.execute_batch(
"FIND Employee WHERE department = :dept AGGREGATE COUNT(*) AS cnt",
params_list=[
{"dept": "Engineering"},
{"dept": "Product"},
{"dept": "Design"},
]
)
for dept_result in batch_results:
print(f"{dept_result.params['dept']}: {dept_result.results[0].cnt} employees")
#Example 20: Reasoning-Integrated Queries
OQL can integrate with the Intelligence Layer reasoning engine:
# Rule-based reasoning query
results = oql.execute("""
FIND Employee
WHERE INFERRED risk_level = 'high'
SELECT
name, department,
INFERRED risk_level,
INFERRED risk_factors,
INFERRED recommended_actions
""")
# The INFERRED keyword triggers the reasoning engine
# Intelligence Layer computes derived properties based on rules and knowledge graph
# Knowledge graph reasoning query
results = oql.execute("""
FIND Customer
WHERE INFERRED churn_probability > 0.7
TRAVERSE serves <- Project
SELECT
Customer.name,
Customer.tier,
INFERRED Customer.churn_probability,
INFERRED Customer.churn_reason,
Project.name AS related_project
ORDER BY INFERRED Customer.churn_probability DESC
""")
for row in results:
print(f"WARNING: {row.customer_name} (Churn probability: {row.churn_probability:.1%})")
print(f" Reason: {row.churn_reason}")
print(f" Related project: {row.related_project}")
#7. OQL Best Practices
#7.1 Performance Optimization
# Bad: full scan then filter
oql.execute("FIND Employee SELECT * WHERE salary > 50000")
# Good: select only needed fields, filter first
oql.execute("""
FIND Employee
WHERE salary > 50000
SELECT name, salary, level
LIMIT 100
""")
# Bad: N+1 query
for project in projects:
tasks = oql.execute(f"FIND Task TRAVERSE has_task <- Project WHERE Project.rid = '{project.rid}'")
# Good: batch traversal
results = oql.execute("""
FIND Project
WHERE status = 'in_progress'
INCLUDE
TRAVERSE has_task -> Task
SELECT Task.title, Task.status
SELECT Project.name, tasks
""")
#7.2 Query Plan Analysis
# Use EXPLAIN to view the query plan
plan = oql.explain("""
FIND Employee
TRAVERSE works_in -> Department
WHERE Department.location = 'Shanghai'
SELECT Employee.name, Employee.salary
""")
print(plan.to_tree())
# +-- ObjectScan: Employee (estimated: 5000 rows)
# +-- RelationLookup: works_in (index: btree)
# +-- Filter: Department.location = 'Shanghai' (selectivity: 0.15)
# +-- Project: [Employee.name, Employee.salary]
# Estimated cost: 750 | Uses indexes: [works_in_idx, dept_location_idx]
#7.3 Common Errors and Troubleshooting
| Error | Cause | Solution |
|---|---|---|
ObjectTypeNotFound | Typo in object type name | Check Schema Registry |
PropertyNotFound | Property does not exist | Use platform.schema.describe("Employee") |
PermissionDenied | ABAC policy blocks access | Check current user's permission policies |
TraversalDepthExceeded | Graph traversal too deep | Adjust MAX_DEPTH or restructure query |
QueryTimeout | Query execution timed out | Add indexes or restructure query |
#8. Complete Example: Project Health Dashboard
from ontology_sdk import OntoPlatform
platform = OntoPlatform(
control_plane_url="localhost:50051",
data_plane_url="localhost:50052"
)
oql = platform.oql
# Project overview
overview = oql.execute("""
FIND Project
GROUP BY status
AGGREGATE COUNT(*) AS count, SUM(budget) AS total_budget
""")
print("=== Project Status Distribution ===")
for row in overview:
print(f" {row.status}: {row.count} projects, total budget: ${row.total_budget:,.0f}")
# Resource utilization
utilization = oql.execute("""
FIND Employee
INCLUDE
TRAVERSE participates_in -> Project
WHERE Project.status = 'in_progress'
AGGREGATE COUNT(*) AS active_projects
SELECT
name, department, level, active_projects,
CASE
WHEN active_projects > 3 THEN 'Overloaded'
WHEN active_projects = 0 THEN 'Idle'
ELSE 'Normal'
END AS workload_status
ORDER BY active_projects DESC
""")
print("\n=== Resource Load ===")
overloaded = [r for r in utilization if r.workload_status == 'Overloaded']
idle = [r for r in utilization if r.workload_status == 'Idle']
print(f" Overloaded: {len(overloaded)} employees")
print(f" Idle: {len(idle)} employees")
# At-risk projects
at_risk = oql.execute("""
FIND Project
WHERE status = 'in_progress'
AND end_date < NOW() + INTERVAL '14 days'
INCLUDE
TRAVERSE has_task -> Task
WHERE Task.status != 'done'
AGGREGATE COUNT(*) AS remaining_tasks
SELECT name, end_date, remaining_tasks, priority
HAVING remaining_tasks > 0
ORDER BY end_date ASC
""")
print("\n=== At-Risk Projects ===")
for row in at_risk:
print(f" {row.name}: {row.remaining_tasks} tasks remaining, "
f"due {row.end_date}")
#Key Takeaways
- OQL is Ontology-centric: Queries target objects and relations, not tables and rows, making business semantics more intuitive
- TRAVERSE replaces JOIN: Graph traversal is OQL's core advantage; multi-level relation queries need no complex JOINs
- Built-in security: ABAC permission policies are automatically injected into queries
- Reasoning integration: The INFERRED keyword seamlessly connects to Intelligence Layer's reasoning engine
- Parameterized injection prevention: Always use parameterized queries to prevent OQL injection attacks
- Performance first: Use EXPLAIN, select only needed fields, and avoid N+1 queries
#Next Article
Next: S12-07 Pipeline Development Guide — Learn how to build end-to-end data pipelines, from data ingestion to Ontology write-back.
Tags: OQL Query Language Ontology Graph Traversal Aggregation Reasoning Query coomia-dip