2

I have an RDF Graph with only one relationship(RDFS.subClassOf or is-a) between all the classes.

The 'size' of each class is equal to the total number of its subclasses. The 'size' of each RDFS.subClassOf property is 0.5 if it is connecting from a class with fewer total number of subclasses and 1 if it is connecting from class with large total number of subclasses to class with less total number of subclasses.

I want to perform an arithmetic sum of all the sizes of each semantic component (class / relationship) in the path using the Jena RDF/Ontology API.

For example, given the camera ontology (http://protege.cim3.net/file/pub/ontologies/camera/camera.owl) one of the paths is: Thing - PurchaseableItem - Lens : Its sum would be (5 + 0.5 + 3 + 0.5 + 0) = 9.

DNA
  • 40,109
  • 12
  • 96
  • 136
  • Not answers, but maybe useful: [computing the position of an element in an RDF list](http://stackoverflow.com/questions/17523804/is-it-possible-to-get-the-position-of-an-element-in-an-rdf-collection-in-sparql/17530689#17530689); [one on computing mathematical formulae based on RDF collections](http://stackoverflow.com/questions/17312774/functions-to-manipulate-rdf-collections-in-sparql/17319546#17319546); [computing similarity metrics between pairs resources](http://stackoverflow.com/questions/17763587/do-i-use-netbeans-or-sparql-in-protege/17765809#17765809). – Joshua Taylor Jul 25 '13 at 23:24
  • Joshua thank you for the links are very useful. – user2502144 Jul 26 '13 at 08:14

1 Answers1

1

Assuming that this builds on the answer to your previous question about constructing the type of paths that you mention in the question, can you just use:

public static int classSize( final Resource klass ) {
    return klass.getModel().listSubjectsWithProperty( RDFS.subClassOf, klass ).toList().size();
}

public static double pathSize( final List<Resource> path ) {
    int prevSize = classSize( path.get( 0 )); 
    double pathSum = prevSize;
    for ( int i = 1; i < path.size(); i++ ) {
        int currSize = classSize( path.get( i ));
        double linkWeight = currSize < prevSize ? 0.5 : 1.0;
        pathSum += linkWeight + currSize;
        prevSize = currSize;
    }
    return pathSum;
}

Then we get the following sums for the paths. The complete code follows this output. Notice the owl:Thing has a size of four here, not five, as you gave in the question. if the idea was to count the number of times that a class appeared as the object in a triple of rdfs:subClassOf, there are only four triples of the form something rdfs:subClassOf owl:Thing in the OWL file that you linked to, so it seems like its size should be four, not five. Given that consideration, note that the “Thing–PurchaseableItem–Lens” path has weight eight, as expected (one less than nine, as you mentioned in the question).

4.0 [http://www.w3.org/2002/07/owl#Thing]
7.5 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#PurchaseableItem]
4.5 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#Window]
4.5 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#Range]
4.5 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#Money]
10.0 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#PurchaseableItem, http://www.xfront.com/owl/ontologies/camera/#Camera]
8.0 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#PurchaseableItem, http://www.xfront.com/owl/ontologies/camera/#Lens]
8.0 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#PurchaseableItem, http://www.xfront.com/owl/ontologies/camera/#Body]
10.5 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#PurchaseableItem, http://www.xfront.com/owl/ontologies/camera/#Camera, http://www.xfront.com/owl/ontologies/camera/#Digital]
10.5 [http://www.w3.org/2002/07/owl#Thing, http://www.xfront.com/owl/ontologies/camera/#PurchaseableItem, http://www.xfront.com/owl/ontologies/camera/#Camera, http://www.xfront.com/owl/ontologies/camera/#Large-Format]

Complete code:

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDFS;

public class BFSInRDFWithJena {

    public static List<List<Resource>> BFS( final Model model, final Queue<List<Resource>> queue, final int depth ) {
        final List<List<Resource>> results = new ArrayList<>();
        while ( !queue.isEmpty() ) {
            final List<Resource> path = queue.poll();
            results.add( path );
            if ( path.size() < depth ) {
                final Resource last = path.get( path.size() - 1 );
                final StmtIterator stmt = model.listStatements( null, RDFS.subClassOf, last );
                while ( stmt.hasNext() ) {
                    final List<Resource> extPath = new ArrayList<>( path );
                    extPath.add( stmt.next().getSubject().asResource() );
                    queue.offer( extPath );
                }
            }
        }
        return results;
    }

    public static int classSize( final Resource klass ) {
        return klass.getModel().listSubjectsWithProperty( RDFS.subClassOf, klass ).toList().size();
    }

    public static double pathSize( final List<Resource> path ) {
        int prevSize = classSize( path.get( 0 )); 
        double pathSum = prevSize;
        for ( int i = 1; i < path.size(); i++ ) {
            int currSize = classSize( path.get( i ));
            double linkWeight = currSize < prevSize ? 0.5 : 1.0;
            pathSum += linkWeight + currSize;
            prevSize = currSize;
        }
        return pathSum;
    }

    public static void main( final String[] args ) throws IOException {
        final Model model = ModelFactory.createDefaultModel();
        try ( final InputStream in = BFSInRDFWithJena.class.getClassLoader().getResourceAsStream( "camera.owl" ) ) {
            model.read( in, null );
        }

        // setup the initial queue
        final Queue<List<Resource>> queue = new LinkedList<>();
        final List<Resource> thingPath = new ArrayList<>();
        thingPath.add( OWL.Thing.inModel( model ));
        queue.offer( thingPath );

        // Get the paths, and display them
        final List<List<Resource>> paths = BFS( model, queue, 4 );
        for ( List<Resource> path : paths ) {
            System.out.println( pathSize( path ) + " " + path );
        }
    }
}
Community
  • 1
  • 1
Joshua Taylor
  • 80,876
  • 9
  • 135
  • 306
  • 1
    Joshua thank you, that's correct. Was missing the link on constructing the method and the great point is the double linkWeight = currSize < prevSize ? 0.5 : 1.0;. This is bravo. – user2502144 Jul 26 '13 at 08:19
  • @user2502144 Glad to hear it helps! One thing that you might want to do, if you're doing this on a lot of paths, though, is to _cache_ the size of the classes. For instance, in the example above, there are ten paths, and the size of `owl:Thing` is getting computed ten times. `PurchaseableItem` appears in six paths and its size is computed six times. Each computation requires a query to the graph and iterating over the results to construct a Java list. This could easily be cached, and probably ought to be. – Joshua Taylor Jul 26 '13 at 12:48
  • 1
    That sound great. Definitely caching will improve performance and the likes and would love to do so. I appreciate if you can assist me on how to get this done and also if you can point me to the tutorials that can help me add more knowledge. Thank you. – user2502144 Jul 26 '13 at 20:43
  • @user2502144 I'd just add a [HashMap field](http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html) to the class, and when computing `classSize`, first check whether there's an entry in the map for the class, and if there isn't, compute the size, and store it in the map. The return the value stored in the map. – Joshua Taylor Jul 27 '13 at 01:45
  • 1
    Thanks for an additional positive input to my peoblem. – user2502144 Jul 27 '13 at 06:52