Your First Ontology: Creating ObjectType and RelationType
Ontology is the core abstraction of coomia-dip. While traditional databases use "tables" to describe data, coomia-dip uses "ontology" to describe the world. An ObjectType is analogous to a "class" in object-oriented programming, while a RelationType describes relationships between classes. This modeling approach gives your data not just structure, but semantics — enabling machines to "understand" the connections between data elements.
“Series: S12 Developer Tutorials · Article 2 | Level: Beginner | Reading Time: 15 min
Your First Ontology: Creating ObjectType and RelationType
#Introduction
Ontology is the core abstraction of coomia-dip. While traditional databases use "tables" to describe data, coomia-dip uses "ontology" to describe the world. An ObjectType is analogous to a "class" in object-oriented programming, while a RelationType describes relationships between classes. This modeling approach gives your data not just structure, but semantics — enabling machines to "understand" the connections between data elements.
In this tutorial, you will learn how to create your first complete ontology model, including defining ObjectTypes and RelationTypes using the Python SDK.
#Core Concepts
#What is an ObjectType?
An ObjectType is a metadata definition that describes a business entity in coomia-dip. It is similar to a table definition (Schema) in databases or a Class in object-oriented programming. In Palantir Foundry, this corresponds to an Object Type. coomia-dip maintains the same semantic model as Foundry but implements it using an open-source technology stack.
Each ObjectType consists of:
- name: Unique identifier (e.g., "Employee")
- display_name: Human-readable name (e.g., "Employee")
- properties: A list of typed, constrained attributes
- primary_key: The unique identifying property
from ontology_sdk import OntoPlatform
platform = OntoPlatform(
control_plane_url="localhost:50051",
data_plane_url="localhost:50052"
)
employee_type = platform.ontology.create_object_type(
name="Employee",
display_name="Employee",
description="Enterprise employee entity",
properties={
"employee_id": {
"type": "string",
"required": True,
"constraints": {"pattern": "^EMP-[0-9]{6}$"}
},
"name": {"type": "string", "required": True},
"email": {
"type": "string",
"required": True,
"constraints": {"format": "email", "unique": True}
},
"title": {"type": "string"},
"level": {"type": "integer", "constraints": {"min": 1, "max": 15}},
"hire_date": {"type": "date", "required": True},
"salary": {"type": "decimal", "constraints": {"min": 0, "precision": 2}},
"is_active": {"type": "boolean", "default": True},
"skills": {"type": "array", "items_type": "string"}
},
primary_key="employee_id"
)
print(f"Created: {employee_type.name} (rid={employee_type.rid})")
#Property Type System
coomia-dip supports 14 built-in property types:
| Type | Description | Example |
|---|---|---|
string | Text string | "Alice" |
integer | 32-bit integer | 42 |
long | 64-bit integer | 1234567890123 |
decimal | Exact decimal | 99999.99 |
double | Floating point | 3.14159 |
boolean | Boolean value | true |
date | Date | "2024-01-01" |
datetime | Date and time | "2024-01-01T12:00:00Z" |
timestamp | Millisecond timestamp | 1704067200000 |
enum | Enumeration | "active" |
array | Array | ["java", "python"] |
map | Key-value pairs | {"region": "asia"} |
geo_point | Geographic coordinates | [121.47, 31.23] |
attachment | Attachment reference | "ri.attachment.xxx" |
Each type supports constraints such as string patterns, numeric min/max, array max_length, and more.
#What is a RelationType?
A RelationType defines semantic relationships between two ObjectTypes. Unlike traditional database foreign keys, a RelationType carries semantic information and can have its own properties.
Three cardinalities are supported:
- ONE_TO_ONE: e.g., Employee to Badge
- ONE_TO_MANY: e.g., Department to Employee
- MANY_TO_MANY: e.g., Employee to Project
dept_type = platform.ontology.create_object_type(
name="Department",
display_name="Department",
properties={
"dept_id": {"type": "string", "required": True},
"name": {"type": "string", "required": True},
"code": {"type": "string", "constraints": {"unique": True}},
"budget": {"type": "decimal"},
},
primary_key="dept_id"
)
belongs_to = platform.ontology.create_relation_type(
name="belongs_to",
display_name="Belongs To",
source_type="Employee",
target_type="Department",
cardinality="MANY_TO_ONE",
properties={
"joined_at": {"type": "date"},
"role_in_dept": {"type": "string"}
}
)
#Complete Modeling Example: Enterprise Organization
Let us build a complete enterprise organization management ontology with three ObjectTypes and four RelationTypes.
#Business Scenario
- The company has multiple departments with hierarchical relationships
- Each employee belongs to one department
- The company has multiple projects, each owned by a department
- Employees can participate in multiple projects
#Creating All ObjectTypes
project_type = platform.ontology.create_object_type(
name="Project",
display_name="Project",
properties={
"project_id": {"type": "string", "required": True},
"name": {"type": "string", "required": True},
"status": {
"type": "enum",
"values": ["planning", "in_progress", "on_hold", "completed", "cancelled"],
"default": "planning"
},
"priority": {
"type": "enum",
"values": ["low", "medium", "high", "critical"]
},
"budget": {"type": "decimal"},
"start_date": {"type": "date"},
"end_date": {"type": "date"},
"tags": {"type": "array", "items_type": "string"}
},
primary_key="project_id"
)
#Creating All RelationTypes
# Employee participates in Project (many-to-many)
participates_in = platform.ontology.create_relation_type(
name="participates_in",
display_name="Participates In",
source_type="Employee",
target_type="Project",
cardinality="MANY_TO_MANY",
properties={
"role": {
"type": "enum",
"values": ["owner", "member", "reviewer", "observer"]
},
"allocation_pct": {
"type": "integer",
"constraints": {"min": 0, "max": 100}
}
}
)
# Department owns Project (one-to-many)
owns_project = platform.ontology.create_relation_type(
name="owns_project",
display_name="Owns",
source_type="Department",
target_type="Project",
cardinality="ONE_TO_MANY"
)
# Department hierarchy (self-reference)
parent_dept = platform.ontology.create_relation_type(
name="parent_department",
display_name="Parent Department",
source_type="Department",
target_type="Department",
cardinality="MANY_TO_ONE"
)
#Viewing the Ontology Graph
for ot in platform.ontology.list_object_types():
print(f"ObjectType: {ot.name} ({ot.display_name})")
for p in ot.properties:
req = " [required]" if p.required else ""
print(f" - {p.name}: {p.type}{req}")
for rt in platform.ontology.list_relation_types():
print(f"Relation: {rt.source_type} --[{rt.name}]--> {rt.target_type} ({rt.cardinality})")
#Dynamic Ontology Modification
One of coomia-dip's key advantages is runtime ontology modification without downtime migrations.
#Adding Properties
platform.ontology.update_object_type(
name="Employee",
add_properties={
"phone": {"type": "string", "description": "Phone number"},
"avatar_url": {"type": "string", "description": "Avatar URL"}
}
)
#Modifying Properties
platform.ontology.update_object_type(
name="Employee",
update_properties={
"skills": {"description": "Skill tags list (updated)"}
}
)
#Removing Properties
platform.ontology.update_object_type(
name="Employee",
remove_properties=["avatar_url"]
)
#Ontology Version Management
coomia-dip integrates with Nessie for Git-like ontology version management:
# View change history
history = platform.ontology.get_history(object_type="Employee")
for entry in history:
print(f" {entry.timestamp}: {entry.change_type} by {entry.user}")
# Create an ontology branch
branch = platform.ontology.create_branch("feature/add-address-type")
# Modify on the branch
platform.ontology.create_object_type(
name="Address",
branch="feature/add-address-type",
properties={...}
)
# Merge back
platform.ontology.merge_branch("feature/add-address-type")
#Comparison with Palantir Foundry
| Feature | Palantir Foundry | coomia-dip |
|---|---|---|
| ObjectType Definition | Web UI + API | SDK + API + YAML |
| RelationType | Link Type | RelationType (equivalent) |
| Property Constraints | Limited | Rich (regex, range, unique) |
| Dynamic Modification | Supported | Supported |
| Version Management | Yes | Yes (Nessie-based) |
| API Protocol | REST | gRPC (internal) + REST (external) |
| Cost | $$$$ | Open source, free |
#Best Practices
- Naming Conventions: PascalCase for ObjectTypes, snake_case for properties, verb phrases for RelationTypes
- Single Responsibility: Each ObjectType describes one business concept
- Moderate Properties: 5-15 properties is ideal
- Explicit Relations: Use RelationType instead of JSON nesting
- Use Constraints: pattern, min/max, unique improve data quality
- Document Everything: Add description to every property
#FAQ
#Q: Can ObjectTypes inherit from each other?
Currently coomia-dip does not support ObjectType inheritance. The recommended approach is composition — create shared ObjectTypes and connect them via RelationTypes.
#Q: Can properties be deleted?
Yes. After deleting a property, existing data values for that property are preserved (marked as deprecated), but new writes will not include it.
#Q: How many ObjectTypes are supported?
There is no theoretical limit. In production environments, we have tested 1000+ ObjectType scenarios with good performance.
#Next Steps
- Your First Data — Write and query entities
- Your First Action — Define business operations
- OQL Query Guide — Complex relationship queries
#Summary
This tutorial introduced coomia-dip's core concept — Ontology — including ObjectTypes and RelationTypes. Through an enterprise organization management example, we learned how to define types, properties, constraints, and relationships, as well as how to perform dynamic modifications and version management. Ontology is what distinguishes coomia-dip from traditional data platforms, elevating data from "rows and columns" to a "semantic knowledge graph."
This is Article 2 in the coomia-dip Developer Tutorial series. Repository: https://github.com/coomia-dip/coomia-dip↗ | License: Apache License 2.0