phenoscape / owlery

Owlery is a set of REST web services which allow querying of an OWL reasoner containing a configured set of ontologies.
MIT License
16 stars 11 forks source link

DL Queries not getting expected answers: parsing issues #142

Closed rpgoldman closed 3 years ago

rpgoldman commented 3 years ago

Using the make server command to set up Owlery as per this makefile I am getting query failures I did not expect.

Here's the curl query I use:

curl -G --location --request GET 'http://localhost:8080/kbs/strateos-catalog/instances' --data "kb=strateos-catalog" --data-urlencode "object=cont:Plate and (cont:wellCount value 96)"   --data 'direct=false' --data-urlencode 'prefixes={ "owl" :  "http://www.w3.org/2002/07/owl#", "cont": "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#"}'

The important bit is object=cont:Plate and (cont:wellCount value 96) and the error I get back is:

requirement failed: Encountered 96 at line 1 column 38. Expected one of:
    Individual name

It looks like Owlery believes that my cont:wellCount property is an object property, even though it is defined as a data property, that is positive integer valued.

When I do what I think is the corresponding query in Protege, cont:Plate and cont:wellCount value 96 I get 22 results.

P.S. You might consider activating the "Discussions" GitHub action in addition to issues, if it bothers you that I am abusing Issues to ask questions.

Note on replication

Note that this is replicable as follows:

  1. git clone https://github.com/rpgoldman/container-ontology
  2. git checkout owlery-server
  3. cd owl
  4. make server
  5. Execute queries

Possible explanation: Bad syntax

It's quite possible that I'm doing something wrong in authoring my Manchester Syntax query expressions. But reading the OWL 2 Web Ontology Language Manchester Syntax (Second Edition) it didn't look like I needed any special syntax for an integer literal.

Possible explanation: Some problem with properties

I wondered whether Owlery somehow isn't getting my property definitions, and so it might be assuming that cont:wellCount is an object property instead of a datatype property? I tried asking Owlery to find all of my DatatypeProperty's, ObjectProperty's and AnnotationProperty's but was not successful. I don't know if such a query is possible in Owlery.

I tried using the sparql endpoint, but could not get that to work at all: all of my queries returned an empty set of results.

Possible explanation: Import problem

One possible explanation is that there has been an import problem. When I query Owlery for my ontology (strateos-catalog) I see this:

{
    "label": "strateos-catalog",
    "logicalAxiomsCount": 1318,
    "@context": "https://owlery.phenoscape.org/json/context.jsonld",
    "isConsistent": true,
    "imports": [],
    "@id": "_:anonymousOnt0"
}

If I look at Protege for the same ontology, I see this:

image

Another possible clue

Owlery is reporting that it has 1318 logical axioms. Looking at the Protege display for strateos-catalog, I see 1303. The included container-ontology, Protege displays as having 415, and the om-subset ontology (also imported) has 15. If the definition of logical axioms is the same between Owlery and Protege, then Owlery believes there are 1318 logical axioms and Protege believes there are 1733. I don't know if the definitions are different, or Owlery is not seeing some of my axioms. Actually, if the two definitions are the same, this would be consistent with Owlery reading only my strateos-catalog.ttl and the om-subset.ttl, and missing the container-ontology.ttl entirely.

I'm afraid I'm not sure how to debug this, if it is an import issue, since I am not getting any log data (see #131). Is there anything I can do to configure log4j so that it writes to the console or a file? Sorry to be so clueless, but log4j is a really big thing and I don't know where to start, especially since their own docs say that there is no way for a user to tell where the log4j config files should go.

That said, it looks like at least one of the imported ontologies is, in fact, imported, since when I ask Owlery for all the instances of cont:Plate (lab multi-well plates), I get a set that contains not just the entities from my main ontology (strateos-catalog.ttl), but also the foundational ontology it imports (container-ontology.ttl).

So this may be a red herring, since Owlery is loading all the files in the directory, it may be that it does not see container-ontology.ttl as an import -- it's loaded manually.

OTOH, OWLAPI does not feel that it's an error when it can't process a triple and throws it on the floor. These are logged, but only as WARN or INFO, I believe and (broken record) I can't see the logs.

balhoff commented 3 years ago

I'm working on this. It boils down to me trying to implement a standalone Manchester syntax expression parser independent of any particular ontology (not a parser exactly, that part is provided by OWL API; rather the entity checker component). It turns out that isn't possible with that syntax, so the current implementation always defaults to object properties over data properties. The folks who have been using this software never had a need for data properties, so this never got fixed. But I'm now reworking the parser to consult the loaded ontology, which should make everything work correctly.

If we instead used OWL functional syntax (for example), we could parse standalone fragments without worrying about which properties were or were not declared.

balhoff commented 3 years ago

Thanks for bearing with these little fixes. The current users all come from the bio-ontology world, where we have tended to be using ontologies built with certain assumptions.

rpgoldman commented 3 years ago

Thanks for bearing with these little fixes. The current users all come from the bio-ontology world, where we have tended to be using ontologies built with certain assumptions.

A follow-up question, then: I did what I thought was the obvious work-around, and added the class Plate96Well, defined as follows:

cont:Plate96Well rdf:type owl:Class ;
  owl:equivalentClass [ owl:intersectionOf ( cont:Plate
                                             [ rdf:type owl:Restriction ;
                                               owl:onProperty cont:wellCount ;
                                               owl:hasValue 96
                                             ]
                                           ) ;
                                       rdf:type owl:Class
                      ] ;
                 rdfs:subClassOf cont:Plate .

I expected that that would avoid the problem I was encountering with querying, but to my surprise Owlery returned no instances of this class. This is with the "structural" reasoner. When I do the DL Query Plate96Well in Protege, it finds 22 instances (correctly), with Pellet or Fact++.

Another oddity: when I tried changing Owlery's reasoner to "jfact" it reported that the ontology was inconsistent and the server would not start.

rpgoldman commented 3 years ago

@balhoff I think there may be a second issue here that has to do with me not understanding how Owlery treats its ontologies. In my repo, I have container-ontology.ttl, om-subset.ttl, and strateos-catalog-individuals.ttl

Using the swagger UI (I can't thank you enough for that!) I see that they are all getting loaded:

{
  "label": "strateos-catalog",
  "logicalAxiomsCount": 1333,
  "@context": "https://owlery.phenoscape.org/json/context.jsonld",
  "isConsistent": true,
  "imports": [
    {
      "@id": "http://sbols.org/v3"
    },
    {
      "@id": "https://raw.githubusercontent.com/rpgoldman/container-ontology/main/owl/om-subset.ttl",
      "version": "https://raw.githubusercontent.com/rpgoldman/container-ontology/main/owl/om-subset.ttl"
    },
    {
      "@id": "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl",
      "version": "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl"
    },
    {
      "@id": "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/strateos-catalog-individuals.ttl"
    }
  ],
  "@id": "_:anonymousOnt0"
}

I have assumed that these all go into a single workspace -- that the strateos-catalog KB involves all of these.

The container-ontology has all of the facts, and a single example entity that is classified as I expect (from the types API):

{
  "@id": "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#EnduraPlate_96Well_Multicolor",
  "type": [
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#Container",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#LabEquipment",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#Plate",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#ContainerRoot",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#SLAS_4-2004_96_Well_Plate",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#SLAS-4-2004",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#ThermoFisher_EnduraPlate_96Well",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#OpaquePlate",
    "http://sbols.org/v3#Identified"
  ],
  "@context": "https://owlery.phenoscape.org/json/context.jsonld"
}

But when I look to see if the individuals in the strateos-containers.ttl file are classified, I only see the classification I made explicitly, and the path to owl:Thing:

{
  "@id": "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/strateos-catalog-individuals.ttl#Corning96-flat",
  "type": [
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#Container",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#LabEquipment",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#Plate",
    "https://raw.githubusercontent.com/rpgoldman/container-ontology/owlery-server/owl/container-ontology.ttl#ContainerRoot",
    "http://sbols.org/v3#Identified"
  ],
  "@context": "https://owlery.phenoscape.org/json/context.jsonld"
}

So am I expecting classification that Owlery does not provide? Do I need to merge all these ontologies into one file instead of importing? Or am I otherwise doing something wrong?

Also, is there any way of telling whether Owlery is reading these ontologies from my filesystem or chasing the URLs? I suppose that is another question that would be answered by looking at the owlapi logs.

Thanks!

P.S. If this is a different issue and I should be opening a separate issue, LMK and I will fix it.

balhoff commented 3 years ago

Please check and see if the parsing issues are fixed by the latest commit. I'm not sure yet about your reasoning questions. I will need to take a look at your ontologies. In case you are using the structural reasoner, avoid that one - it implements the reasoner API but doesn't do any inference (only returns asserted information). If JFact thinks your ontology is inconsistent, it may be. I would try HermiT as well.

rpgoldman commented 3 years ago

@balhoff I will do as you advise. I don't think that JFact is right here, because multiple reasoners in Protege report that the ontology is consistent. But I will experiment and open another issue if necessary. And I should try to figure out if the Owlery is loading the ontology files I think it's loading!

rpgoldman commented 3 years ago

Please check and see if the parsing issues are fixed by the latest commit.

I'm afraid I'm still not getting the parsing results I expect. When I submit the query cont:Plate and cont:wellCount value 96 I get this error message:

requirement failed: Encountered 96 at line 1 column 37. Expected one of:
    Individual name

Here's the corresponding definition:

cont:wellCount rdf:type owl:DatatypeProperty, owl:FunctionalProperty ;
               rdfs:subPropertyOf cont:containerDataProperty ;
               rdfs:domain cont:Plate ;
               rdfs:range xsd:positiveInteger .

And this class produces the expected instances when queried (cont:Plate96Well):

cont:Plate96Well rdf:type owl:Class ;
                 owl:equivalentClass [ owl:intersectionOf ( cont:Plate
                                                            [ rdf:type owl:Restriction ;
                                                              owl:onProperty cont:wellCount ;
                                                              owl:hasValue 96
                                                            ]
                                                          ) ;
                                       rdf:type owl:Class
                                     ] ;
                 rdfs:subClassOf cont:Plate .

This is a different error than before, so I'm pretty sure I am getting the new parser.

P.S. Hermit says my ontology is consistent. Haven't tried JFact again.

balhoff commented 3 years ago

@rpgoldman is 1333 the same number of logical axioms that Protege reports? I feel like there must be a loading issue, or some issue with property declarations. I tried some data value expressions in the swagger UI and they seemed to work.

rpgoldman commented 3 years ago

I think there must be some loading issue or something. I have found under some circumstances that OWLAPI will ignore my catalog file and pull the URL instead, and it isn't guaranteed that the ontologies at the URL references are up-to-date wrt my local copies.

I just reloaded, and according to Protege, there are 1313 logical axioms:

image

I don't know what it means that there's an Axiom line with 2036. Does that mean there are 2026-1313 = 713 illogical axioms?

The Swagger API to Owlery reports the following:

{
  "label": "strateos-catalog",
  "logicalAxiomsCount": 1552,
  "@context": "https://owlery.phenoscape.org/json/context.jsonld",
  "isConsistent": true,
  "imports": [],
  "@id": "_:anonymousOnt0"
}
balhoff commented 3 years ago

@rpgoldman in case you didn't see—I added some docs on using a catalog file to the README.

rpgoldman commented 3 years ago

@balhoff I did see that, thanks, and I have tried replacing the location with the main file, and adding the IRIs for the main file, and all its imported ontologies to the catalog:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<catalog prefer="public" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
    <uri name="https://raw.githubusercontent.com/rpgoldman/container-ontology/main/owl/om-subset.ttl" uri="/srv/owl/om-subset.ttl"/>
    <uri name="https://raw.githubusercontent.com/rpgoldman/container-ontology/main/owl/container-ontology.ttl" uri="/srv/owl/container-ontology.ttl"/>
    <uri name="https://raw.githubusercontent.com/rpgoldman/container-ontology/main/owl/strateos-catalog-individuals.ttl" uri="/srv/owl/strateos-catalog-individuala.ttl"/>
    <group id="Folder Repository, directory=, recursive=true, Auto-Update=true, version=2" prefer="public" xml:base=""/>
</catalog>

And... I can see I made a typo in the catalog entry above for strateos-catalog-individuals.ttl . What's pretty worrying is that I got no error message at all for this, and Owlery seems to have gone ahead and loaded.... what? Presumably the copy at raw.githubusercontent.com?

I feel like a broken record, and I'm sorry about that, but some logging here would be a huge help in debugging.

rpgoldman commented 3 years ago

Even after that, I am still getting

requirement failed: Encountered 96 at line 1 column 37. Expected one of:
    Individual name

It occurs to me to wonder: is there any way to make a query to Owlery to see what it believes about a Property? Or is that only available for individuals and classes?

balhoff commented 3 years ago

It occurs to me to wonder: is there any way to make a query to Owlery to see what it believes about a Property? Or is that only available for individuals and classes?

There aren't any endpoints for this now, but I think it could be added.