.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use oxigraph::model::NamedNodeRef;
|
||||
use crate::vocab;
|
||||
use oxigraph::model::NamedNodeRef;
|
||||
|
||||
pub enum Category {
|
||||
AudioBook = 0,
|
||||
@@ -19,4 +19,4 @@ impl Category {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+120
-41
@@ -1,9 +1,9 @@
|
||||
use std::fmt::Display;
|
||||
use oxigraph::model::{Graph, Literal, LiteralRef, NamedNode, NamedNodeRef, NamedOrBlankNode, Term, TermRef, Triple};
|
||||
use oxilangtag::LanguageTag;
|
||||
use url::Url;
|
||||
use gl_search::Schema;
|
||||
use crate::vocab;
|
||||
use gl_search::Schema;
|
||||
use oxigraph::model::{Graph, LiteralRef, NamedNode, NamedNodeRef, Triple};
|
||||
use oxilangtag::LanguageTag;
|
||||
use std::fmt::Display;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Class {
|
||||
@@ -83,33 +83,61 @@ impl Class {
|
||||
pub fn fields(&self, language: LanguageTag<String>) -> Vec<(gl_search::Field, String)> {
|
||||
match self {
|
||||
Class::RdfProperty => vec![
|
||||
(Schema::field("label", Some(language.primary_language())), String::from("Label")),
|
||||
(Schema::field("definition", Some(language.primary_language())), String::from("Definition")),
|
||||
(
|
||||
Schema::field("label", Some(language.primary_language())),
|
||||
String::from("Label"),
|
||||
),
|
||||
(
|
||||
Schema::field("definition", Some(language.primary_language())),
|
||||
String::from("Definition"),
|
||||
),
|
||||
],
|
||||
Class::RdfsClass => vec![
|
||||
(Schema::field("label", Some(language.primary_language())), String::from("Label")),
|
||||
(Schema::field("definition", Some(language.primary_language())), String::from("Definition")),
|
||||
(
|
||||
Schema::field("label", Some(language.primary_language())),
|
||||
String::from("Label"),
|
||||
),
|
||||
(
|
||||
Schema::field("definition", Some(language.primary_language())),
|
||||
String::from("Definition"),
|
||||
),
|
||||
],
|
||||
Class::SkosConcept => vec![
|
||||
(Schema::field("label", Some(language.primary_language())), String::from("Label")),
|
||||
(Schema::field("definition", Some(language.primary_language())), String::from("Definition")),
|
||||
],
|
||||
Class::Work => vec![
|
||||
(Schema::field("title", Some(language.primary_language())), String::from("Title")),
|
||||
(
|
||||
Schema::field("label", Some(language.primary_language())),
|
||||
String::from("Label"),
|
||||
),
|
||||
(
|
||||
Schema::field("definition", Some(language.primary_language())),
|
||||
String::from("Definition"),
|
||||
),
|
||||
],
|
||||
Class::Work => vec![(
|
||||
Schema::field("title", Some(language.primary_language())),
|
||||
String::from("Title"),
|
||||
)],
|
||||
Class::Person => vec![
|
||||
(Schema::field("given_name", Some(language.primary_language())), String::from("Given Name")),
|
||||
(Schema::field("surname", Some(language.primary_language())), String::from("Surname")),
|
||||
],
|
||||
Class::CorporateBody => vec![
|
||||
(Schema::field("corporate_body", Some(language.primary_language())), String::from("Corporate Body")),
|
||||
],
|
||||
Class::Expression => vec![
|
||||
(Schema::field("title", Some(language.primary_language())), String::from("Title")),
|
||||
],
|
||||
Class::Manifestation => vec![
|
||||
(Schema::field("title", Some(language.primary_language())), String::from("Title")),
|
||||
(
|
||||
Schema::field("given_name", Some(language.primary_language())),
|
||||
String::from("Given Name"),
|
||||
),
|
||||
(
|
||||
Schema::field("surname", Some(language.primary_language())),
|
||||
String::from("Surname"),
|
||||
),
|
||||
],
|
||||
Class::CorporateBody => vec![(
|
||||
Schema::field("corporate_body", Some(language.primary_language())),
|
||||
String::from("Corporate Body"),
|
||||
)],
|
||||
Class::Expression => vec![(
|
||||
Schema::field("title", Some(language.primary_language())),
|
||||
String::from("Title"),
|
||||
)],
|
||||
Class::Manifestation => vec![(
|
||||
Schema::field("title", Some(language.primary_language())),
|
||||
String::from("Title"),
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,16 +145,23 @@ impl Class {
|
||||
match self {
|
||||
Class::Work => Some(Url::parse("http://fedora.quill.lan/rest/#Work").unwrap()),
|
||||
Class::Person => Some(Url::parse("http://fedora.quill.lan/rest/#Agent").unwrap()),
|
||||
Class::CorporateBody => Some(Url::parse("http://fedora.quill.lan/rest/#Agent").unwrap()),
|
||||
Class::Expression => Some(Url::parse("http://fedora.quill.lan/rest/#Expression").unwrap()),
|
||||
Class::Manifestation => Some(Url::parse("http://fedora.quill.lan/rest/#Manifestation").unwrap()),
|
||||
Class::CorporateBody => {
|
||||
Some(Url::parse("http://fedora.quill.lan/rest/#Agent").unwrap())
|
||||
}
|
||||
Class::Expression => {
|
||||
Some(Url::parse("http://fedora.quill.lan/rest/#Expression").unwrap())
|
||||
}
|
||||
Class::Manifestation => {
|
||||
Some(Url::parse("http://fedora.quill.lan/rest/#Manifestation").unwrap())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn template(&self, subject: NamedNode) -> Graph {
|
||||
let subject = subject.as_ref();
|
||||
let empty_english_string_literal = LiteralRef::new_language_tagged_literal_unchecked("", "en");
|
||||
let empty_english_string_literal =
|
||||
LiteralRef::new_language_tagged_literal_unchecked("", "en");
|
||||
let empty_string_literal = LiteralRef::new_simple_literal("");
|
||||
let empty_node = NamedNodeRef::new_unchecked("");
|
||||
let hash_node = NamedNodeRef::new_unchecked("#");
|
||||
@@ -136,42 +171,86 @@ impl Class {
|
||||
Class::RdfsClass => Graph::new(),
|
||||
Class::SkosConcept => Graph::new(),
|
||||
Class::Work => Graph::from_iter([
|
||||
Triple::new(subject, vocab::rdawd::TITLE_OF_WORK, empty_english_string_literal),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdawd::TITLE_OF_WORK,
|
||||
empty_english_string_literal,
|
||||
),
|
||||
Triple::new(subject, vocab::rdawo::IDENTIFIER_FOR_WORK, empty_node),
|
||||
Triple::new(subject, vocab::rdawo::EXPRESSION_OF_WORK, empty_node),
|
||||
]),
|
||||
Class::Person => Graph::from_iter([
|
||||
Triple::new(subject, vocab::rdaad::GIVEN_NAME, empty_english_string_literal),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdaad::GIVEN_NAME,
|
||||
empty_english_string_literal,
|
||||
),
|
||||
Triple::new(subject, vocab::rdaad::SURNAME, empty_english_string_literal),
|
||||
Triple::new(subject, vocab::rdaao::IDENTIFIER_FOR_PERSON, hash_node),
|
||||
Triple::new(hash_node, vocab::rdano::SCHEME_OF_NOMEN, empty_node),
|
||||
Triple::new(hash_node, vocab::rdand::NOMEN_STRING, empty_string_literal),
|
||||
]),
|
||||
Class::CorporateBody => Graph::from_iter([
|
||||
Triple::new(subject, vocab::rdaao::IDENTIFIER_FOR_CORPORATE_BODY, hash_node),
|
||||
Triple::new(subject, vocab::rdaad::NAME_OF_CORPORATE_BODY, empty_english_string_literal),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdaao::IDENTIFIER_FOR_CORPORATE_BODY,
|
||||
hash_node,
|
||||
),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdaad::NAME_OF_CORPORATE_BODY,
|
||||
empty_english_string_literal,
|
||||
),
|
||||
Triple::new(hash_node, vocab::rdano::SCHEME_OF_NOMEN, empty_node),
|
||||
Triple::new(hash_node, vocab::rdand::NOMEN_STRING, empty_string_literal),
|
||||
]),
|
||||
Class::Expression => Graph::from_iter([
|
||||
Triple::new(subject, vocab::rdaeo::WORK_EXPRESSED, empty_node),
|
||||
Triple::new(subject, vocab::rdaeo::LANGUAGE_OF_EXPRESSION, vocab::lclang::ENGLISH),
|
||||
Triple::new(subject, vocab::rdaeo::TITLE_OF_EXPRESSION, empty_english_string_literal),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdaeo::LANGUAGE_OF_EXPRESSION,
|
||||
vocab::lclang::ENGLISH,
|
||||
),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdaeo::TITLE_OF_EXPRESSION,
|
||||
empty_english_string_literal,
|
||||
),
|
||||
Triple::new(subject, vocab::rdaeo::CONTENT_TYPE, empty_node),
|
||||
Triple::new(subject, vocab::rdaeo::MANIFESTATION_OF_EXPRESSION, empty_node),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdaeo::MANIFESTATION_OF_EXPRESSION,
|
||||
empty_node,
|
||||
),
|
||||
]),
|
||||
Class::Manifestation => Graph::from_iter([
|
||||
Triple::new(subject, vocab::rdamd::TITLE_OF_MANIFESTATION, empty_english_string_literal),
|
||||
Triple::new(subject, vocab::rdamd::UNIFORM_RESOURCE_LOCATOR, empty_string_literal),
|
||||
Triple::new(subject, vocab::rdamo::CARRIER_TYPE, vocab::rdact::ONLINE_RESOURCE),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdamd::TITLE_OF_MANIFESTATION,
|
||||
empty_english_string_literal,
|
||||
),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdamd::UNIFORM_RESOURCE_LOCATOR,
|
||||
empty_string_literal,
|
||||
),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdamo::CARRIER_TYPE,
|
||||
vocab::rdact::ONLINE_RESOURCE,
|
||||
),
|
||||
Triple::new(subject, vocab::rdamo::MEDIA_TYPE, empty_node),
|
||||
Triple::new(subject, vocab::rdamo::FILE_TYPE, empty_node),
|
||||
Triple::new(subject, vocab::rdamo::CATEGORY_OF_MANIFESTATION, empty_node),
|
||||
Triple::new(subject, vocab::rdamo::EXPRESSION_MANIFESTED, empty_node),
|
||||
Triple::new(subject, vocab::rdamo::IDENTIFIER_FOR_MANIFESTATION, hash_node),
|
||||
Triple::new(
|
||||
subject,
|
||||
vocab::rdamo::IDENTIFIER_FOR_MANIFESTATION,
|
||||
hash_node,
|
||||
),
|
||||
Triple::new(hash_node, vocab::rdano::SCHEME_OF_NOMEN, empty_node),
|
||||
Triple::new(hash_node, vocab::rdand::NOMEN_STRING, empty_string_literal),
|
||||
]),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-13
@@ -81,19 +81,24 @@ impl CurieHelper {
|
||||
}
|
||||
|
||||
pub fn expand(&self, base: Option<&Url>, abbreviated_iri: &str) -> Option<String> {
|
||||
let absolute_iri = base.and_then(|base| {
|
||||
base.join(abbreviated_iri).ok().map(|absolute| absolute.as_str().to_string())
|
||||
}).unwrap_or_else(|| abbreviated_iri.to_string());
|
||||
|
||||
absolute_iri.split_once(':')
|
||||
.and_then(|(prefix, name)| {
|
||||
if prefix.is_empty() && let Some(base) = base {
|
||||
Some(format!("{base}{name}"))
|
||||
} else {
|
||||
self.prefixes
|
||||
.get(prefix)
|
||||
.map(|base| format!("{base}{name}"))
|
||||
}
|
||||
let absolute_iri = base
|
||||
.and_then(|base| {
|
||||
base.join(abbreviated_iri)
|
||||
.ok()
|
||||
.map(|absolute| absolute.as_str().to_string())
|
||||
})
|
||||
.unwrap_or_else(|| abbreviated_iri.to_string());
|
||||
|
||||
absolute_iri.split_once(':').and_then(|(prefix, name)| {
|
||||
if prefix.is_empty()
|
||||
&& let Some(base) = base
|
||||
{
|
||||
Some(format!("{base}{name}"))
|
||||
} else {
|
||||
self.prefixes
|
||||
.get(prefix)
|
||||
.map(|base| format!("{base}{name}"))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -24,10 +24,10 @@ pub enum Error {
|
||||
|
||||
#[error(transparent)]
|
||||
UpdateEvaluation(#[from] oxigraph::sparql::UpdateEvaluationError),
|
||||
|
||||
|
||||
#[error(transparent)]
|
||||
TonicTransport(#[from] gl_inference::tonic::transport::Error),
|
||||
|
||||
|
||||
#[error(transparent)]
|
||||
TonicStatus(#[from] gl_inference::tonic::Status),
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use oxigraph::model::{NamedNode, Term, TermRef};
|
||||
use oxigraph::model::vocab::xsd;
|
||||
use crate::vocab::rdf;
|
||||
use oxigraph::model::vocab::xsd;
|
||||
use oxigraph::model::{NamedNode, Term, TermRef};
|
||||
|
||||
pub(crate) fn term_to_named_node(term: &Term) -> Option<&NamedNode> {
|
||||
if let Term::NamedNode(node) = term {
|
||||
@@ -34,4 +34,4 @@ pub(crate) fn term_ref_as_str(term: TermRef<'_>) -> Option<&str> {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+68
-48
@@ -1,12 +1,12 @@
|
||||
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;
|
||||
use crate::ontology::ResourceDescription;
|
||||
use crate::{CurieHelper, helpers, vocab};
|
||||
use gl_search::{Field, OwnedValue, Schema};
|
||||
use oxigraph::model::{Graph, NamedNode, NamedNodeRef, NamedOrBlankNodeRef, TermRef};
|
||||
use rayon::iter::IntoParallelRefIterator;
|
||||
use rayon::iter::ParallelIterator;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub struct Indexer<'a> {
|
||||
language: LanguageCondition,
|
||||
@@ -21,8 +21,14 @@ impl<'a> Indexer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_string(&self, graph: &Graph, subject: NamedNodeRef, predicate: NamedNodeRef) -> OwnedValue {
|
||||
graph.object_for_subject_predicate(subject, predicate)
|
||||
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)
|
||||
@@ -44,52 +50,46 @@ impl<'a> Indexer<'a> {
|
||||
}
|
||||
|
||||
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),
|
||||
),
|
||||
])
|
||||
HashMap::from_iter([(
|
||||
Schema::field("corporate_name", self.language.primary_language()),
|
||||
self.extract_string(graph, subject, vocab::rdaad::NAME_OF_CORPORATE_BODY),
|
||||
)])
|
||||
}
|
||||
|
||||
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),
|
||||
),
|
||||
])
|
||||
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),
|
||||
),
|
||||
])
|
||||
HashMap::from_iter([(
|
||||
Schema::field("title", self.language.primary_language()),
|
||||
self.extract_string(graph, subject, vocab::rdaed::TITLE_OF_EXPRESSION),
|
||||
)])
|
||||
}
|
||||
|
||||
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),
|
||||
),
|
||||
])
|
||||
HashMap::from_iter([(
|
||||
Schema::field("title", self.language.primary_language()),
|
||||
self.extract_string(graph, subject, vocab::rdamd::TITLE_OF_MANIFESTATION),
|
||||
)])
|
||||
}
|
||||
|
||||
pub fn graph(&self, graph: &Graph) -> Vec<HashMap<Field, OwnedValue>> {
|
||||
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 {
|
||||
if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject
|
||||
&& let TermRef::NamedNode(class) = triple.object
|
||||
{
|
||||
entities_and_types.insert((subject, class));
|
||||
}
|
||||
}
|
||||
|
||||
entities_and_types.par_iter()
|
||||
entities_and_types
|
||||
.par_iter()
|
||||
.filter_map(|(subject, class)| {
|
||||
Class::try_from_named_node(*class).and_then(|class| {
|
||||
match class {
|
||||
@@ -101,11 +101,18 @@ impl<'a> Indexer<'a> {
|
||||
Class::CorporateBody => Some(self.corporate_body(graph, *subject)),
|
||||
Class::Expression => Some(self.expression(graph, *subject)),
|
||||
Class::Manifestation => Some(self.manifestation(graph, *subject)),
|
||||
}.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()));
|
||||
}
|
||||
.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())
|
||||
let curie = self
|
||||
.curie_helper
|
||||
.abbreviate(None, subject.as_str())
|
||||
.map(OwnedValue::Str)
|
||||
.unwrap_or(OwnedValue::Null);
|
||||
document.insert(Schema::curie_field(), curie);
|
||||
@@ -113,18 +120,24 @@ impl<'a> Indexer<'a> {
|
||||
document
|
||||
})
|
||||
})
|
||||
}).collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn ontology(&self, entities: HashMap<NamedNode, ResourceDescription>) -> Vec<HashMap<Field, OwnedValue>> {
|
||||
pub fn ontology(
|
||||
&self,
|
||||
entities: HashMap<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());
|
||||
|
||||
entities.iter()
|
||||
entities
|
||||
.iter()
|
||||
.map(|(subject, description)| {
|
||||
let mut document = HashMap::with_capacity(4);
|
||||
|
||||
let discriminant = description.class
|
||||
let discriminant = description
|
||||
.class
|
||||
.as_ref()
|
||||
.and_then(|node| Class::try_from_named_node(node.as_ref()))
|
||||
.map(|doc_type| doc_type as u64)
|
||||
@@ -132,7 +145,9 @@ impl<'a> Indexer<'a> {
|
||||
.unwrap_or(OwnedValue::Null);
|
||||
document.insert(Schema::discriminant_field(), discriminant);
|
||||
|
||||
let curie = self.curie_helper.abbreviate(None, subject.as_str())
|
||||
let curie = self
|
||||
.curie_helper
|
||||
.abbreviate(None, subject.as_str())
|
||||
.map(OwnedValue::Str)
|
||||
.unwrap_or(OwnedValue::Null);
|
||||
document.insert(Schema::curie_field(), curie);
|
||||
@@ -140,17 +155,22 @@ impl<'a> Indexer<'a> {
|
||||
let subject = OwnedValue::from(subject.as_str());
|
||||
document.insert(Schema::iri_field(), subject);
|
||||
|
||||
let label = description.label.clone()
|
||||
let label = description
|
||||
.label
|
||||
.clone()
|
||||
.map(OwnedValue::from)
|
||||
.unwrap_or(OwnedValue::Null);
|
||||
document.insert(label_field, label);
|
||||
|
||||
let definition = description.description.clone()
|
||||
let definition = description
|
||||
.description
|
||||
.clone()
|
||||
.map(OwnedValue::from)
|
||||
.unwrap_or(OwnedValue::Null);
|
||||
document.insert(definition_field, definition);
|
||||
|
||||
document
|
||||
}).collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-25
@@ -1,16 +1,14 @@
|
||||
use oxigraph::model::{Literal, TermRef};
|
||||
use oxilangtag::LanguageTag;
|
||||
use std::sync::LazyLock;
|
||||
use spargebra::algebra::{Expression, Function, GraphPattern};
|
||||
use spargebra::term::Variable;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
pub static ENGLISH_TAG: LazyLock<LanguageTag<String>> = LazyLock::new(|| {
|
||||
LanguageTag::parse("en".to_string()).unwrap()
|
||||
});
|
||||
pub static ENGLISH_TAG: LazyLock<LanguageTag<String>> =
|
||||
LazyLock::new(|| LanguageTag::parse("en".to_string()).unwrap());
|
||||
|
||||
pub static ENGLISH_OR_UNTAGGED: LazyLock<LanguageCondition> = LazyLock::new(|| {
|
||||
LanguageCondition::ExactMatchOrUntagged(ENGLISH_TAG.clone())
|
||||
});
|
||||
pub static ENGLISH_OR_UNTAGGED: LazyLock<LanguageCondition> =
|
||||
LazyLock::new(|| LanguageCondition::ExactMatchOrUntagged(ENGLISH_TAG.clone()));
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum LanguageCondition {
|
||||
@@ -54,20 +52,23 @@ impl LanguageCondition {
|
||||
pub fn filter(&self, variable: impl Into<String>) -> String {
|
||||
let variable = variable.into();
|
||||
|
||||
let exact = |language: &LanguageTag<String>| Expression::FunctionCall(
|
||||
Function::LangMatches, vec![
|
||||
Expression::FunctionCall(Function::Lang, vec![
|
||||
Expression::Variable(Variable::new_unchecked(&variable))
|
||||
]),
|
||||
Expression::Literal(Literal::new_simple_literal(language.to_string()))
|
||||
],
|
||||
);
|
||||
|
||||
let untagged = Expression::Not(
|
||||
Box::new(Expression::FunctionCall(Function::HasLang, vec![
|
||||
Expression::Variable(Variable::new_unchecked(&variable))
|
||||
]))
|
||||
);
|
||||
let exact = |language: &LanguageTag<String>| {
|
||||
Expression::FunctionCall(
|
||||
Function::LangMatches,
|
||||
vec![
|
||||
Expression::FunctionCall(
|
||||
Function::Lang,
|
||||
vec![Expression::Variable(Variable::new_unchecked(&variable))],
|
||||
),
|
||||
Expression::Literal(Literal::new_simple_literal(language.to_string())),
|
||||
],
|
||||
)
|
||||
};
|
||||
|
||||
let untagged = Expression::Not(Box::new(Expression::FunctionCall(
|
||||
Function::HasLang,
|
||||
vec![Expression::Variable(Variable::new_unchecked(&variable))],
|
||||
)));
|
||||
|
||||
match self {
|
||||
Self::ExactMatchOnly(language) => Some(exact(language)),
|
||||
@@ -77,9 +78,14 @@ impl LanguageCondition {
|
||||
)),
|
||||
Self::UntaggedOnly => Some(untagged),
|
||||
Self::AnyOrNone => None,
|
||||
}.map(|expr| GraphPattern::Filter {
|
||||
expr,
|
||||
inner: Box::new(GraphPattern::Bgp { patterns: vec![] }),
|
||||
}.to_string()).unwrap_or_default()
|
||||
}
|
||||
.map(|expr| {
|
||||
GraphPattern::Filter {
|
||||
expr,
|
||||
inner: Box::new(GraphPattern::Bgp { patterns: vec![] }),
|
||||
}
|
||||
.to_string()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
mod curie;
|
||||
mod error;
|
||||
|
||||
pub mod vocab;
|
||||
pub mod class;
|
||||
pub mod category;
|
||||
pub mod language;
|
||||
pub mod class;
|
||||
mod helpers;
|
||||
pub mod indexer;
|
||||
pub mod language;
|
||||
pub mod ontology;
|
||||
pub mod vocab;
|
||||
|
||||
pub use curie::{CurieHelper, PREFIXES};
|
||||
pub use error::{Error, Result};
|
||||
pub use error::{Error, Result};
|
||||
|
||||
+49
-40
@@ -1,17 +1,19 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Debug;
|
||||
use std::str::FromStr;
|
||||
use oxigraph::io::{RdfFormat, RdfParser, RdfSerializer};
|
||||
use oxigraph::model::{Graph, NamedNode, Triple};
|
||||
use oxigraph::sparql::results::{QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput};
|
||||
use spargebra::algebra::GraphPattern;
|
||||
use spargebra::term::{GroundTerm, NamedNodePattern, TermPattern, TriplePattern, Variable};
|
||||
use gl_inference::proto::ontology_client::OntologyClient;
|
||||
use gl_inference::proto::OntologyQueryRequest;
|
||||
use gl_inference::tonic::transport::{Channel, Endpoint};
|
||||
use crate::helpers::{term_as_str, term_to_named_node};
|
||||
use crate::language::LanguageCondition;
|
||||
use crate::vocab;
|
||||
use gl_inference::proto::OntologyQueryRequest;
|
||||
use gl_inference::proto::ontology_client::OntologyClient;
|
||||
use gl_inference::tonic::transport::{Channel, Endpoint};
|
||||
use oxigraph::io::{RdfFormat, RdfParser, RdfSerializer};
|
||||
use oxigraph::model::{Graph, NamedNode, Triple};
|
||||
use oxigraph::sparql::results::{
|
||||
QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput,
|
||||
};
|
||||
use spargebra::algebra::GraphPattern;
|
||||
use spargebra::term::{GroundTerm, NamedNodePattern, TermPattern, TriplePattern, Variable};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Debug;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ResourceDescription {
|
||||
@@ -45,10 +47,7 @@ impl OntologyBuilder {
|
||||
.keep_alive_timeout(std::time::Duration::from_secs(20))
|
||||
.keep_alive_while_idle(true);
|
||||
|
||||
Ok(Self {
|
||||
endpoint,
|
||||
language,
|
||||
})
|
||||
Ok(Self { endpoint, language })
|
||||
}
|
||||
|
||||
pub async fn connect(self) -> crate::Result<ConnectedOntology> {
|
||||
@@ -78,8 +77,8 @@ impl Debug for ConnectedOntology {
|
||||
impl ConnectedOntology {
|
||||
pub async fn run_inference(&mut self, graph: &Graph) -> crate::Result<Graph> {
|
||||
let mut output_buffer = Vec::new();
|
||||
let mut serializer = RdfSerializer::from_format(RdfFormat::Turtle)
|
||||
.for_writer(output_buffer);
|
||||
let mut serializer =
|
||||
RdfSerializer::from_format(RdfFormat::Turtle).for_writer(output_buffer);
|
||||
for triple in graph {
|
||||
serializer.serialize_triple(triple)?;
|
||||
}
|
||||
@@ -110,7 +109,8 @@ SELECT ?subject ?class WHERE {
|
||||
VALUES ?class { rdf:Property rdfs:Class }
|
||||
?subject a ?class ;
|
||||
gl:readOnly "true"^^xsd:boolean .
|
||||
}"#.to_owned();
|
||||
}"#
|
||||
.to_owned();
|
||||
|
||||
let request = OntologyQueryRequest {
|
||||
sparql_query: Some(sparql_query),
|
||||
@@ -129,13 +129,11 @@ SELECT ?subject ?class WHERE {
|
||||
.and_then(term_to_named_node)
|
||||
.cloned();
|
||||
|
||||
let class = solution
|
||||
.get("class")
|
||||
.and_then(term_to_named_node)
|
||||
.cloned();
|
||||
let class = solution.get("class").and_then(term_to_named_node).cloned();
|
||||
|
||||
if let Some(subject) = subject &&
|
||||
let Some(class) = class {
|
||||
if let Some(subject) = subject
|
||||
&& let Some(class) = class
|
||||
{
|
||||
let entry = match class.as_ref() {
|
||||
vocab::rdf::PROPERTY => ReadOnlyEntity::Property(subject),
|
||||
vocab::rdfs::CLASS => ReadOnlyEntity::Class(subject),
|
||||
@@ -148,8 +146,12 @@ SELECT ?subject ?class WHERE {
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
fn selector_to_sparql_pattern(selector: ResourceSelector, nodes: impl IntoIterator<Item = NamedNode>) -> String {
|
||||
let bindings = nodes.into_iter()
|
||||
fn selector_to_sparql_pattern(
|
||||
selector: ResourceSelector,
|
||||
nodes: impl IntoIterator<Item = NamedNode>,
|
||||
) -> String {
|
||||
let bindings = nodes
|
||||
.into_iter()
|
||||
.map(GroundTerm::NamedNode)
|
||||
.map(Some)
|
||||
.map(|item| vec![item])
|
||||
@@ -181,16 +183,22 @@ SELECT ?subject ?class WHERE {
|
||||
GraphPattern::Join {
|
||||
left: Box::new(basic_pattern),
|
||||
right: Box::new(values_pattern),
|
||||
}.to_string()
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub async fn resource_descriptions(&mut self, selector: ResourceSelector, nodes: impl IntoIterator<Item = NamedNode>) -> crate::Result<HashMap<NamedNode, ResourceDescription>> {
|
||||
pub async fn resource_descriptions(
|
||||
&mut self,
|
||||
selector: ResourceSelector,
|
||||
nodes: impl IntoIterator<Item = NamedNode>,
|
||||
) -> crate::Result<HashMap<NamedNode, ResourceDescription>> {
|
||||
let pattern = Self::selector_to_sparql_pattern(selector, nodes);
|
||||
let label_filter = self.language.filter("label");
|
||||
let comment_filter = self.language.filter("comment");
|
||||
let definition_filter = self.language.filter("definition");
|
||||
|
||||
let sparql_query = format!(r#"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
||||
let sparql_query = format!(
|
||||
r#"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
|
||||
|
||||
@@ -207,7 +215,8 @@ SELECT ?subject ?label ?description ?class WHERE {{
|
||||
{definition_filter}
|
||||
}}
|
||||
BIND(COALESCE(?definition, ?comment) AS ?description)
|
||||
}}"#);
|
||||
}}"#
|
||||
);
|
||||
|
||||
let request = OntologyQueryRequest {
|
||||
sparql_query: Some(sparql_query),
|
||||
@@ -221,10 +230,7 @@ SELECT ?subject ?label ?description ?class WHERE {{
|
||||
let mut results = HashMap::new();
|
||||
if let SliceQueryResultsParserOutput::Solutions(solutions) = parser_output {
|
||||
for solution in solutions.filter_map(Result::ok) {
|
||||
let class = solution
|
||||
.get("class")
|
||||
.and_then(term_to_named_node)
|
||||
.cloned();
|
||||
let class = solution.get("class").and_then(term_to_named_node).cloned();
|
||||
|
||||
let subject = solution
|
||||
.get("subject")
|
||||
@@ -242,14 +248,17 @@ SELECT ?subject ?label ?description ?class WHERE {{
|
||||
.and_then(term_as_str)
|
||||
.map(String::from);
|
||||
|
||||
results.insert(subject, ResourceDescription {
|
||||
label,
|
||||
description,
|
||||
class,
|
||||
});
|
||||
results.insert(
|
||||
subject,
|
||||
ResourceDescription {
|
||||
label,
|
||||
description,
|
||||
class,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -171,4 +171,4 @@ pub mod skos {
|
||||
|
||||
pub const CONCEPT: NamedNodeRef =
|
||||
NamedNodeRef::new_unchecked("http://www.w3.org/2004/02/skos/core#Concept");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user