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

Remove redundant relation graph #564

Merged
merged 2 commits into from
Jun 20, 2022
Merged
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
12 changes: 0 additions & 12 deletions src/main/resources/swaggerDocs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,6 @@ paths:
required: true
type: string
format: IRI
- name: direct
in: query
description: Returns only direct neighbors when set `true`. Filters out superclasses and transitively related terms.
required: false
type: boolean
default: false
responses:
200:
description: subject terms related to this object
Expand All @@ -451,12 +445,6 @@ paths:
required: true
type: string
format: IRI
- name: direct
in: query
description: Returns only direct neighbors when set `true`. Filters out superclasses and transitively related terms.
required: false
type: boolean
default: false
responses:
200:
description: object terms related to this subject
Expand Down
39 changes: 32 additions & 7 deletions src/main/scala/org/phenoscape/kb/AnatomicalEntity.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.MediaTypes
import org.apache.jena.query.{QueryFactory, QuerySolution}
import org.phenoscape.kb.KBVocab.{rdfsSubClassOf, _}
import org.phenoscape.kb.Similarity.rdfsSubClassOf
import org.phenoscape.owl.Vocab._
import org.phenoscape.scowl._
import org.phenoscape.sparql.SPARQLInterpolation._
import org.phenoscape.sparql.SPARQLInterpolationOWL._
import org.phenoscape.kb.util.SPARQLInterpolatorBlazegraph._
import org.phenoscape.owl.{NamedRestrictionGenerator, Vocab}
import org.semanticweb.owlapi.model.IRI
import spray.json.DefaultJsonProtocol._
Expand Down Expand Up @@ -70,15 +70,18 @@ object AnatomicalEntity {
}

// Output a boolean matrix as CSV
def matrixRendererFromMapOfMaps[A](dependencyMatrix: DependencyMatrix[A]): String = {
def matrixRendererFromMapOfMaps[A](dependencyMatrix: DependencyMatrix[A]) = {

val mapOfMaps = dependencyMatrix.map
val orderedKeys = dependencyMatrix.orderedKeys
val headers = s",${orderedKeys.mkString(",")}" //print column headers

val matrix = for (x <- orderedKeys) yield {
val row = s"$x"
val values = for (y <- orderedKeys) yield (if (mapOfMaps(x)(y)) 1 else 0)
val values = for (y <- orderedKeys) yield mapOfMaps(x)(y) match {
case true => 1
case false => 0
}
s"$row,${values.mkString(",")}"
}
s"$headers\n${matrix.mkString("\n")}\n"
Expand Down Expand Up @@ -118,16 +121,38 @@ object AnatomicalEntity {
"""

private def queryImpliesPresenceOfMulti(terms: Iterable[IRI]): QueryText = {
import scalaz._
import Scalaz._
val valuesList = terms.map(t => sparql" $t ").fold(sparql"")(_ + _)
sparql"""
PREFIX hint: <http://www.bigdata.com/queryHints#>
SELECT DISTINCT ?x ?y
FROM $KBClosureGraph
FROM $KBMainGraph
FROM $KBRedundantRelationGraph
WITH {
SELECT ?term ?presence
WHERE {
VALUES ?term { $valuesList }
?presence <http://purl.org/phenoscape/vocab.owl#implies_presence_of_some> ?term .
}
} AS %SUB1
WHERE {
VALUES ?x { $valuesList }
VALUES ?y { $valuesList }
?x $rdfsSubClassOf | $IMPLIES_PRESENCE_OF ?y .
hint:Query hint:filterExists "VectoredSubPlan" .
{
SELECT (?term AS ?x) (?presence AS ?x_presence)
WHERE {
INCLUDE %SUB1
}
}
{
SELECT (?term AS ?y) (?presence AS ?y_presence)
WHERE {
INCLUDE %SUB1
}
}
FILTER EXISTS {
?x_presence <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?y_presence
}
FILTER(?x != ?y)
}
"""
Expand Down
142 changes: 85 additions & 57 deletions src/main/scala/org/phenoscape/kb/EQForGene.scala
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
package org.phenoscape.kb

import akka.util.Timeout
import com.google.common.collect.HashMultiset
import org.apache.jena.query.Query
import org.phenoscape.kb.KBVocab._
import org.phenoscape.owl.Vocab._
import org.phenoscape.sparql.SPARQLInterpolation._
import org.phenoscape.owl.{NamedRestrictionGenerator, Vocab}
import org.phenoscape.owlet.SPARQLComposer._
import org.phenoscape.scowl._
import org.semanticweb.owlapi.apibinding.OWLManager
import org.semanticweb.owlapi.model.IRI
import org.phenoscape.sparql.SPARQLInterpolationOWL._
import spray.json.DefaultJsonProtocol._
import spray.json._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.jdk.CollectionConverters._
import scala.language.postfixOps

object EQForGene {

private val factory = OWLManager.getOWLDataFactory
private val rdfType = ObjectProperty(Vocab.rdfType)
private val rdfsSubClassOf = ObjectProperty(Vocab.rdfsSubClassOf)
private val rdfsIsDefinedBy = factory.getRDFSIsDefinedBy
private val UBERON = IRI.create("http://purl.obolibrary.org/obo/uberon.owl")
private val PATO = IRI.create("http://purl.obolibrary.org/obo/pato.owl")
private val has_part_some = NamedRestrictionGenerator.getClassRelationIRI(Vocab.has_part.getIRI)

private val has_part_inhering_in_some =
NamedRestrictionGenerator.getClassRelationIRI(Vocab.has_part_inhering_in.getIRI)

implicit private val timeout: Timeout = Timeout(10 minutes)

def query(geneID: IRI): Future[JsArray] = {
Expand All @@ -41,72 +55,86 @@ object EQForGene {
}

def annotationsForGene(geneID: IRI): Future[Iterable[String]] =
App.executeSPARQLQuery(annotationsQuery(geneID), _.getResource("association").getURI)
App.executeSPARQLQuery(annotationsQuery(geneID), _.getResource("annotation").getURI)

def annotationsQuery(geneIRI: IRI): Query =
sparql"""
SELECT DISTINCT ?association
FROM $KBMainGraph
WHERE {
?association $rdfType $association .
?association $associationHasPredicate $has_phenotype .
?association $associationHasSubject $geneIRI .
}
""".toQuery

def qualitiesForAnnotation(annotationID: String): Future[Iterable[String]] =
App.executeSPARQLQuery(annotationSuperQualityQuery(annotationID), _.getResource("quality").getURI)
select_distinct('association) from "http://kb.phenoscape.org/" where bgp(
t('association, rdfType, association),
t('association, associationHasPredicate, has_phenotype),
t('association, associationHasSubject, geneIRI))

def qualitiesForAnnotation(annotationID: String): Future[Iterable[String]] = {
val allSuperQualities =
App.executeSPARQLQuery(annotationSuperQualityQuery(annotationID), _.getResource("quality").getURI)
for {
superQualities <- allSuperQualities
superSuperQualities <- superClassesForSuperQualities(superQualities)
} yield {
val superclasses = HashMultiset.create[String]
superSuperQualities.foreach(superclasses.add)
val nearestQualities = superclasses.entrySet.asScala.filter(_.getCount == 1).map(_.getElement)
nearestQualities.toVector
}
}

def superClassesForSuperQualities(superQualities: Iterable[String]): Future[Iterable[String]] = {
val superclasses = Future.sequence(superQualities.map { superClass =>
App.executeSPARQLQuery(qualitySuperQualityQuery(superClass), _.getResource("quality").getURI)
})
for { result <- superclasses } yield result.flatten
}

def annotationSuperQualityQuery(annotationID: String): Query = {
val annotationIRI = IRI.create(annotationID)
select_distinct('quality) from "http://kb.phenoscape.org/" from "http://kb.phenoscape.org/closure" where bgp(
t(annotationIRI, rdfType / rdfsSubClassOf, 'has_quality),
t('has_quality, has_part_some, 'quality),
t('quality, rdfsIsDefinedBy, PATO))
}

val query =
sparql"""
SELECT DISTINCT ?quality
FROM $KBMainGraph
FROM $KBRedundantRelationGraph
WHERE {
$annotationIRI $associationHasObject ?phenotype .
?phenotype $has_part ?quality .
?quality $rdfsIsDefinedBy $PATO .

FILTER NOT EXISTS {
?phenotype $has_part ?other_quality .
?other_quality $rdfsIsDefinedBy $PATO .
?other_quality ${KBVocab.rdfsSubClassOf} ?quality .
FILTER (?other_quality != ?quality)
}
}
"""
query.toQuery
def qualitySuperQualityQuery(termID: String): Query = {
val termIRI = IRI.create(termID)
select_distinct('quality) from "http://kb.phenoscape.org/" from "http://kb.phenoscape.org/closure" where bgp(
t(termIRI, rdfsSubClassOf, 'has_quality),
t('has_quality, has_part_some, 'quality),
t('quality, rdfsIsDefinedBy, PATO))
}

def entitiesForAnnotation(annotationID: String): Future[Iterable[String]] =
App.executeSPARQLQuery(annotationEntityTypesQuery(annotationID), _.getResource("bearer").getURI)
def entitiesForAnnotation(annotationID: String): Future[Iterable[String]] = {
val entityTypes =
App.executeSPARQLQuery(annotationEntityTypesQuery(annotationID), _.getResource("description").getURI)
for {
entityTypesResult <- entityTypes
entitySuperClasses <- superClassesForEntityTypes(entityTypesResult)
} yield {
val superclasses = HashMultiset.create[String]
entitySuperClasses.foreach(superclasses.add)
val nearestEntities = superclasses.entrySet.asScala.filter(_.getCount == 1).map(_.getElement)
nearestEntities.toVector
}
}

def superClassesForEntityTypes(entityTypes: Iterable[String]): Future[Iterable[String]] = {
val superclasses = Future.sequence(entityTypes.map { entityType =>
App.executeSPARQLQuery(entitySuperClassesQuery(entityType), _.getResource("bearer").getURI)
})
for { result <- superclasses } yield result.flatten
}

def annotationEntityTypesQuery(annotationID: String): Query = {
val annotationIRI = IRI.create(annotationID)
val query =
sparql"""
SELECT DISTINCT ?bearer
FROM $KBMainGraph
FROM $KBRedundantRelationGraph
WHERE {
$annotationIRI $associationHasObject ?phenotype .

?phenotype $has_part_inhering_in ?bearer .
?bearer $rdfsIsDefinedBy $Uberon .

FILTER NOT EXISTS {
?phenotype $has_part_inhering_in ?other_bearer .
?other_bearer $rdfsIsDefinedBy $Uberon .
?other_bearer ${KBVocab.rdfsSubClassOf} ?bearer .
FILTER (?other_bearer != ?bearer)
}
}
"""
query.toQuery
select_distinct('description) from "http://kb.phenoscape.org/" from "http://kb.phenoscape.org/closure" where bgp(
t(annotationIRI, rdfType / rdfsSubClassOf, 'description),
t('description, has_part_inhering_in_some, 'bearer),
t('bearer, rdfsIsDefinedBy, UBERON))
}

def entitySuperClassesQuery(termID: String): Query = {
val termIRI = IRI.create(termID)
select_distinct('bearer) from "http://kb.phenoscape.org/" from "http://kb.phenoscape.org/closure" where bgp(
t(termIRI, rdfsSubClassOf, 'description),
t('description, has_part_inhering_in_some, 'bearer),
t('bearer, rdfsIsDefinedBy, UBERON))
}

}
96 changes: 22 additions & 74 deletions src/main/scala/org/phenoscape/kb/Graph.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,90 +11,38 @@ import org.phenoscape.kb.Main.system.dispatcher
import org.phenoscape.kb.Similarity.PhenotypeCorpus
import org.phenoscape.sparql.SPARQLInterpolation._
import org.phenoscape.sparql.SPARQLInterpolationOWL._
import org.phenoscape.owl.NamedRestrictionGenerator
import org.phenoscape.owlet.SPARQLComposer._

import scala.concurrent.Future
import scala.language.postfixOps

object Graph {

def propertyNeighborsForObject(term: IRI, property: IRI, direct: Boolean): Future[Seq[MinimalTerm]] =
App.executeSPARQLQuery(buildPropertyNeighborsQueryObject(term, property, direct), MinimalTerm.fromQuerySolution)
def propertyNeighborsForObject(term: IRI, property: IRI): Future[Seq[MinimalTerm]] =
App.executeSPARQLQuery(buildPropertyNeighborsQueryObject(term, property), MinimalTerm.fromQuerySolution)

def propertyNeighborsForSubject(term: IRI, property: IRI, direct: Boolean): Future[Seq[MinimalTerm]] =
App.executeSPARQLQuery(buildPropertyNeighborsQuerySubject(term, property, direct), MinimalTerm.fromQuerySolution)
def propertyNeighborsForSubject(term: IRI, property: IRI): Future[Seq[MinimalTerm]] =
App.executeSPARQLQuery(buildPropertyNeighborsQuerySubject(term, property), MinimalTerm.fromQuerySolution)

private def buildPropertyNeighborsQueryObject(focalTerm: IRI, property: IRI, direct: Boolean): Query = {

val filterIndirectNeighbors =
sparql"""
FILTER NOT EXISTS {
?other_term $property $focalTerm .
?other_term $rdfsSubClassOf ?term .
FILTER(?other_term != ?term)
}

FILTER NOT EXISTS {
$property $rdfType $transitiveProperty .
?other_term $property $focalTerm .
?other_term $property ?term .
FILTER(?other_term != ?term)
}
"""

val filters = if (direct) filterIndirectNeighbors else sparql""

val query =
sparql"""
SELECT DISTINCT ?term ?term_label
FROM $KBMainGraph
FROM $KBClosureGraph
FROM $KBRedundantRelationGraph
WHERE {
?term $property $focalTerm .
?term $rdfsLabel ?term_label .

$filters
}
"""

query.toQuery
private def buildPropertyNeighborsQueryObject(focalTerm: IRI, property: IRI): Query = {
val classRelation = NamedRestrictionGenerator.getClassRelationIRI(property)
select_distinct('term, 'term_label) from "http://kb.phenoscape.org/" where bgp(
t('existential_node, classRelation, focalTerm),
t('existential_subclass, rdfsSubClassOf, 'existential_node),
t('existential_subclass, classRelation, 'term),
t('term, rdfsLabel, 'term_label)
)
}

private def buildPropertyNeighborsQuerySubject(focalTerm: IRI, property: IRI, direct: Boolean): Query = {

val filterIndirectNeighbors =
sparql"""
FILTER NOT EXISTS {
$focalTerm $property ?other_term .
?other_term $rdfsSubClassOf ?term .
FILTER(?other_term != ?term)
}

FILTER NOT EXISTS {
$property $rdfType $transitiveProperty .
$focalTerm $property ?other_term .
?other_term $property ?term .
FILTER(?other_term != ?term)
}
"""

val filters = if (direct) filterIndirectNeighbors else sparql""

val query =
sparql"""
SELECT DISTINCT ?term ?term_label
FROM $KBMainGraph
FROM $KBClosureGraph
FROM $KBRedundantRelationGraph
WHERE {
$focalTerm $property ?term .
?term $rdfsLabel ?term_label .

$filters
}
"""

query.toQuery
private def buildPropertyNeighborsQuerySubject(focalTerm: IRI, property: IRI): Query = {
val classRelation = NamedRestrictionGenerator.getClassRelationIRI(property)
select_distinct('term, 'term_label) from "http://kb.phenoscape.org/" where bgp(
t('existential_node, classRelation, focalTerm),
t('existential_node, rdfsSubClassOf, 'existential_superclass),
t('existential_superclass, classRelation, 'term),
t('term, rdfsLabel, 'term_label)
)
}

def getTermSubsumerPairs(terms: Set[IRI], corpusOpt: Option[PhenotypeCorpus]): Future[Seq[(IRI, IRI)]] = {
Expand Down
Loading