Production Integration¶
Patterns for embedding OntoLogos in services and pipelines. Profile status: Profile stability matrix.
Dependency selection¶
| Need | Minimum crates |
|---|---|
| Build/load JSON only | ontologos-core |
| Load OWL files | + ontologos-parser |
| RDFS materialization | ontologos-rl (rdfs module) |
| OWL RL saturation | + ontologos-rl |
| OWL EL taxonomy | + ontologos-el, + ontologos-ql |
| Profile routing | + ontologos-profile |
| Explanations | + ontologos-explain |
See Choosing an API. There is no umbrella ontologos meta-crate on crates.io. For Python services, use pip install ontologos.
Untrusted OWL uploads¶
Do not use load_ontology(path) for user-supplied paths without constraints.
use ontologos_parser::{load_ontology_with_limits_and_base, ParseLimits};
use std::path::Path;
let base = Path::new("/var/uploads/sandbox");
let user_file = Path::new("ontology.owl");
let limits = ParseLimits {
max_file_bytes: 1_048_576, // 1 MiB
..ParseLimits::default()
};
let ontology = load_ontology_with_limits_and_base(user_file, limits, Some(base))?;
load_ontology_with_limits_and_base canonicalizes paths and rejects directory traversal outside base. See Security.
Untrusted JSON snapshots¶
Use from_json_with_limits — format v1 is rejected. Writers emit v3 on v1.1.4; readers accept v2 and v3.
use ontologos_core::{Limits, Ontology};
let limits = Limits {
max_json_bytes: 1_048_576,
..Limits::default()
};
let ontology = Ontology::from_json_with_limits(json_bytes, limits)?;
Persisting results¶
After materialization or saturation, persist the enriched ontology:
Reload later with Ontology::from_json. OWL export is not built in — keep JSON snapshots or retain the source OWL plus processing metadata. See JSON snapshot v3.
Reasoning workflow (Rust)¶
Use profile-aware routing instead of manual match on detected profiles:
use ontologos_core::{Profile, Reasoner, ReasonerConfig};
use ontologos_facade::{check_consistency, classify, ClassifyOutcome};
use ontologos_parser::load_ontology;
let ontology = load_ontology(path)?;
let mut reasoner = Reasoner::builder()
.profile(Profile::Auto)
.config(ReasonerConfig {
incremental: true,
..ReasonerConfig::default()
})
.build(ontology)?;
let consistency = check_consistency(&reasoner)?;
if !consistency.complete || !consistency.consistent {
return Err("ontology inconsistent or consistency check incomplete".into());
}
match classify(&mut reasoner)? {
ClassifyOutcome::Taxonomy(t) => { /* EL or DL taxonomy */ }
ClassifyOutcome::Rl(r) => { /* RL saturation report */ }
ClassifyOutcome::Rdfs(r) => { /* RDFS materialization report */ }
}
OWL DL in production¶
Stable --profile dl on v1.1.4 uses bounded tableau reasoning. Follow this checklist before serving DL in production:
- Always use
check_consistency— notis_consistent. InspectConsistencyResult { consistent, complete }. Whencomplete == false, the check hit a wall-clock or tableau budget; do not treat the ontology as proven consistent. - Set a wall-clock budget —
ReasonerConfig { budget_secs: Some(30), .. }orONTOLOGOS_DL_BUDGET_SECS. Without a budget, DL consistency may run until natural completion (unbounded on pathological inputs). - Never set conformance env vars — leave
ONTOLOGOS_CONFORMANCE,ONTOLOGOS_STRICT_TAXONOMY, andONTOLOGOS_CI_PROMOTED_ONLYunset. CI shortcuts are not production semantics. See Security. - Validate on your corpus — HermiT catalog parity (
parity_pct = 100%) applies to gated test corpora only, not every real-world ontology. Run classify + consistency on your files before cutover. - Single-thread OWL loads — horned-owl parsing is serialized by a process-wide mutex; use one load at a time or process-isolated workers. See Security.
Rust (DL service)¶
use ontologos_core::{Profile, Reasoner, ReasonerConfig};
use ontologos_facade::{check_consistency, classify, ClassifyOutcome};
use ontologos_parser::{load_ontology_in, ParseLimits};
use std::path::Path;
let base = Path::new("/var/uploads/sandbox");
let ontology = load_ontology_in(
base,
Path::new("ontology.owl"),
)?;
let mut reasoner = Reasoner::builder()
.profile(Profile::Dl)
.config(ReasonerConfig {
budget_secs: Some(30),
..ReasonerConfig::default()
})
.build(ontology)?;
let result = check_consistency(&reasoner)?;
if !result.complete {
return Err("DL consistency incomplete — increase budget_secs".into());
}
if !result.consistent {
return Err("ontology inconsistent".into());
}
match classify(&mut reasoner)? {
ClassifyOutcome::Taxonomy(t) => { /* use t */ }
_ => unreachable!("Profile::Dl yields Taxonomy"),
}
Python (DL service)¶
from ontologos import Reasoner
reasoner = Reasoner(
path="/data/ontology.owl",
profile="dl",
budget_secs=30,
)
consistency = reasoner.check_consistency()
if not consistency["complete"]:
raise RuntimeError("DL consistency incomplete — increase budget_secs")
if not consistency["consistent"]:
raise RuntimeError("ontology inconsistent")
report = reasoner.classify()
CLI: ontologos classify --profile dl --budget-secs 30 ontology.owl
See Facade API · Performance · Evaluator scope.
For direct engine access (no Reasoner wrapper):
- RDFS:
ontologos_rl::rdfs::RdfsEngine::materializeorontologos_rl::rdfs::classify_reasoner - RL:
ontologos_rl::RlEngine::saturateorclassify_reasoner - EL:
ontologos_el::ElClassifier::classifyorontologos_el::classify_reasoner
Note: Classification and consistency live in
ontologos_facade— not onontologos_core::Reasoner. See Facade API and Facade reference.
When merging triples from reasonable back into core, apply merge limits to cap axiom growth on untrusted input.
Python services¶
Python 1.0.0 returns structured report dicts from classify(), supports explain(), incremental mutations, and optional DataFrame export:
from ontologos import Reasoner
reasoner = Reasoner(path="/data/ontology.owl", profile="auto", incremental=True)
report = reasoner.classify()
graph = reasoner.explain()
reasoner.add_subclass_of("http://example.org/A", "http://example.org/B")
reasoner.classify()
Reasoner is not thread-safe — one instance per worker or external locking.
Positional Reasoner("file.owl") still works; prefer keyword path= for clarity.
See Python guide and v0.9.x → v1.0.0 migration.
Incremental pipelines¶
Enable ReasonerConfig::incremental (Rust) or incremental=True (Python) when ontologies change between passes. After axiom removal, engines strip inferred axioms before rematerialization — see Incremental reasoning.
CLI: ontologos classify --incremental ontology.owl runs a single incremental pass per invocation (library multi-pass workflows hold session state across edits).
Observability¶
For containers, health checks, DL budgets, and tracing setup, see Deployment and observability.
Inspect parse_meta after load:
warnings— skipped mapping shapesmapped_axiom_count/skipped_axiom_count— see Protégé vs counts
Engine reports (MaterializationReport, EL taxonomy, proof graphs) expose counts, clashes (RL), and subsumptions (EL). RDFS/RL rule-level telemetry may be empty when delegating to reasonable — see Reasonable adapter limits.