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

Add support for owl:unionOf when resolving rdfs:range on an owl:ObjectProperty #3

Open
Astn opened this issue Feb 23, 2017 · 11 comments

Comments

@Astn
Copy link

Astn commented Feb 23, 2017

When using ontologies such as the OWL compliant version of schema.org created by topbraid (http://topbraid.org/schema) @ http://topbraid.org/schema/schema.ttl

It is common to encounter a union of resources as the object of rdfs:range. Example:

###  http://schema.org/acquiredFrom
<http://schema.org/acquiredFrom> rdf:type owl:ObjectProperty ;
                                 rdfs:domain <http://schema.org/OwnershipInfo> ;
                                 rdfs:range [ rdf:type owl:Class ;
                                              owl:unionOf ( <http://schema.org/Organization>
                                                            <http://schema.org/Person>
                                                          )
                                            ] ;
                                 rdfs:comment "The organization or person from which the product was acquired."^^xsd:string ;
                                 rdfs:label "acquired from"^^xsd:string .

I propose that we handle this case by adding all of the resources found in the owl:unionOf to a GraphQLUnionType and return that from the call to getGraphqlPolymorphicObjectType.

I have been working on a solution for this particular issue, and should be able to submit a pull request for review shortly.

@dherault
Copy link
Member

re @Astn, there is a major difference between a GraphQLUnionType (badly named, it returns only one type, the resource must belong to either of the classes), and a owl:unionOf class (which is many classes at the same time, the resource must belong to all the classes).

Also, what about an interface ?

@dherault
Copy link
Member

Mmm my bad it seems I'm wrong about owl:unionOf

@dherault
Copy link
Member

Ok owl:unionOf is a logical disjunction so it could be either or both classes

@dherault
Copy link
Member

dherault commented Feb 23, 2017

A GraphQLUnion type would handle the "either" case, but not if it is "both". A GraphQLInterface type would handle fragments on "both", but we'd still have to resolve only one type (because GraphQL requires a single type) for a particular resource.

Let's say a field returns an owl:unionOf(Dog, Cat) and a user queries a resource that is both a Dog and a Cat (whatever) using a fragment on Dog and another one on Cat, for that resource we would have to resolve only one type (Dog or Cat) not both, and only one fragment would be collected.

This is a typical case where GraphQL and Semantic data do not mix well.

@dherault
Copy link
Member

I've been thinking about a fix that would solve many GraphQL vs Semantic conflicts like this one : it would be to add some magic into the resolveType function, by introspecting the AST and knowing what the user wants. Does it need a Dog ? Then return 'Dog' as the type. A Cat ? 'Cat'. A Dog and a Cat ? Return a special DogCat GraphQL type.

@Astn
Copy link
Author

Astn commented Feb 23, 2017

From the brief testing I was doing earlier, this case is already handled O.K. I'm sure it could be better. Likely is the case that anything can be an owlThing. So is there a way for us to create a fragment on an objectProperty that has a rdfs:range of owlThing? My currently implementation does not allow such a thing.

But so far, I am able to formulate queries such as:

query {
  foo(bar:"bar"){
    __typename
    ... on I_sdo_Action {
      startTime
      agent {
        ... on sdo_Person {
          url
        }
      }
    }
    ... on sdo_FollowAction {
      followee {
        ... on I_sdo_Thing {
          url
        }
      }
    }
    ... on sdo_MarryAction {
      object {
        ... on I_sdo_Thing {
          url
        }
      }
    }
  }
}

@Astn
Copy link
Author

Astn commented Feb 23, 2017

So it appears that if the components of a Union implement a common interface, then you are able to pull the common fields from it right now. Not sure of what to do when some Thing is both a Cat and a Dog.

@dherault
Copy link
Member

Yes the "both" case is still missing in the GraphQLUnion type solution. But the "both" case is the essence of owl:unionOf. Otherwise simply listing the classes instead of using an owl:unionOf would do.

@Astn
Copy link
Author

Astn commented Feb 23, 2017

Do you know any way that graphql supports some kind of a Both case?
All I can think of at the moment, which I think you suggested earlier would be to generate another type that represented the logical disjunction. But that then still has the issue that derived types or more specific types are also allowed.

So in the case of

###  http://schema.org/acquiredFrom
<http://schema.org/acquiredFrom> rdf:type owl:ObjectProperty ;
                                 rdfs:domain <http://schema.org/OwnershipInfo> ;
                                 rdfs:range [ rdf:type owl:Class ;
                                              owl:unionOf ( <http://schema.org/Organization>
                                                            <http://schema.org/Person>
                                                          )
                                            ] ;
                                 rdfs:comment "The organization or person from which the product was acquired."^^xsd:string ;
                                 rdfs:label "acquired from"^^xsd:string .

The resource returned as the object of http://schema.org/aquiredFrom could be a schema:CafeOrCoffeeShop because

schema:CafeOrCoffeeShop subClassOf schema:LocalBusiness subClassOf schema:Organization

schema:CafeOrCoffeeShop
  rdf:type owl:Class ;
  rdfs:comment "A cafe or coffee shop." ;
  rdfs:label "Cafe or coffee shop" ;
  rdfs:subClassOf schema:FoodEstablishment ;

schema:FoodEstablishment
  rdf:type owl:Class ;
  rdfs:comment "A food-related business." ;
  rdfs:label "Food establishment" ;
  rdfs:subClassOf schema:LocalBusiness ;

schema:LocalBusiness
  rdf:type owl:Class ;
  rdfs:comment "A particular physical business or branch of an organization. Examples of LocalBusiness include a restaurant, a particular branch of a restaurant chain, a branch of a bank, a medical practice, a club, a bowling alley, etc." ;
  rdfs:label "Local business" ;
  rdfs:subClassOf schema:Organization ;
  rdfs:subClassOf schema:Place ;

So that makes me conclude that in the simple case of

schema:error
  rdf:type owl:ObjectProperty ;
  rdfs:comment "For failed actions, more information on the cause of the failure." ;
  rdfs:domain schema:Action ;
  rdfs:label "error" ;
  rdfs:range owl:Thing ;

you should be able to formulate the following query because schema:APIReference is an owl:Thing

query {
   schemaActions {
      schemaerror {
         ... on schemaAPIReference {
            id
         }
      }
   }
}

So where do we go from here?

@dherault
Copy link
Member

Yes, you're right, that's why I wanted the "type" of fields to be GraphQLInterfaceType instead of GraphQLObjectType. This kind of fragments would then be available, without breaking changes. I never made the swich, it's on the TODO list thought.

@Astn
Copy link
Author

Astn commented Feb 23, 2017

So I think we have two separate issues here.

  1. This one Add support for owl:unionOf when resolving rdfs:range on an owl:ObjectProperty #3 = Handle unions in rdfs:range position.
  2. Need to define = How to handle subtypes or implementers of some interface.

I would still like to try to solve this #3 without tackling the Interface / subtype issue yet.
Currently there is no support for unions, so IMO some support is a step forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants