This commit is contained in:
2026-08-07 18:16:03 -04:00
parent cd47d868c1
commit 36a105edfc
14 changed files with 175 additions and 257 deletions
Generated
+1
View File
@@ -1585,6 +1585,7 @@ name = "gl-graph"
version = "0.1.0"
dependencies = [
"oxigraph",
"thiserror 2.0.19",
"tracing",
]
+1
View File
@@ -5,4 +5,5 @@ edition = "2024"
[dependencies]
oxigraph.workspace = true
thiserror.workspace = true
tracing.workspace = true
+21
View File
@@ -0,0 +1,21 @@
use thiserror::Error;
pub type Result<R> = std::result::Result<R, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
IriParse(#[from] oxigraph::model::IriParseError),
#[error(transparent)]
Storage(#[from] oxigraph::store::StorageError),
#[error(transparent)]
SparqlSyntax(#[from] oxigraph::sparql::SparqlSyntaxError),
#[error(transparent)]
QueryEvaluation(#[from] oxigraph::sparql::QueryEvaluationError),
#[error(transparent)]
UpdateEvaluation(#[from] oxigraph::sparql::UpdateEvaluationError)
}
+59
View File
@@ -0,0 +1,59 @@
use oxigraph::model::{Dataset, GraphNameRef, NamedNodeRef, Quad, QuadRef};
use oxigraph::sparql::{QueryResults, SparqlEvaluator};
use oxigraph::store::{Store, Transaction};
use tracing::{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"));
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();
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 . }
}"#)?;
query.dataset_mut().set_default_graph_as_union();
let inferences = if let QueryResults::Graph(result) = query.on_transaction(&transaction).execute()? {
result.filter_map(Result::ok)
.map(|triple| Quad::new(triple.subject, triple.predicate, triple.object, INFERENCE_GRAPH))
.collect()
} else {
Dataset::new()
};
span.record("inferences", inferences.len());
Ok(inferences)
}
impl InferenceEngine {
pub fn new(store: Store) -> Self {
Self {
ontology: store,
}
}
pub fn run(&self, dataset: &Dataset) -> crate::Result<Dataset> {
let _span = debug_span!("Inference").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)
}
}
+5
View File
@@ -1,4 +1,9 @@
mod curie;
//mod materialize;
mod error;
pub mod vocab;
pub mod inference;
pub use curie::{PREFIXES, CurieHelper};
pub use error::{Error, Result};
@@ -1,18 +1,17 @@
use crate::error;
use gl_graph::vocab::owl;
use crate::vocab;
use oxigraph::model::{Dataset, GraphName, NamedNodeRef, NamedOrBlankNode, NamedOrBlankNodeRef, Term};
use oxigraph::sparql::SparqlEvaluator;
use oxigraph::store::Store;
use tracing::{debug, debug_span};
const INFERENCE_GRAPH: NamedNodeRef = NamedNodeRef::new_unchecked("https://graphofliberty.org/inference");
const RDF_SCHEMA: NamedNodeRef = NamedNodeRef::new_unchecked("http://www.w3.org/2000/01/rdf-schema#");
pub fn same_as(store: &mut Store) -> error::Result<()> {
pub fn same_as(store: &mut Store) -> crate::Result<()> {
let _span = debug_span!("Materialize owl:sameAs").entered();
let additional_quads = store
.quads_for_pattern(None, Some(owl::SAME_AS), None, None)
.quads_for_pattern(None, Some(vocab::owl::SAME_AS), None, None)
.filter_map(Result::ok)
.fold(Dataset::new(), |mut new_dataset, alias| {
if let NamedOrBlankNode::NamedNode(x) = alias.subject
@@ -56,7 +55,7 @@ pub fn same_as(store: &mut Store) -> error::Result<()> {
Ok(())
}
pub fn super_properties(store: &mut Store) -> error::Result<()> {
pub fn super_properties(store: &mut Store) -> crate::Result<()> {
let _span = debug_span!("Materialize rdfs:subPropertyOf").entered();
let update = SparqlEvaluator::new()
@@ -85,7 +84,7 @@ pub fn super_properties(store: &mut Store) -> error::Result<()> {
Ok(())
}
pub fn super_classes(store: &mut Store) -> error::Result<()> {
pub fn super_classes(store: &mut Store) -> crate::Result<()> {
let _span = debug_span!("Materialize rdfs:subClassOf").entered();
let update = SparqlEvaluator::new()
-201
View File
@@ -87,11 +87,6 @@ xsd:unsignedShort rdf:type rdfs:Datatype ;
# Object Properties
#################################################################
### https://graphofliberty.org/2026/04/ont/associatedProperty
:associatedProperty rdf:type owl:ObjectProperty ;
rdfs:label "associated property"@en .
### https://graphofliberty.org/2026/04/ont/derivedWith
:derivedWith rdf:type owl:ObjectProperty ;
rdfs:range :DerivationMethodology ;
@@ -99,62 +94,10 @@ xsd:unsignedShort rdf:type rdfs:Datatype ;
rdfs:label "derived with"@en .
### https://graphofliberty.org/2026/04/ont/indexDocument
:indexDocument rdf:type owl:ObjectProperty ;
rdfs:range :IndexDocument ;
rdfs:comment "Relates an entity to an Index Document."@en ;
rdfs:label "has index document"@en .
### https://graphofliberty.org/2026/04/ont/indexedByField
:indexedByField rdf:type owl:ObjectProperty ;
rdfs:range :IndexDocumentField ;
rdfs:comment "The property is associated with the given field in a full-text search database."@en ;
rdfs:label "indexed by field"@en .
### https://graphofliberty.org/2026/04/ont/subtitles
:subtitles rdf:type owl:ObjectProperty ;
rdfs:comment "Relates an entity to a File which contains subtitles for the entity."@en ;
rdfs:label "has subtitles"@en .
### https://graphofliberty.org/2026/04/ont/template
:template rdf:type owl:ObjectProperty ;
rdfs:comment "A default set of triples used during the creation of new entities of the associated class."@en ;
rdfs:label "has template"@en .
#################################################################
# Data properties
#################################################################
### https://graphofliberty.org/2026/04/ont/categoryId
:categoryId rdf:type owl:DatatypeProperty ;
rdfs:domain :SearchableClass ;
rdfs:range xsd:nonNegativeInteger ;
rdfs:comment "An integer associated with the class for fast lookup in a database."@en ;
rdfs:label "category id" .
### https://graphofliberty.org/2026/04/ont/fieldLabel
:fieldLabel rdf:type owl:DatatypeProperty ;
rdfs:domain :IndexDocumentField ;
rdfs:range rdf:dirLangString ,
rdf:langString ,
xsd:string ;
rdfs:comment "The label of a field, which shall be displayed to the user."@en ;
rdfs:label "field label"@en .
### https://graphofliberty.org/2026/04/ont/fieldName
:fieldName rdf:type owl:DatatypeProperty ;
rdfs:domain :IndexDocumentField ;
rdfs:range xsd:string ;
rdfs:comment "The name of the field, as defined in the full-text search document schema."@en ;
rdfs:label "field name"@en .
### https://graphofliberty.org/2026/04/ont/readOnly
:readOnly rdf:type owl:DatatypeProperty ;
rdfs:comment "Indicates that the property or class is read only (server managed) and should not be made editable in user-facing applications."@en ;
@@ -165,47 +108,12 @@ xsd:unsignedShort rdf:type rdfs:Datatype ;
# Classes
#################################################################
### https://graphofliberty.org/2026/04/ont/AudioBook
:AudioBook rdf:type owl:Class ;
rdfs:subClassOf :Entity .
### https://graphofliberty.org/2026/04/ont/DerivationMethodology
:DerivationMethodology rdf:type owl:Class ;
rdfs:comment "The methodology used to derive content. Individuals of this class should provide enough information to replicate the process by which the content was generated. For example, if Whisper was used derive captions for an audio book, the precise model used (e.g. large v3), a link to the source code (e.g. HuggingFace) and/or a paper should be provided."@en ;
rdfs:label "Derivation Methodology"@en .
### https://graphofliberty.org/2026/04/ont/Entity
:Entity rdf:type owl:Class ;
rdfs:comment "An Entity is a first-class citizen of the Graph of Liberty catalog. It is the class of all cultural artifacts which are to be preserved."@en ;
rdfs:label "Graph of Liberty Entity"@en .
### https://graphofliberty.org/2026/04/ont/IndexDocument
:IndexDocument rdf:type owl:Class ;
rdfs:comment "A document which is intended to be passed verbatim to a full-text search engine for indexing."@en ;
rdfs:label "Index Document"@en .
### https://graphofliberty.org/2026/04/ont/IndexDocumentField
:IndexDocumentField rdf:type owl:Class ;
rdfs:comment "Describes a single field present within a document that is indexed in a full-text search database."@en ;
rdfs:label "Index Document Field"@en .
### https://graphofliberty.org/2026/04/ont/SearchableClass
:SearchableClass rdf:type owl:Class ;
rdfs:comment "The class of classes which are to be indexed in the full-text search database."@en ;
rdfs:label "Searchable Class"@en .
### https://graphofliberty.org/2026/04/ont/Transcription
:Transcription rdf:type owl:Class ;
rdfs:comment "A structured or unstructured textual file which contains a transcription of an audio file."@en ;
rdfs:label "Transcription"@en .
#################################################################
# Individuals
#################################################################
@@ -255,24 +163,6 @@ fedora:lastModifiedBy rdf:type owl:NamedIndividual ;
:readOnly "true"^^xsd:boolean .
### http://rdaregistry.info/Elements/a/datatype/P50291
<http://rdaregistry.info/Elements/a/datatype/P50291> rdf:type owl:NamedIndividual ;
:indexedByField :Surname .
### http://rdaregistry.info/Elements/a/datatype/P50292
<http://rdaregistry.info/Elements/a/datatype/P50292> rdf:type owl:NamedIndividual ;
:indexedByField :GivenName .
### http://rdaregistry.info/Elements/c/C10004
rdac:C10004 rdf:type owl:NamedIndividual ,
:SearchableClass ;
:associatedProperty <http://rdaregistry.info/Elements/a/datatype/P50291> ,
<http://rdaregistry.info/Elements/a/datatype/P50292> ;
:categoryId "3"^^xsd:nonNegativeInteger .
### http://www.loc.gov/premis/rdf/v1#hasMessageDigest
premis:hasMessageDigest rdf:type owl:NamedIndividual ;
:readOnly "true"^^xsd:boolean .
@@ -293,52 +183,6 @@ premis3:size rdf:type owl:NamedIndividual ;
:readOnly "true"^^xsd:boolean .
### http://www.w3.org/1999/02/22-rdf-syntax-ns#Property
rdf:Property rdf:type owl:NamedIndividual ,
:SearchableClass ;
:associatedProperty rdfs:comment ,
rdfs:label ,
skos:definition ;
:categoryId "0"^^xsd:nonNegativeInteger .
### http://www.w3.org/2000/01/rdf-schema#Class
rdfs:Class rdf:type owl:NamedIndividual ,
:SearchableClass ;
:associatedProperty rdfs:comment ,
rdfs:label ,
skos:definition ;
:categoryId "1"^^xsd:nonNegativeInteger .
### http://www.w3.org/2000/01/rdf-schema#comment
rdfs:comment rdf:type owl:NamedIndividual ;
:indexedByField :Definition .
### http://www.w3.org/2000/01/rdf-schema#label
rdfs:label rdf:type owl:NamedIndividual ;
:indexedByField :Label .
### http://www.w3.org/2004/02/skos/core#Concept
skos:Concept rdf:type owl:NamedIndividual ,
:SearchableClass ;
:associatedProperty skos:definition ,
skos:prefLabel ;
:categoryId "2"^^xsd:nonNegativeInteger .
### http://www.w3.org/2004/02/skos/core#definition
skos:definition rdf:type owl:NamedIndividual ;
:indexedByField :Definition .
### http://www.w3.org/2004/02/skos/core#prefLabel
skos:prefLabel rdf:type owl:NamedIndividual ;
:indexedByField :Label .
### http://www.w3.org/ns/ldp#BasicContainer
ldp:BasicContainer rdf:type owl:NamedIndividual ;
:readOnly "true"^^xsd:boolean .
@@ -369,49 +213,4 @@ ldp:contains rdf:type owl:NamedIndividual ;
:readOnly "true"^^xsd:boolean .
### https://graphofliberty.org/2026/04/ont/AudioBook
:AudioBook rdf:type owl:NamedIndividual ,
:SearchableClass ;
:categoryId "4"^^xsd:nonNegativeInteger .
### https://graphofliberty.org/2026/04/ont/Definition
:Definition rdf:type owl:NamedIndividual ,
:IndexDocumentField ;
:fieldLabel "Definition"@en ;
:fieldName "definition" ;
rdfs:label "Definition Field"@en .
### https://graphofliberty.org/2026/04/ont/GivenName
:GivenName rdf:type owl:NamedIndividual ,
:IndexDocumentField ;
:fieldLabel "Given Name"@en ;
:fieldName "given_name" ;
rdfs:label "Given Name Field"@en .
### https://graphofliberty.org/2026/04/ont/Label
:Label rdf:type owl:NamedIndividual ,
:IndexDocumentField ;
:fieldLabel "Label"@en ;
:fieldName "label" ;
rdfs:label "Label Field"@en .
### https://graphofliberty.org/2026/04/ont/Surname
:Surname rdf:type owl:NamedIndividual ,
:IndexDocumentField ;
:fieldLabel "Surname"@en ;
:fieldName "surname" ;
rdfs:label "Surname Field"@en .
#################################################################
# Annotations
#################################################################
:AudioBook rdfs:label "Audio Book"@en .
### Generated by the OWL API (version 4.5.29.2024-05-13T12:11:03Z) https://github.com/owlcs/owlapi
+2 -2
View File
@@ -733,10 +733,10 @@ impl Publisher {
text_input("Query", &search_state.query).on_input(Message::QueryUpdated)
.id("query");
let entities = self.ontology
let entities = Vec::new(); /*self.ontology
.searchable_classes(&*language::ENGLISH_OR_UNTAGGED)
.into_iter()
.collect::<Vec<_>>();
.collect::<Vec<_>>();*/
let type_selector = pick_list(search_state.entity_selection.as_ref(), entities, ToString::to_string)
.on_select(|selection| Message::QueryTypeUpdated(selection));
+11
View File
@@ -1,5 +1,15 @@
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand};
#[derive(Args)]
pub(crate) struct QueryArgs {
#[arg(short, long, value_name = "DATASET PATH")]
pub(crate) dataset_path: PathBuf,
#[arg(short, long, value_name = "QUERY PATH")]
pub(crate) query_path: PathBuf,
}
#[derive(Args)]
pub(crate) struct SearchArgs {
#[arg(short, long, value_name = "DOC TYPE")]
@@ -11,6 +21,7 @@ pub(crate) struct SearchArgs {
#[derive(Subcommand)]
pub(crate) enum Command {
Query(QueryArgs),
Search(SearchArgs),
Reindex,
}
+63 -13
View File
@@ -7,18 +7,25 @@ mod navigator;
mod theme;
mod args;
use std::fs::File;
use clap::Parser;
use iced::futures::StreamExt;
use ldp::middleware::BasicAuthMiddleware;
use ldp::reqwest::{Client, Url};
use ldp::reqwest_middleware::ClientBuilder;
use ldp::traverse::Traverse;
use oxigraph::io::{RdfFormat, RdfParser, RdfSerializer};
use oxigraph::model::{Dataset, Graph, GraphName, GraphNameRef, NamedNode, Quad, Triple};
use oxigraph::sparql::{QueryResults, SparqlEvaluator};
use oxigraph::sparql::results::{QueryResultsFormat, QueryResultsSerializer};
use oxigraph::store::Store;
use tracing::{debug, debug_span, error, field};
use crate::app::Publisher;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{EnvFilter, fmt};
use tracing_subscriber::fmt::format::FmtSpan;
use gl_graph::inference::InferenceEngine;
use gl_search::{Document, Schema, SearchIndex};
use crate::args::{AppArgs, Command};
use crate::rdf::ontology::Ontology;
@@ -31,10 +38,8 @@ fn main() -> color_eyre::Result<()> {
.init();
color_eyre::install()?;
let ontology = Ontology::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/ontology")
.build()
.expect("Failed to build ontology");
let store = Store::open("/home/alex/.local/share/org.graphofliberty.desktop/ontology")?;
let inference_engine = InferenceEngine::new(store.clone());
let mut index = SearchIndex::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
@@ -43,11 +48,49 @@ fn main() -> color_eyre::Result<()> {
let args = AppArgs::parse();
match args.command {
Some(Command::Search(args)) => {
for doc in index.query(args.discriminant, &args.query, Schema::all_fields(), 500000)? {
println!("{}", doc.to_json(Schema::schema()));
Some(Command::Query(args)) => {
let graph_name = GraphName::NamedNode(NamedNode::new_unchecked(format!("file://{}", args.dataset_path.to_string_lossy())));
let mut dataset = RdfParser::from_format(RdfFormat::Turtle)
.with_default_graph(graph_name)
.for_reader(File::open(&args.dataset_path)?)
.filter_map(Result::ok)
.collect::<Dataset>();
let inferences = inference_engine.run(&dataset)?;
dataset.extend(&inferences);
let raw_query = String::from_utf8(std::fs::read(&args.query_path)?)?;
let mut query = SparqlEvaluator::new()
.parse_query(&raw_query)?;
query.dataset_mut().set_default_graph_as_union();
match query.on_queryable_dataset(&dataset).execute()? {
QueryResults::Graph(graph) => {
let mut serializer = RdfSerializer::from_format(RdfFormat::Turtle)
.for_writer(std::io::stdout());
for triple in graph.filter_map(Result::ok) {
serializer.serialize_triple(triple.as_ref())?;
}
serializer.finish()?;
}
QueryResults::Solutions(solutions) => {
let json_serializer = QueryResultsSerializer::from_format(QueryResultsFormat::Json);
let mut writer = json_serializer.serialize_solutions_to_writer(std::io::stdout(), Vec::from_iter(solutions.variables().iter().cloned()))?;
for solution in solutions.filter_map(Result::ok) {
writer.serialize(&solution)?;
}
writer.finish()?;
}
QueryResults::Boolean(result) => {
let json_serializer = QueryResultsSerializer::from_format(QueryResultsFormat::Json);
json_serializer.serialize_boolean_to_writer(std::io::stdout(), result)?;
}
}
}
Some(Command::Search(args)) => {
/*for doc in index.query(args.discriminant, &args.query, Schema::all_fields(), 500000)? {
println!("{}", doc.to_json(Schema::schema()));
}*/
}
Some(Command::Reindex) => {
let mut writer = index.writer()?;
debug_span!("Clear Index").in_scope(|| {
@@ -57,7 +100,6 @@ fn main() -> color_eyre::Result<()> {
{
let span = debug_span!("Index Schema", documents = field::Empty).entered();
let store = ontology.store();
let count = gl_search::rdf::index_schema(store, &*gl_search::language::ENGLISH_OR_UNTAGGED, &writer)?;
span.record("documents", count);
}
@@ -76,17 +118,25 @@ fn main() -> color_eyre::Result<()> {
))
.build();
let mut documents = 0usize;
let mut rdf_source_count = 0usize;
let mut dataset = Dataset::new();
let mut traversal = Traverse::new(http_client, starting_url, None);
while let Some(result) = traversal.next().await {
match result {
Ok(rdf_source) => {
documents += gl_search::rdf::index_entity(rdf_source.dataset(), &*gl_search::language::ENGLISH_OR_UNTAGGED, &writer)?;
}
Ok(rdf_source) => dataset.extend(rdf_source.dataset()),
Err(err) => error!(?err),
}
rdf_source_count += 1;
}
debug!(documents, "Repository Traversal");
let inferences = inference_engine.run(&dataset).unwrap();
dataset.extend(&inferences);
let span = debug_span!("Index Repository", rdf_sources = field::Empty, documents = field::Empty).entered();
let document_count = gl_search::rdf::index_entity(&dataset, &*gl_search::language::ENGLISH_OR_UNTAGGED, &writer)?;
span.record("rdf_sources", rdf_source_count);
span.record("documents", document_count);
Ok::<_, gl_search::SearchError>(writer)
});
-1
View File
@@ -1,4 +1,3 @@
pub(crate) mod ontology;
pub(crate) mod term_helper;
pub(crate) mod materialize;
pub(crate) mod conversion;
+1 -27
View File
@@ -1,5 +1,5 @@
use crate::error;
use crate::rdf::{conversion, materialize};
use crate::rdf::conversion;
use gl_graph::vocab::gl;
use gl_search::language::LanguageCondition;
use iced::futures::TryFutureExt;
@@ -91,13 +91,6 @@ impl OntologyBuilder {
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect::<HashMap<String, String>>();
if self.materialize_inferences {
materialize::same_as(&mut store)?;
materialize::super_properties(&mut store)?;
materialize::super_classes(&mut store)?;
debug_span!("Optimize Ontology").in_scope(|| store.optimize())?;
}
let mut indexed_by = HashMap::new();
for quad in store.quads_for_pattern(None, Some(gl::INDEXED_BY_FIELD), None, None)
.filter_map(Result::ok) {
@@ -297,25 +290,6 @@ WHERE {{
}
}
pub fn searchable_classes(&self, language: &LanguageCondition) -> BTreeSet<LabeledIri> {
self.store.quads_for_pattern(None, Some(rdf::TYPE), Some(gl::SEARCHABLE_CLASS.into()), None)
.filter_map(Result::ok)
.filter_map(|quad| {
let label = self.store.quads_for_pattern(Some(quad.subject.as_ref().into()), Some(rdfs::LABEL), None, None)
.filter_map(Result::ok)
.map(conversion::quad_into_term)
.filter(|term| language.primary_matches_term(term))
.filter_map(conversion::term_into_string)
.next();
if let Some(label) = label && let NamedOrBlankNode::NamedNode(subject) = quad.subject {
Some(LabeledIri {
iri: subject,
label,
})
} else { None }
}).collect()
}
pub fn subclasses_of(&self, class: &NamedNode) -> BTreeSet<NamedNode> {
self.store.quads_for_pattern(None, Some(rdfs::SUB_CLASS_OF), Some(class.into()), None)
.filter_map(Result::ok)
+1 -1
View File
@@ -41,7 +41,7 @@ impl DocType {
}
}
pub fn from_named_node<'a>(node: impl Into<NamedNodeRef<'a>>) -> Option<Self> {
pub fn try_from_named_node<'a>(node: impl Into<NamedNodeRef<'a>>) -> Option<Self> {
let node = node.into();
match node {
vocab::rdf::PROPERTY => Some(DocType::RdfProperty),
+2 -3
View File
@@ -5,7 +5,6 @@ use oxigraph::sparql::{QueryResults, SparqlEvaluator};
use oxigraph::store::Store;
use tantivy::IndexWriter;
use tantivy::schema::{Field, OwnedValue};
use tracing::debug;
use gl_graph::{vocab, CurieHelper};
use crate::DocType;
use crate::language::LanguageCondition;
@@ -68,7 +67,7 @@ pub fn index_entity(dataset: &Dataset, language: &LanguageCondition, writer: &In
let mut counter = 0usize;
for (subject, types) in subject_type_map {
for type_ in types {
if let Some(doc_type) = term_ref_as_named_node(type_).and_then(DocType::from_named_node) {
if let Some(doc_type) = term_ref_as_named_node(type_).and_then(DocType::try_from_named_node) {
let mut doc = match doc_type {
DocType::Person => index_person(dataset, subject, language),
DocType::CorporateBody => index_corporate_body(dataset, subject, language),
@@ -170,7 +169,7 @@ pub fn index_schema(store: Store, language: &LanguageCondition, writer: &IndexWr
let discriminant = solution.get("class")
.and_then(term_to_named_node)
.and_then(DocType::from_named_node)
.and_then(DocType::try_from_named_node)
.map(|doc_type| doc_type as u64)
.map(OwnedValue::U64)
.unwrap_or(OwnedValue::Null);