Files
tools/graph/src/indexer.rs
T

156 lines
6.3 KiB
Rust
Raw Normal View History

2026-08-16 15:50:10 -04:00
use rayon::iter::ParallelIterator;
use std::collections::{HashMap, HashSet};
use oxigraph::model::{Graph, NamedNode, TermRef, NamedOrBlankNodeRef, NamedNodeRef};
use rayon::iter::IntoParallelRefIterator;
use gl_search::{Field, OwnedValue, Schema};
use crate::class::Class;
use crate::{helpers, vocab, CurieHelper};
use crate::language::LanguageCondition;
2026-08-22 23:31:14 -04:00
use crate::ontology::ResourceDescription;
2026-08-16 15:50:10 -04:00
pub struct Indexer<'a> {
language: LanguageCondition,
curie_helper: &'a CurieHelper,
}
impl<'a> Indexer<'a> {
pub fn new(language: LanguageCondition, curie_helper: &'a CurieHelper) -> Self {
Self {
language,
curie_helper,
}
}
fn extract_string(&self, graph: &Graph, subject: NamedNodeRef, predicate: NamedNodeRef) -> OwnedValue {
graph.object_for_subject_predicate(subject, predicate)
.filter(|term| self.language.primary_matches_term(*term))
.and_then(helpers::term_ref_as_str)
.map(String::from)
.map(OwnedValue::Str)
.unwrap_or_else(|| OwnedValue::Null)
}
fn person(&self, graph: &Graph, subject: NamedNodeRef) -> HashMap<Field, OwnedValue> {
HashMap::from_iter([
(
Schema::field("given_name", self.language.primary_language()),
self.extract_string(graph, subject, vocab::rdaad::GIVEN_NAME),
),
(
Schema::field("surname", self.language.primary_language()),
self.extract_string(graph, subject, vocab::rdaad::SURNAME),
),
])
}
fn corporate_body(&self, graph: &Graph, subject: NamedNodeRef) -> HashMap<Field, OwnedValue> {
HashMap::from_iter([
(
Schema::field("corporate_name", self.language.primary_language()),
self.extract_string(graph, subject, vocab::rdaad::NAME_OF_CORPORATE_BODY),
),
])
}
2026-08-16 21:42:14 -04:00
fn work(&self, graph: &Graph, subject: NamedNodeRef) -> HashMap<Field, OwnedValue> {
HashMap::from_iter([
(
Schema::field("title", self.language.primary_language()),
self.extract_string(graph, subject, vocab::rdawd::TITLE_OF_WORK),
),
])
}
fn expression(&self, graph: &Graph, subject: NamedNodeRef) -> HashMap<Field, OwnedValue> {
HashMap::from_iter([
(
Schema::field("title", self.language.primary_language()),
self.extract_string(graph, subject, vocab::rdaed::TITLE_OF_EXPRESSION),
),
])
}
2026-08-20 20:43:18 -04:00
fn manifestation(&self, graph: &Graph, subject: NamedNodeRef) -> HashMap<Field, OwnedValue> {
HashMap::from_iter([
(
Schema::field("title", self.language.primary_language()),
self.extract_string(graph, subject, vocab::rdamd::TITLE_OF_MANIFESTATION),
),
])
}
2026-08-22 23:31:14 -04:00
pub fn graph(&self, graph: &Graph) -> Vec<HashMap<Field, OwnedValue>> {
2026-08-16 15:50:10 -04:00
let mut entities_and_types = HashSet::new();
let triples = graph.triples_for_predicate(vocab::rdf::TYPE);
for triple in triples {
if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject &&
let TermRef::NamedNode(class) = triple.object {
entities_and_types.insert((subject, class));
}
}
let results = entities_and_types.par_iter()
.filter_map(|(subject, class)| {
Class::try_from_named_node(*class).and_then(|class| {
match class {
Class::RdfProperty => None,
Class::RdfsClass => None,
Class::SkosConcept => None,
2026-08-16 21:42:14 -04:00
Class::Work => Some(self.work(graph, *subject)),
2026-08-16 15:50:10 -04:00
Class::Person => Some(self.person(graph, *subject)),
Class::CorporateBody => Some(self.corporate_body(graph, *subject)),
2026-08-16 21:42:14 -04:00
Class::Expression => Some(self.expression(graph, *subject)),
2026-08-20 20:43:18 -04:00
Class::Manifestation => Some(self.manifestation(graph, *subject)),
2026-08-16 15:50:10 -04:00
}.map(|mut document| {
document.insert(Schema::discriminant_field(), OwnedValue::from(class as u64));
document.insert(Schema::iri_field(), OwnedValue::Str(subject.as_str().to_string()));
let curie = self.curie_helper.abbreviate(None, subject.as_str())
.map(OwnedValue::Str)
.unwrap_or(OwnedValue::Null);
document.insert(Schema::curie_field(), curie);
document
})
})
}).collect();
2026-08-22 23:31:14 -04:00
results
2026-08-16 15:50:10 -04:00
}
2026-08-22 23:31:14 -04:00
pub fn ontology(&self, entities: HashMap<NamedNode, (NamedNode, ResourceDescription)>) -> Vec<HashMap<Field, OwnedValue>> {
let label_field = Schema::field("label", self.language.primary_language());
let definition_field = Schema::field("definition", self.language.primary_language());
2026-08-16 15:50:10 -04:00
2026-08-22 23:31:14 -04:00
entities.iter()
.map(|(subject, (class, description))| {
2026-08-16 15:50:10 -04:00
let mut document = HashMap::with_capacity(4);
2026-08-22 23:31:14 -04:00
let discriminant = Class::try_from_named_node(class)
2026-08-16 15:50:10 -04:00
.map(|doc_type| doc_type as u64)
.map(OwnedValue::U64)
.unwrap_or(OwnedValue::Null);
document.insert(Schema::discriminant_field(), discriminant);
2026-08-22 23:31:14 -04:00
let curie = self.curie_helper.abbreviate(None, subject.as_str())
2026-08-16 15:50:10 -04:00
.map(OwnedValue::Str)
.unwrap_or(OwnedValue::Null);
document.insert(Schema::curie_field(), curie);
2026-08-22 23:31:14 -04:00
let subject = OwnedValue::from(subject.as_str());
2026-08-16 15:50:10 -04:00
document.insert(Schema::iri_field(), subject);
2026-08-22 23:31:14 -04:00
let label = description.label.clone()
2026-08-16 15:50:10 -04:00
.map(OwnedValue::from)
.unwrap_or(OwnedValue::Null);
document.insert(label_field, label);
2026-08-22 23:31:14 -04:00
let definition = description.description.clone()
2026-08-16 15:50:10 -04:00
.map(OwnedValue::from)
.unwrap_or(OwnedValue::Null);
document.insert(definition_field, definition);
2026-08-22 23:31:14 -04:00
document
}).collect()
2026-08-16 15:50:10 -04:00
}
}