Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Make ontology cache data fields private and move access into methods #3448

Draft
wants to merge 6 commits into
base: wip/minor-refactoring
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ final case class InferenceOptimizationService(
* if so, all ontologies defined by the project to which the data belongs, will be included in the results.
*
* @param entity an RDF entity.
* @param map a map of entity IRIs to the IRIs of the ontology where they are defined.
* @param lookup a function optionally defining the ontology in an entity is defined.
* @return a sequence of ontology IRIs which relate to the input RDF entity.
*/
private def resolveEntity(entity: Entity, map: Map[SmartIri, SmartIri]): Task[Seq[SmartIri]] =
private def resolveEntity(entity: Entity, lookup: SmartIri => Option[SmartIri]): Task[Seq[SmartIri]] =
entity match {
case IriRef(iri, _) =>
val internal = iri.toOntologySchema(InternalSchema)
val maybeOntoIri = map.get(internal)
val maybeOntoIri = lookup(internal)
maybeOntoIri match {
// if the map contains an ontology IRI corresponding to the entity IRI, then this can be returned
case Some(iri) => ZIO.succeed(Seq(iri))
Expand Down Expand Up @@ -105,10 +105,8 @@ final case class InferenceOptimizationService(

for {
ontoCache <- ontologyCache.getCacheData
// from the cache, get the map from entity to the ontology where the entity is defined
entityMap = ontoCache.entityDefinedInOntology
// resolve all entities from the WHERE clause to the ontology where they are defined
relevantOntologies <- ZIO.foreach(entities)(resolveEntity(_, entityMap))
relevantOntologies <- ZIO.foreach(entities)(resolveEntity(_, ontoCache.entityDefinedInOntology))
relevantOntologiesSet = relevantOntologies.flatten.toSet
relevantOntologiesMaybe =
relevantOntologiesSet match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ final case class OntologyInferencer(
}
} yield {
// look up subclasses from ontology cache
val knownSubClasses = cache.classToSubclassLookup.get(baseClassIri.iri).getOrElse(Set(baseClassIri.iri)).toSeq
val knownSubClasses = cache.getSubClassesOf(baseClassIri.iri).getOrElse(Set(baseClassIri.iri)).toSeq

// if provided, limit the child classes to those that belong to relevant ontologies
val subClasses = limitInferenceToOntologies match {
case None => knownSubClasses
case Some(relevantOntologyIris) =>
// filter the known subclasses against the relevant ontologies
knownSubClasses.filter(cache.classDefinedInOntology.get(_).exists(relevantOntologyIris.contains(_)))
knownSubClasses.filter(cache.classDefinedInOntology(_).exists(relevantOntologyIris.contains(_)))
}

// Searches for a `?v a <subClassIRI>`, or if multiple subclasses are present, then
Expand All @@ -63,12 +63,12 @@ final case class OntologyInferencer(
queryVariableSuffix: Option[String],
): Seq[QueryPattern] = {
// look up subproperties from ontology cache
val knownSubProps = cache.superPropertyOfRelations.get(predIri).getOrElse(Set(predIri)).toSeq
val knownSubProps = cache.getSubPropertiesOf(predIri).getOrElse(Set(predIri)).toSeq

// if provided, limit the child properties to those that belong to relevant ontologies
val subProps = limitInferenceToOntologies match {
case Some(ontologyIris) =>
knownSubProps.filter(cache.propertyDefinedInOntology.get(_).exists(ontologyIris.contains(_)))
knownSubProps.filter(cache.propertyDefinedInOntology(_).exists(ontologyIris.contains(_)))
case None => knownSubProps
}
// Searches for a `?v <propertyIRI> ?b`, or if multiple propertyIRIs are present, then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,12 @@ final case class OntologyResponderV2(
}
}.toMap

propertyDefsAvailable = propertyOntologies.flatMap { ontology =>
ontology.properties.filter { case (propertyIri, _) =>
standoffPropertyIris.contains(propertyIri) && cacheData.standoffProperties.contains(
propertyIri,
)
}
}.toMap
propertyDefsAvailable =
propertyOntologies.flatMap { ontology =>
ontology.properties.filter { case (propertyIri, _) =>
standoffPropertyIris.contains(propertyIri) && cacheData.containsStandoffProperty(propertyIri)
}
}.toMap

missingClassDefs = classIrisForCache -- classDefsAvailable.keySet
missingPropertyDefs = propertyIrisForCache -- propertyDefsAvailable.keySet
Expand Down Expand Up @@ -248,10 +247,9 @@ final case class OntologyResponderV2(
* @return a [[StandoffAllPropertyEntitiesGetResponseV2]].
*/
private def getAllStandoffPropertyEntitiesV2: Task[StandoffAllPropertyEntitiesGetResponseV2] =
ontologyCache.getCacheData.map { data =>
val ontologies: Iterable[ReadOntologyV2] = data.ontologies.values
ontologies.flatMap(_.properties.view.filterKeys(data.standoffProperties)).toMap
}.map(StandoffAllPropertyEntitiesGetResponseV2.apply)
ontologyCache.getCacheData
.map(_.getAllStandoffPropertyEntities)
.map(StandoffAllPropertyEntitiesGetResponseV2.apply)

/**
* Checks whether a certain Knora resource or value class is a subclass of another class.
Expand All @@ -264,7 +262,7 @@ final case class OntologyResponderV2(
for {
cacheData <- ontologyCache.getCacheData
isSubClass <- ZIO
.fromOption(cacheData.classToSuperClassLookup.get(subClassIri))
.fromOption(cacheData.getSuperClassesOf(subClassIri))
.map(_.contains(superClassIri))
.orElseFail(BadRequestException(s"Class $subClassIri not found"))
} yield CheckSubClassResponseV2(isSubClass)
Expand All @@ -279,7 +277,7 @@ final case class OntologyResponderV2(
for {
cacheData <- ontologyCache.getCacheData
subClasses <-
ZIO.foreach(cacheData.classToSubclassLookup(classIri).toVector.sorted) { subClassIri =>
ZIO.foreach(cacheData.getSubClassesOf(classIri).get.toVector.sorted) { subClassIri =>
val labelValueMaybe = cacheData
.ontologies(subClassIri.getOntologyFromEntity)
.classes(subClassIri)
Expand Down Expand Up @@ -786,8 +784,9 @@ final case class OntologyResponderV2(
// Check for rdfs:subClassOf cycles.

allBaseClassIrisWithoutSelf: Set[SmartIri] = internalClassDef.subClassOf.flatMap { baseClassIri =>
cacheData.classToSuperClassLookup
.getOrElse(baseClassIri, Set.empty[SmartIri])
cacheData
.getSuperClassesOf(baseClassIri)
.getOrElse(Set.empty[SmartIri])
.toSet
}

Expand Down Expand Up @@ -1147,10 +1146,11 @@ final case class OntologyResponderV2(
// Check that the new cardinalities are valid, and add any inherited cardinalities.

allBaseClassIrisWithoutInternal = newInternalClassDef.subClassOf.toSeq.flatMap { baseClassIri =>
cacheData.classToSuperClassLookup.getOrElse(
baseClassIri,
Seq.empty[SmartIri],
)
cacheData
.getSuperClassesOf(baseClassIri)
.getOrElse(
Seq.empty[SmartIri],
)
}

allBaseClassIris = internalClassIri +: allBaseClassIrisWithoutInternal
Expand Down Expand Up @@ -1320,10 +1320,11 @@ final case class OntologyResponderV2(
// Check that the new cardinalities are valid, and don't add any inherited cardinalities.
newInternalClassDef = oldClassInfo.copy(directCardinalities = newClassInfo.directCardinalities)
allBaseClassIrisWithoutInternal = newInternalClassDef.subClassOf.toSeq.flatMap { baseClassIri =>
cacheData.classToSuperClassLookup.getOrElse(
baseClassIri,
Seq.empty[SmartIri],
)
cacheData
.getSuperClassesOf(baseClassIri)
.getOrElse(
Seq.empty[SmartIri],
)
}

allBaseClassIris = classIri +: allBaseClassIrisWithoutInternal
Expand Down Expand Up @@ -1976,10 +1977,11 @@ final case class OntologyResponderV2(
// Check for rdfs:subPropertyOf cycles.

allKnoraSuperPropertyIrisWithoutSelf: Set[SmartIri] = knoraSuperProperties.flatMap { superPropertyIri =>
cacheData.subPropertyOfRelations.getOrElse(
superPropertyIri,
Set.empty[SmartIri],
)
cacheData
.getSuperPropertiesOf(superPropertyIri)
.getOrElse(
Set.empty[SmartIri],
)
}

_ <- ZIO.when(allKnoraSuperPropertyIrisWithoutSelf.contains(internalPropertyIri)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,7 @@ final case class CardinalityHandler(

allBaseClassIrisWithoutInternal =
newClassDefinitionWithRemovedCardinality.subClassOf.toSeq.flatMap { baseClassIri =>
cacheData.classToSuperClassLookup.getOrElse(
baseClassIri,
Seq.empty[SmartIri],
)
cacheData.getSuperClassesOf(baseClassIri).getOrElse(Seq.empty[SmartIri])
}

allBaseClassIris = internalClassIri +: allBaseClassIrisWithoutInternal
Expand Down Expand Up @@ -242,10 +239,7 @@ final case class CardinalityHandler(

allBaseClassIrisWithoutInternal =
newClassDefinitionWithRemovedCardinality.subClassOf.toSeq.flatMap { baseClassIri =>
cacheData.classToSuperClassLookup.getOrElse(
baseClassIri,
Seq.empty[SmartIri],
)
cacheData.getSuperClassesOf(baseClassIri).getOrElse(Seq.empty[SmartIri])
}

allBaseClassIris = internalClassIri +: allBaseClassIrisWithoutInternal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ object OntologyHelpers {
directClassCardinalities: Map[SmartIri, Map[SmartIri, KnoraCardinalityInfo]],
classCardinalitiesWithInheritance: Map[SmartIri, Map[SmartIri, KnoraCardinalityInfo]],
allSubClassOfRelations: Map[SmartIri, Seq[SmartIri]],
allSubPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
superPropertyLookup: SmartIri => Option[Set[SmartIri]],
allPropertyDefs: Map[SmartIri, PropertyInfoContentV2],
allKnoraResourceProps: Set[SmartIri],
allLinkProps: Set[SmartIri],
Expand Down Expand Up @@ -266,7 +266,7 @@ object OntologyHelpers {

val maybePropertyAndSubproperty: Option[(SmartIri, SmartIri)] = OntologyHelpers.findPropertyAndSubproperty(
propertyIris = allPropertyIrisForCardinalitiesInClass,
subPropertyOfRelations = allSubPropertyOfRelations,
superPropertyLookup = superPropertyLookup,
)

maybePropertyAndSubproperty match {
Expand Down Expand Up @@ -875,11 +875,11 @@ object OntologyHelpers {
*/
private def findPropertyAndSubproperty(
propertyIris: Set[SmartIri],
subPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
superPropertyLookup: SmartIri => Option[Set[SmartIri]],
): Option[(SmartIri, SmartIri)] =
propertyIris.flatMap { propertyIri =>
val maybeBasePropertyIri: Option[SmartIri] = (propertyIris - propertyIri).find { otherPropertyIri =>
subPropertyOfRelations.get(propertyIri).exists { (baseProperties: Set[SmartIri]) =>
superPropertyLookup(propertyIri).exists { (baseProperties: Set[SmartIri]) =>
baseProperties.contains(otherPropertyIri)
}
}
Expand Down Expand Up @@ -1038,7 +1038,7 @@ object OntologyHelpers {
classIri = internalClassDef.classIri,
thisClassCardinalities = classDefWithAddedLinkValueProps.directCardinalities,
inheritableCardinalities = cardinalitiesAvailableToInherit,
allSubPropertyOfRelations = cacheData.subPropertyOfRelations,
superPropertyLookup = cacheData.getSuperPropertiesOf,
errorSchema = ApiV2Complex,
errorFun = { msg => throw BadRequestException(msg) },
),
Expand Down Expand Up @@ -1079,7 +1079,7 @@ object OntologyHelpers {

_ <- findPropertyAndSubproperty(
propertyIris = cardinalitiesForClassWithInheritance.keySet,
subPropertyOfRelations = cacheData.subPropertyOfRelations,
superPropertyLookup = cacheData.getSuperPropertiesOf,
) match {
case Some((basePropertyIri, propertyIri)) =>
Validation.fail(
Expand Down Expand Up @@ -1158,7 +1158,7 @@ object OntologyHelpers {
classIri: SmartIri,
thisClassCardinalities: Map[SmartIri, KnoraCardinalityInfo],
inheritableCardinalities: Map[SmartIri, KnoraCardinalityInfo],
allSubPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
superPropertyLookup: SmartIri => Option[Set[SmartIri]],
errorSchema: OntologySchema,
errorFun: String => Nothing,
): Map[SmartIri, KnoraCardinalityInfo] = {
Expand All @@ -1169,7 +1169,7 @@ object OntologyHelpers {
// If the class has a cardinality for a non-Knora property like rdfs:label (which can happen only
// if it's a built-in class), we won't have any information about the base properties of that property.
val basePropsOfThisClassProp: Set[SmartIri] =
allSubPropertyOfRelations.getOrElse(thisClassProp, Set.empty[SmartIri])
superPropertyLookup(thisClassProp).getOrElse(Set.empty[SmartIri])

val overriddenBaseProps: Set[SmartIri] = inheritableCardinalities.foldLeft(Set.empty[SmartIri]) {
case (acc, (baseClassProp, baseClassCardinality)) =>
Expand Down Expand Up @@ -1377,7 +1377,7 @@ object OntologyHelpers {
def inheritCardinalitiesInLoadedClass(
classIri: SmartIri,
directSubClassOfRelations: Map[SmartIri, Set[SmartIri]],
allSubPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
superPropertyLookup: SmartIri => Option[Set[SmartIri]],
directClassCardinalities: Map[SmartIri, Map[SmartIri, KnoraCardinalityInfo]],
): Map[SmartIri, KnoraCardinalityInfo] = {
// Recursively get properties that are available to inherit from base classes. If we have no information about
Expand All @@ -1390,7 +1390,7 @@ object OntologyHelpers {
acc ++ inheritCardinalitiesInLoadedClass(
classIri = baseClass,
directSubClassOfRelations = directSubClassOfRelations,
allSubPropertyOfRelations = allSubPropertyOfRelations,
superPropertyLookup = superPropertyLookup,
directClassCardinalities = directClassCardinalities,
)
}
Expand All @@ -1405,7 +1405,7 @@ object OntologyHelpers {
classIri = classIri,
thisClassCardinalities = thisClassCardinalities,
inheritableCardinalities = cardinalitiesAvailableToInherit,
allSubPropertyOfRelations = allSubPropertyOfRelations,
superPropertyLookup = superPropertyLookup,
errorSchema = InternalSchema,
(msg: String) => throw InconsistentRepositoryDataException(msg),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package org.knora.webapi.slice.ontology.repo.model
import org.knora.webapi.messages.SmartIri
import org.knora.webapi.messages.v2.responder.ontologymessages.PropertyInfoContentV2
import org.knora.webapi.messages.v2.responder.ontologymessages.ReadOntologyV2
import org.knora.webapi.messages.v2.responder.ontologymessages.ReadPropertyInfoV2

/**
* The in-memory cache of ontologies.
Expand All @@ -23,20 +24,35 @@ import org.knora.webapi.messages.v2.responder.ontologymessages.ReadOntologyV2
*/
case class OntologyCacheData(
ontologies: Map[SmartIri, ReadOntologyV2],
classToSuperClassLookup: Map[SmartIri, Seq[SmartIri]],
classToSubclassLookup: Map[SmartIri, Set[SmartIri]],
subPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
superPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
classDefinedInOntology: Map[SmartIri, SmartIri],
propertyDefinedInOntology: Map[SmartIri, SmartIri],
entityDefinedInOntology: Map[SmartIri, SmartIri],
standoffProperties: Set[SmartIri],
private val classToSuperClassLookup: Map[SmartIri, Seq[SmartIri]],
private val classToSubclassLookup: Map[SmartIri, Set[SmartIri]],
private val subPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
private val superPropertyOfRelations: Map[SmartIri, Set[SmartIri]],
private val classDefinedInOntology: Map[SmartIri, SmartIri],
private val propertyDefinedInOntology: Map[SmartIri, SmartIri],
private val entityDefinedInOntology: Map[SmartIri, SmartIri],
private val standoffProperties: Set[SmartIri],
) {
lazy val allPropertyDefs: Map[SmartIri, PropertyInfoContentV2] = ontologies.values
.flatMap(_.properties.map { case (propertyIri, readPropertyInfo) =>
propertyIri -> readPropertyInfo.entityInfoContent
})
.toMap

def containsStandoffProperty(propertyIri: SmartIri): Boolean = standoffProperties.contains(propertyIri)

def getAllStandoffPropertyEntities: Map[SmartIri, ReadPropertyInfoV2] =
ontologies.values.flatMap(_.properties.view.filterKeys(standoffProperties)).toMap

def entityDefinedInOntology(propertyIri: SmartIri): Option[SmartIri] = entityDefinedInOntology.get(propertyIri)
def classDefinedInOntology(classIri: SmartIri): Option[SmartIri] = classDefinedInOntology.get(classIri)
def propertyDefinedInOntology(propertyIri: SmartIri): Option[SmartIri] = propertyDefinedInOntology.get(propertyIri)

def getSubPropertiesOf(propertyIri: SmartIri): Option[Set[SmartIri]] = superPropertyOfRelations.get(propertyIri)
def getSuperPropertiesOf(propertyIri: SmartIri): Option[Set[SmartIri]] = subPropertyOfRelations.get(propertyIri)

def getSubClassesOf(classIri: SmartIri): Option[Set[SmartIri]] = classToSubclassLookup.get(classIri)
def getSuperClassesOf(classIri: SmartIri): Option[Seq[SmartIri]] = classToSuperClassLookup.get(classIri)
}
object OntologyCacheData {
val Empty = OntologyCacheData(
Expand Down
Loading
Loading