This commit is contained in:
2026-08-08 23:36:25 -04:00
parent 64a2c87346
commit 9177c8902b
3 changed files with 82 additions and 30 deletions
-2
View File
@@ -1,10 +1,8 @@
use std::collections::BTreeMap;
use std::sync::LazyLock;
use oxigraph::model::{GraphNameRef, NamedNodeRef};
use tracing::debug;
const ONTOLOGY_PREFIX: &str = "https://graphofliberty.org/2026/04/ont/";
const ONTOLOGY_GRAPH_NAME: GraphNameRef = GraphNameRef::NamedNode(NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont"));
pub static PREFIXES: LazyLock<BTreeMap<String, String>> = LazyLock::new(|| {
BTreeMap::from_iter([
+72 -24
View File
@@ -1,36 +1,55 @@
use std::sync::Arc;
use oxigraph::model::{Dataset, GraphNameRef, NamedNodeRef, Quad, QuadRef};
use oxigraph::sparql::{QueryResults, SparqlEvaluator};
use oxigraph::store::{Store, Transaction};
use tracing::{debug_span, field};
use oxigraph::store::Store;
use tracing::{debug, debug_span, field};
const RDF_SCHEMA_PREFIX: &str = "http://www.w3.org/2000/01/rdf-schema#";
const GL_PREFIX: &str = "https://graphofliberty.org/";
const INFERENCE_GRAPH: GraphNameRef = GraphNameRef::NamedNode(NamedNodeRef::new_unchecked("https://graphofliberty.org/inference"));
const INPUT_GRAPH: GraphNameRef = GraphNameRef::NamedNode(NamedNodeRef::new_unchecked("https://graphofliberty.org/input"));
#[derive(Clone)]
pub struct InferenceEngine {
ontology: Store,
}
/// `prp-spo1`
fn sub_property_of(transaction: Transaction) -> crate::Result<Dataset> {
let span = debug_span!("rdfs:subPropertyOf", inferences = field::Empty).entered();
const SUB_PROPERTY_OF_QUERY: &str = r#"CONSTRUCT {
?x ?p2 ?y .
} WHERE {
?p1 rdfs:subPropertyOf+ ?p2 .
GRAPH gl:inference { ?x ?p1 ?y . }
}"#;
/// `cax-sco`
const SUB_CLASS_OF_QUERY: &str = r#"CONSTRUCT {
?x a ?c2 .
} WHERE {
?c1 rdfs:subClassOf+ ?c2 .
GRAPH gl:inference { ?x a ?c1 . }
}"#;
/// `prp-dom`
const DOMAIN_QUERY: &str = r#"CONSTRUCT {
?x a ?c .
} WHERE {
?p rdfs:domain ?c .
GRAPH gl:inference { ?x ?p ?y . }
}"#;
/// https://www.w3.org/TR/owl2-profiles/#Reasoning_in_OWL_2_RL_and_RDF_Graphs_using_Rules
#[derive(Clone)]
pub struct InferenceEngine {
ontology: Dataset,
}
fn run_query(name: &str, query: &str, dataset: &Dataset) -> crate::Result<Dataset> {
let span = debug_span!("Query", name).entered();
let mut query = SparqlEvaluator::new()
.with_prefix("rdfs", RDF_SCHEMA_PREFIX)?
.with_prefix("gl", GL_PREFIX)?
.parse_query(r#"CONSTRUCT {
?x ?p2 ?y .
} WHERE {
?p1 rdfs:subPropertyOf+ ?p2 .
GRAPH gl:input { ?x ?p1 ?y . }
}"#)?;
.parse_query(query)?;
query.dataset_mut().set_default_graph_as_union();
let inferences = if let QueryResults::Graph(result) = query.on_transaction(&transaction).execute()? {
let inferences = if let QueryResults::Graph(result) = query.on_queryable_dataset(dataset).execute()? {
result.filter_map(Result::ok)
.map(|triple| Quad::new(triple.subject, triple.predicate, triple.object, INFERENCE_GRAPH))
.collect()
@@ -38,23 +57,52 @@ fn sub_property_of(transaction: Transaction) -> crate::Result<Dataset> {
Dataset::new()
};
span.record("inferences", inferences.len());
Ok(inferences)
}
fn run_recursively(mut dataset: Dataset) -> crate::Result<Dataset> {
let sub_property_of_result = run_query("rdfs:subPropertyOf", SUB_PROPERTY_OF_QUERY, &dataset)?;
let sub_class_of_result = run_query("rdfs:subClassOf", SUB_CLASS_OF_QUERY, &dataset)?;
let domain_result = run_query("rdfs:domain", DOMAIN_QUERY, &dataset)?;
let old_count = dataset.len();
dataset.extend(&sub_property_of_result);
dataset.extend(&sub_class_of_result);
dataset.extend(&domain_result);
let new_count = dataset.len();
if new_count > old_count {
run_recursively(dataset)
} else {
Ok(dataset)
}
}
impl InferenceEngine {
pub fn new(store: Store) -> Self {
let mut ontology = Dataset::new();
debug_span!("Load Ontology").in_scope(|| {
ontology.extend(store.iter().filter_map(Result::ok));
});
Self {
ontology: store,
ontology,
}
}
pub fn run(&self, dataset: &Dataset) -> crate::Result<Dataset> {
let _span = debug_span!("Inference").entered();
let span = debug_span!("Inference", inferences = field::Empty).entered();
let mut transaction = self.ontology.start_transaction()?;
let input = dataset.iter().map(|triple| QuadRef::new(triple.subject, triple.predicate, triple.object, INPUT_GRAPH));
transaction.extend(input);
sub_property_of(transaction)
let input = dataset.iter().map(|triple| QuadRef::new(triple.subject, triple.predicate, triple.object, INFERENCE_GRAPH));
let mut ontology = self.ontology.clone();
ontology.extend(input);
let result: Dataset = run_recursively(ontology)?
.quads_for_graph_name(INFERENCE_GRAPH)
.collect();
span.record("inferences", result.len());
Ok(result)
}
}