Merge two ontologies algorithmically.
This performs a union merge of the two ontology graphs, mapping contradictions.
The result has both ontologies as parents. This is similar to a git merge:
- Takes union of all triples from both ontologies
- Detects contradictions (same subject-predicate with different objects)
- Creates a new ontology with both parents
- Sets created_at to merge time
Parameters:
Returns:
| Name | Type |
Description |
Ontology |
Ontology
|
Merged ontology with both parents
|
Raises:
| Type |
Description |
ValueError
|
If ontologies have different IRIs
|
Source code in ontocast/onto/ontology_operations.py
| def merge_ontologies(onto1: Ontology, onto2: Ontology) -> Ontology:
"""Merge two ontologies algorithmically.
This performs a union merge of the two ontology graphs, mapping contradictions.
The result has both ontologies as parents. This is similar to a git merge:
- Takes union of all triples from both ontologies
- Detects contradictions (same subject-predicate with different objects)
- Creates a new ontology with both parents
- Sets created_at to merge time
Args:
onto1: First ontology to merge
onto2: Second ontology to merge
Returns:
Ontology: Merged ontology with both parents
Raises:
ValueError: If ontologies have different IRIs
"""
# Validate that both ontologies have the same IRI
if onto1.iri != onto2.iri:
raise ValueError(
f"Cannot merge ontologies with different IRIs: {onto1.iri} != {onto2.iri}"
)
# Ensure both ontologies have hashes
if not onto1.hash:
onto1._compute_and_set_hash()
if not onto2.hash:
onto2._compute_and_set_hash()
if not onto1.hash or not onto2.hash:
raise ValueError("Cannot merge ontologies without hashes")
# Create merged graph (union) - use RDFGraph's __add__ operator
merged_graph = onto1.graph + onto2.graph
# Map contradictions (same subject-predicate with different objects)
contradictions = _find_contradictions(onto1.graph, onto2.graph)
if contradictions:
logger.warning(f"Found {len(contradictions)} contradictions in merge")
for (s, p), (obj1_set, obj2) in contradictions.items():
logger.debug(f"Contradiction: {s} {p} -> {obj1_set} vs {obj2}")
# For now, keep both objects (RDF allows multiple values)
# In future LLM-based merge, this would be resolved intelligently
# Create merged ontology
# Note: sync_properties_to_graph() will remove existing versionInfo triples,
# so we need to preserve them manually after creation
merged_ontology = Ontology(
graph=merged_graph,
iri=onto1.iri, # Use IRI from first ontology (should be same)
title=onto1.title or onto2.title,
description=onto1.description or onto2.description,
ontology_id=onto1.ontology_id or onto2.ontology_id,
version=onto1.version or onto2.version or "1.0.0",
parent_hashes=[onto1.hash, onto2.hash],
created_at=datetime.now(timezone.utc),
)
# Compute hash for merged ontology
# Note: Hash excludes metadata (version, title, description, created_at, hash, parent_hash)
# so it only reflects the actual ontology content (classes, properties, etc.)
merged_ontology._compute_and_set_hash()
logger.info(
f"Merged ontologies {onto1.hash[:8]}... "
f"and {onto2.hash[:8]}... "
f"-> {merged_ontology.hash[:8] if merged_ontology.hash else 'None'}..."
)
return merged_ontology
|