返回博客

OQL 查询指南:20 个真实示例

OQL(Ontology Query Language)是 coomia-dip 平台的声明式查询语言,专为 Ontology 数据模型设计。它比 SQL 更贴近业务语义,支持对象、关系、属性的联合查询,以及图遍历、聚合和推理集成。本文通过 20 个真实示例,从基础到高级全面覆盖 OQL 的查询能力。

Coomia发布于 2026年1月15日13 分钟阅读
分享本文Twitter / X

系列:S12 开发者教程 · 第 6 篇 | 难度:中级 | 阅读时间:15 分钟

OQL 查询指南:20 个真实示例

#TL;DR

OQL(Ontology Query Language)是 coomia-dip 平台的声明式查询语言,专为 Ontology 数据模型设计。它比 SQL 更贴近业务语义,支持对象、关系、属性的联合查询,以及图遍历、聚合和推理集成。本文通过 20 个真实示例,从基础到高级全面覆盖 OQL 的查询能力。

#1. OQL 概述

#1.1 什么是 OQL?

OQL 是 coomia-dip 平台的原生查询语言,运行在 Control Layer(Control Layer)之上。与传统 SQL 不同,OQL 以 Ontology 为核心抽象:你查询的是"对象"和"关系",而不是"表"和"行"。

Code
SQL:   SELECT * FROM projects WHERE status = 'active'
OQL:   FIND Project WHERE status = 'active'

#1.2 OQL 与 SQL 的关键差异

特性SQLOQL
查询目标表/行对象/关系
关联方式JOINTRAVERSE
数据模型关系型本体(Ontology)
图遍历多级 JOIN原生 TRAVERSE
权限过滤手动 WHERE自动 ABAC 集成
类型安全Schema 强校验

#1.3 OQL 执行架构

Code
Client (SDK/API)
    │
    ▼
Control Layer (gRPC)
    │  ① 解析 OQL → AST
    │  ② Schema 校验
    │  ③ 权限过滤注入
    │  ④ 查询优化
    ▼
Data Layer (Doris/Iceberg)
    │  ⑤ 执行查询
    ▼
Result Set → Object 映射

#2. 环境准备

#2.1 安装 SDK

Bash
pip install ontology-sdk>=1.0.0

#2.2 初始化连接

Python
from ontology_sdk import OntoPlatform

platform = OntoPlatform(
    control_plane_url="localhost:50051",
    data_plane_url="localhost:50052",
    auth_token="your-token"
)

# 获取 OQL 客户端
oql = platform.oql

#2.3 示例数据模型

本文所有示例基于以下 Ontology 模型:

YAML
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. 基础查询(示例 1-5)

#示例 1:简单对象查询

查找所有进行中的项目:

Python
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} | 优先级: {project.priority} | 预算: {project.budget}")

输出:

Code
智慧工厂监控系统 | 优先级: critical | 预算: 5000000
供应链优化平台 | 优先级: high | 预算: 3200000
客户360画像 | 优先级: medium | 预算: 1800000

#示例 2:多条件组合过滤

查找高薪资的高级员工:

Python
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
""")

OQL 支持的操作符:

  • 比较:=, !=, >, <, >=, <=
  • 集合:IN, NOT IN
  • 模糊:LIKE, CONTAINS, STARTS_WITH
  • 空值:IS NULL, IS NOT NULL
  • 逻辑:AND, OR, NOT

#示例 3:属性投影与别名

Python
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
""")

#示例 4:分页查询

Python
# 第一页
page1 = oql.execute("""
    FIND Employee
    WHERE department = 'Engineering'
    SELECT name, email, level
    ORDER BY hire_date ASC
    LIMIT 20 OFFSET 0
""")

# 第二页
page2 = oql.execute("""
    FIND Employee
    WHERE department = 'Engineering'
    SELECT name, email, level
    ORDER BY hire_date ASC
    LIMIT 20 OFFSET 20
""")

# SDK 封装的分页方式
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_number} 页,共 {page.total_pages} 页 ---")

#示例 5:模糊搜索与全文检索

Python
# 属性模糊匹配
results = oql.execute("""
    FIND Project
    WHERE name LIKE '%供应链%'
       OR description CONTAINS '优化'
    SELECT name, description
""")

# 全文检索模式
results = oql.execute("""
    FIND Project
    SEARCH '供应链风险预警'
    SELECT name, description, _score
    ORDER BY _score DESC
    LIMIT 10
""")

#4. 关系遍历查询(示例 6-10)

#示例 6:单级关系遍历

查找某个部门下的所有员工:

Python
results = oql.execute("""
    FIND Employee
    TRAVERSE works_in -> Department
    WHERE Department.name = '工程部'
    SELECT Employee.name, Employee.level, Employee.salary
""")

等效的 gRPC 调用:

Python
# 先通过 SDK 对象 API
dept = platform.objects.get("Department", filters={"name": "工程部"})
employees = platform.relations.get_related(
    source_rid=dept.rid,
    relation_type="works_in",
    direction="inbound"
)

#示例 7:多级关系遍历

查找参与了某客户项目的所有员工:

Python
results = oql.execute("""
    FIND Employee
    TRAVERSE participates_in -> Project
    TRAVERSE serves -> Customer
    WHERE Customer.name = '华为技术有限公司'
    SELECT
        Employee.name AS employee_name,
        Project.name AS project_name,
        Customer.name AS customer_name
""")

#示例 8:反向关系遍历

查找某个员工负责的所有任务及其所属项目:

Python
results = oql.execute("""
    FIND Task
    TRAVERSE assigned_to -> Employee
    WHERE Employee.name = '张三'
    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
""")

#示例 9:关系属性过滤

Python
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
""")

#示例 10:图路径查询

查找两个对象之间的连接路径:

Python
results = oql.execute("""
    PATH FROM Employee WHERE name = '张三'
    TO Customer WHERE name = '华为技术有限公司'
    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]))

输出:

Code
Employee:张三 -> Project:智慧工厂监控系统 -> Customer:华为技术有限公司
Employee:张三 -> Department:工程部 -> Project:供应链优化平台 -> Customer:华为技术有限公司

#5. 聚合与分析查询(示例 11-15)

#示例 11:基础聚合

Python
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}人, "
          f"平均薪资: {row.avg_salary:.0f}")

#示例 12:多维度聚合

Python
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
""")

#示例 13:时间序列聚合

Python
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})")

#示例 14:HAVING 条件过滤

Python
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("=== 进度落后的项目 ===")
for row in results:
    print(f"{row.project_name}: {row.completion_rate}% "
          f"({row.done_tasks}/{row.total_tasks})")

#示例 15:跨对象统计

Python
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. 高级查询(示例 16-20)

#示例 16:子查询

Python
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
""")

#示例 17:WITH 预计算(CTE 等价)

Python
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
""")

#示例 18:条件表达式

Python
results = oql.execute("""
    FIND Project
    SELECT
        name,
        budget,
        CASE
            WHEN budget > 5000000 THEN '大型项目'
            WHEN budget > 2000000 THEN '中型项目'
            WHEN budget > 500000 THEN '小型项目'
            ELSE '微型项目'
        END AS project_scale,
        CASE
            WHEN end_date < NOW() AND status != 'done' THEN '已逾期'
            WHEN end_date < NOW() + INTERVAL '7 days' THEN '即将到期'
            ELSE '正常'
        END AS deadline_status
    ORDER BY budget DESC
""")

#示例 19:参数化查询与防注入

Python
# 参数化查询 — 防止 OQL 注入
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_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}人")

#示例 20:推理集成查询

OQL 可以与 Intelligence Layer 的推理引擎联动:

Python
# 基于规则推理的查询
results = oql.execute("""
    FIND Employee
    WHERE INFERRED risk_level = 'high'
    SELECT
        name, department,
        INFERRED risk_level,
        INFERRED risk_factors,
        INFERRED recommended_actions
""")

# INFERRED 关键字触发推理引擎
# Intelligence Layer 会基于规则和知识图谱计算衍生属性

# 图谱推理查询
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"⚠ {row.customer_name} (流失概率: {row.churn_probability:.1%})")
    print(f"  原因: {row.churn_reason}")
    print(f"  关联项目: {row.related_project}")

#7. OQL 最佳实践

#7.1 性能优化

Python
# 差:全量扫描后过滤
oql.execute("FIND Employee SELECT * WHERE salary > 50000")

# 好:只选必要字段、先过滤
oql.execute("""
    FIND Employee
    WHERE salary > 50000
    SELECT name, salary, level
    LIMIT 100
""")

# 差:N+1 查询
for project in projects:
    tasks = oql.execute(f"FIND Task TRAVERSE has_task <- Project WHERE Project.rid = '{project.rid}'")

# 好:批量遍历
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 查询计划分析

Python
# 使用 EXPLAIN 查看查询计划
plan = oql.explain("""
    FIND Employee
    TRAVERSE works_in -> Department
    WHERE Department.location = '上海'
    SELECT Employee.name, Employee.salary
""")

print(plan.to_tree())
# ├── ObjectScan: Employee (estimated: 5000 rows)
# ├── RelationLookup: works_in (index: btree)
# ├── Filter: Department.location = '上海' (selectivity: 0.15)
# └── Project: [Employee.name, Employee.salary]
# Estimated cost: 750 | Uses indexes: [works_in_idx, dept_location_idx]

#7.3 常见错误与排查

错误原因解决方案
ObjectTypeNotFound对象类型名拼写错误检查 Schema Registry
PropertyNotFound属性名不存在使用 platform.schema.describe("Employee")
PermissionDeniedABAC 策略阻止访问检查当前用户的权限策略
TraversalDepthExceeded图遍历深度超限调整 MAX_DEPTH 或优化查询
QueryTimeout查询执行超时添加索引或重构查询

#8. 完整实战:项目健康度仪表盘

Python
from ontology_sdk import OntoPlatform

platform = OntoPlatform(
    control_plane_url="localhost:50051",
    data_plane_url="localhost:50052"
)
oql = platform.oql

# 项目总览
overview = oql.execute("""
    FIND Project
    GROUP BY status
    AGGREGATE COUNT(*) AS count, SUM(budget) AS total_budget
""")

print("=== 项目状态分布 ===")
for row in overview:
    print(f"  {row.status}: {row.count} 个项目, 预算合计: ¥{row.total_budget:,.0f}")

# 资源利用率
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 '过载'
            WHEN active_projects = 0 THEN '空闲'
            ELSE '正常'
        END AS workload_status
    ORDER BY active_projects DESC
""")

print("\n=== 资源负载 ===")
overloaded = [r for r in utilization if r.workload_status == '过载']
idle = [r for r in utilization if r.workload_status == '空闲']
print(f"  过载: {len(overloaded)} 人")
print(f"  空闲: {len(idle)} 人")

# 延期风险
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=== 延期风险项目 ===")
for row in at_risk:
    print(f"  {row.name}: 剩余 {row.remaining_tasks} 个任务, "
          f"截止 {row.end_date}")

#Key Takeaways

  1. OQL 以 Ontology 为核心:查询的是对象和关系,而非表和行,业务语义更直观
  2. TRAVERSE 替代 JOIN:图遍历是 OQL 的核心优势,多级关系查询无需复杂 JOIN
  3. 内置安全:ABAC 权限策略自动注入查询,无需手动过滤
  4. 推理集成:INFERRED 关键字无缝对接 Intelligence Layer 的推理引擎
  5. 参数化防注入:始终使用参数化查询,避免 OQL 注入风险
  6. 性能优先:善用 EXPLAIN、合理选择字段、避免 N+1 查询

#Next Article

下一篇:S12-07 Pipeline 开发指南 — 学习如何构建端到端的数据管道,从数据接入到 Ontology 写入。

Tags: OQL 查询语言 Ontology 图遍历 聚合分析 推理查询 coomia-dip