Search code examples
jenaowlontologyprotege4

Determining class/individual relationships based on values computed at runtime


I have a simple ontology that consists of a Weather class and some subclasses (although I'm not sure if I should make them individuals instead) such as "Cold", "Rainy", "Sunny", etc. The thing is, I don't know which of these conditions hold until I get weather data at runtime. For instance, it is only "Cold" if the current temperature is less than, say, 70 degrees (I live in Texas ;p). Is there a way to structure the ontology so that this sort of reasoning can be done at runtime? (I am using Protege and Jena.)

Basically, I want to do different things based on which weather conditions are currently valid. For simplicity's sake, let's assume I just want to print out "It is currently cold, rainy ...", listing out the current weather conditions based on data such as temperature and amount of precipitation.


Solution

  • Writing the axioms in OWL

    It sounds like you're trying to add some rules of the form:

    If x has a temperature less than or equal to 32.0 F, then x has weather condition Cold.
    If x has a temperature above 32.0 F and less than or equal to 70.0 F, then x has weather condition Warm.
    If x has a temperature above 70.0 F, then x has weather condition Hot.

    You can do these in OWL without much problem with axioms like

    hasTemperature some double[> 32.0, <= 70.0] SubClassOf hasWeatherCondition value Warm

    These are called general class axioms because they have class expressions rather than atomic class names on the left hand side. The full set that I described above would be entered in Protégé as follows:

    three general class axioms in Protégé

    Seeing the results with Jena and Pellet

    To do the reasoning about numbers, you'll need a reasoner. I'm not sure whether or not Jena's rule reasoners can do this type of reasoning or not, but I know that Pellet can. The following code uses a Pellet-backed inference model.

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    import org.mindswap.pellet.jena.PelletReasonerFactory;
    
    import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
    import com.hp.hpl.jena.ontology.Individual;
    import com.hp.hpl.jena.ontology.OntModel;
    import com.hp.hpl.jena.ontology.OntProperty;
    import com.hp.hpl.jena.rdf.model.ModelFactory;
    import com.hp.hpl.jena.rdf.model.RDFNode;
    import com.hp.hpl.jena.rdf.model.StmtIterator;
    import com.hp.hpl.jena.vocabulary.OWL;
    
    public class WeatherExample {
        public static void main(String[] args) throws FileNotFoundException, IOException {
            final String NS = "http://stackoverflow.com/q/20489574/1281433/weather#";
    
            // Create an OntModel and read in the content from the ontology.  We're creating an model
            // that has Pellet doing inference behind the scenes. Pellet can handle the types of datatype
            // reasoning that we need for this particular problem.
            final OntModel model = ModelFactory.createOntologyModel( PelletReasonerFactory.THE_SPEC );
            try ( final FileInputStream in = new FileInputStream( "/home/taylorj/tmp/ontologies/weather/weather.owl" )) {
                model.read( in, null, "RDF/XML" );
            }
    
            // create an individual and list the things that the model knows about it.
            final Individual todaysWeather = model.createIndividual( NS+"weatherOfToday", OWL.Thing );
            System.out.println( "== Initial Knowledge ==" );
            for ( final StmtIterator it = model.listStatements( todaysWeather, null, (RDFNode) null ); it.hasNext(); ) {
                System.out.println( it.next() );
            }
    
            // Add the information that todaysWeather had temperature 28.0.
            final OntProperty hasTemperature = model.createOntProperty( NS+"hasTemperature" );
            todaysWeather.addLiteral( hasTemperature, model.createTypedLiteral( "28.0", XSDDatatype.XSDdouble ));
    
            // Show the new knowledge about todaysWeather.
            System.out.println( "== Later Knowledge ==" );
            for ( final StmtIterator it = model.listStatements( todaysWeather, null, (RDFNode) null ); it.hasNext(); ) {
                System.out.println( it.next() );
            }
        }
    }
    

    The output follows. Notice that in the second chunk todaysWeather hasWeatherCondition Cold.

    == Initial Knowledge ==
    [http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://www.w3.org/2002/07/owl#Thing]
    [http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday, http://www.w3.org/2002/07/owl#sameAs, http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday]
    
    == Later Knowledge ==
    [http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday, http://www.w3.org/1999/02/22-rdf-syntax-ns#type, http://www.w3.org/2002/07/owl#Thing]
    [http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday, http://www.w3.org/2002/07/owl#sameAs, http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday]
    [http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday, http://stackoverflow.com/q/20489574/1281433/weather#hasWeatherCondition, http://stackoverflow.com/q/20489574/1281433/weather#Cold]
    [http://stackoverflow.com/q/20489574/1281433/weather#weatherOfToday, http://stackoverflow.com/q/20489574/1281433/weather#hasTemperature, "28.0"^^http://www.w3.org/2001/XMLSchema#double]
    

    The ontology

    You can copy and paste the content of the ontology from which I made the screenshot from the following.

    <rdf:RDF
        xmlns="http://stackoverflow.com/q/20489574/1281433/weather#"
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:owl="http://www.w3.org/2002/07/owl#"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
        xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
      <owl:Ontology rdf:about="http://stackoverflow.com/q/20489574/1281433/weather"/>
      <owl:ObjectProperty rdf:about="http://stackoverflow.com/q/20489574/1281433/weather#hasWeatherCondition"/>
      <owl:DatatypeProperty rdf:about="http://stackoverflow.com/q/20489574/1281433/weather#hasTemperature">
        <rdfs:comment>temperature in degrees Fahrenheit </rdfs:comment>
        <rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#double"/>
      </owl:DatatypeProperty>
      <owl:Restriction>
        <rdfs:subClassOf>
          <owl:Restriction>
            <owl:onProperty rdf:resource="http://stackoverflow.com/q/20489574/1281433/weather#hasWeatherCondition"/>
            <owl:hasValue>
              <owl:NamedIndividual rdf:about="http://stackoverflow.com/q/20489574/1281433/weather#Hot"/>
            </owl:hasValue>
          </owl:Restriction>
        </rdfs:subClassOf>
        <owl:onProperty rdf:resource="http://stackoverflow.com/q/20489574/1281433/weather#hasTemperature"/>
        <owl:someValuesFrom>
          <rdfs:Datatype>
            <owl:onDatatype rdf:resource="http://www.w3.org/2001/XMLSchema#double"/>
            <owl:withRestrictions rdf:parseType="Collection">
              <rdf:Description>
                <xsd:minExclusive rdf:datatype="http://www.w3.org/2001/XMLSchema#double"
                >70.0</xsd:minExclusive>
              </rdf:Description>
            </owl:withRestrictions>
          </rdfs:Datatype>
        </owl:someValuesFrom>
      </owl:Restriction>
      <owl:Restriction>
        <rdfs:subClassOf>
          <owl:Restriction>
            <owl:onProperty rdf:resource="http://stackoverflow.com/q/20489574/1281433/weather#hasWeatherCondition"/>
            <owl:hasValue>
              <owl:NamedIndividual rdf:about="http://stackoverflow.com/q/20489574/1281433/weather#Warm"/>
            </owl:hasValue>
          </owl:Restriction>
        </rdfs:subClassOf>
        <owl:onProperty rdf:resource="http://stackoverflow.com/q/20489574/1281433/weather#hasTemperature"/>
        <owl:someValuesFrom>
          <rdfs:Datatype>
            <owl:onDatatype rdf:resource="http://www.w3.org/2001/XMLSchema#double"/>
            <owl:withRestrictions rdf:parseType="Collection">
              <rdf:Description>
                <xsd:maxInclusive rdf:datatype="http://www.w3.org/2001/XMLSchema#double"
                >70.0</xsd:maxInclusive>
              </rdf:Description>
              <rdf:Description>
                <xsd:minExclusive rdf:datatype="http://www.w3.org/2001/XMLSchema#double"
                >32.0</xsd:minExclusive>
              </rdf:Description>
            </owl:withRestrictions>
          </rdfs:Datatype>
        </owl:someValuesFrom>
      </owl:Restriction>
      <owl:Restriction>
        <rdfs:subClassOf>
          <owl:Restriction>
            <owl:onProperty rdf:resource="http://stackoverflow.com/q/20489574/1281433/weather#hasWeatherCondition"/>
            <owl:hasValue>
              <owl:NamedIndividual rdf:about="http://stackoverflow.com/q/20489574/1281433/weather#Cold"/>
            </owl:hasValue>
          </owl:Restriction>
        </rdfs:subClassOf>
        <owl:onProperty rdf:resource="http://stackoverflow.com/q/20489574/1281433/weather#hasTemperature"/>
        <owl:someValuesFrom>
          <rdfs:Datatype>
            <owl:onDatatype rdf:resource="http://www.w3.org/2001/XMLSchema#double"/>
            <owl:withRestrictions rdf:parseType="Collection">
              <rdf:Description>
                <xsd:maxInclusive rdf:datatype="http://www.w3.org/2001/XMLSchema#double"
                >32.0</xsd:maxInclusive>
              </rdf:Description>
            </owl:withRestrictions>
          </rdfs:Datatype>
        </owl:someValuesFrom>
      </owl:Restriction>
    </rdf:RDF>