[ https://issues.apache.org/jira/browse/RYA-292?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16128088#comment-16128088 ]
ASF GitHub Bot commented on RYA-292: ------------------------------------ Github user jessehatfield commented on a diff in the pull request: https://github.com/apache/incubator-rya/pull/206#discussion_r133319932 --- Diff: sail/src/main/java/org/apache/rya/rdftriplestore/inference/InferenceEngine.java --- @@ -416,22 +425,131 @@ private void refreshHasValueRestrictions(Map<Resource, URI> restrictions) throws } } - private static Vertex getVertex(Graph graph, Object id) { - Iterator<Vertex> it = graph.vertices(id.toString()); + private void refreshIntersectionOf() throws QueryEvaluationException { + final Map<Resource, List<Set<Resource>>> intersectionsProp = new HashMap<>(); + + // First query for all the owl:intersectionOf's. + // If we have the following intersectionOf: + // :A owl:intersectionOf[:B, :C] + // It will be represented by triples following a pattern similar to: + // <:A> owl:intersectionOf _:bnode1 . + // _:bnode1 rdf:first <:B> . + // _:bnode1 rdf:rest _:bnode2 . + // _:bnode2 rdf:first <:C> . + // _:bnode2 rdf:rest rdf:nil . + ryaDaoQueryWrapper.queryAll(null, OWL.INTERSECTIONOF, null, new RyaDaoStatementIterHandler() { + @Override + public void handleStatementIter(final Statement st1) throws Exception { + final Resource type = st1.getSubject(); + // head will point to a type that is part of the intersection. + URI head = (URI) st1.getObject(); + if (!intersectionsProp.containsKey(type)) { + intersectionsProp.put(type, new ArrayList<Set<Resource>>()); + } + final Set<Resource> intersection = new HashSet<>(); + // Go through and find all bnodes that are part of the defined + // intersection. + while (!RDF.NIL.equals(head)) { + // rdf.first will point to a type item that is in the + // intersection. + ryaDaoQueryWrapper.queryFirst(head, RDF.FIRST, null, new RyaDaoStatementIterHandler() { + @Override + public void handleStatementIter(final Statement st2) throws Exception{ + // The object found in the query represents a type + // that should be included in the intersection. + final URI obj2 = (URI) st2.getObject(); + intersection.add(obj2); + } + }); + final List<URI> headHolder = new ArrayList<>(1); + // rdf.rest will point to the next bnode that's part of the + // intersection. + ryaDaoQueryWrapper.queryFirst(head, RDF.REST, null, new RyaDaoStatementIterHandler() { + @Override + public void handleStatementIter(final Statement st3) throws Exception { + // This object is the next bnode head to look for. + final URI obj3 = (URI) st3.getObject(); + headHolder.add(obj3); + } + }); + // As long as we get a new head there are more bnodes that + // are part of the intersection. Keep going until we reach + // rdf.nil. + if (!headHolder.isEmpty()) { + head = headHolder.get(0); + } else { + head = RDF.NIL; + } + } + // Add this intersection for this type. There may be more + // intersections for this type so each type has a list of + // intersection sets. + intersectionsProp.get(type).add(intersection); + } + }); + + for (final Map.Entry<Resource, List<Set<Resource>>> entry : intersectionsProp.entrySet()) { + final Resource type = entry.getKey(); + final List<Set<Resource>> intersectionList = entry.getValue(); + final Set<Resource> otherTypes = new HashSet<>(); + // Combine all of a type's intersections together. + for (final Set<Resource> intersection : intersectionList) { + otherTypes.addAll(intersection); + } + for (final Resource other : otherTypes) { + // :A intersectionOf[:B, :C] implies that + // :A subclassOf :B + // :A subclassOf :C + // So add each type that's part of the intersection to the + // subClassOf graph. + addSubClassOf(type, other); + for (final Set<Resource> intersection : intersectionList) { + if (!intersection.contains(other)) { + addIntersection(intersection, other); --- End diff -- Upon thinking about this, I wonder if it might be better to handle multiple intersections via the subclass relations we're adding, rather than by explicitly connecting each type/intersection pair like this. That is: 1. If A equals (the intersection of B and C) and A equals (the intersection of D and E), then we want to make sure (B and C) doesn't just imply A but also implies D and E. (And, equivalently, that (D and E) implies both B and C.) This inner for loop applies this rule. 2. It's also true that if A is a subclass of A2, and A equals (the intersection of B and C), then anything belonging to (B and C) is implied to belong to A2. (Because it belongs to A, and anything belonging to a subclass also belongs to its superclasses.) Since we're explicitly adding the facts (A subClassOf D), (A subClassOf E), etc., then rule 2 is just a more general version of rule 1. So an alternative approach would be to replace the innermost addIntersection loop with an implementation of this second rule, which would have the benefit of being more powerful in cases where the intersection type is a subclass of some other type. (e.g. `[ intersectionOf (X Y) ] subClassOf Z` or more likely `Z equivalentClass [ intersectionOf (X Y) ]` ). This could be done either at query time (in getIntersectionsImplying(type), get the subclasses of the type and include any of their intersections as well); or here at refresh time (after looping over the intersections and adding subclass edges, loop through again: for each (type, intersection list) pair, and for each superclass of that type, add the subclass's intersections to the superclass). > Implement owl:intersectionOf inference > -------------------------------------- > > Key: RYA-292 > URL: https://issues.apache.org/jira/browse/RYA-292 > Project: Rya > Issue Type: Sub-task > Components: sail > Reporter: Jesse Hatfield > Assignee: Eric White > > An *{{owl:intersectionOf}}* expression defines the set of resources who > belong to all of a particular set of classes. > A basic implementation, if the ontology states that {{:Mother}} is the > intersection of {{:Parent}} and {{:Woman}}, should cause the inference engine > to: > 1. Rewrite query patterns {{?x rdf:type :Mother}} (the intersection type) to > check for resources that have both types {{:Parent}} and {{:Woman}} (as well > as check for resources that are explicitly stated to be {{:Mother}} s) > 2. Rewrite query patterns {{?y rdf:type :Parent}} (one of the intersecting > sets) to check for resources that are stated to be either {{:Mother}} or > {{:Parent}} , since belonging to the intersection type implies membership in > the component types. (Equivalent logic applies to {{Woman}} ) -- This message was sent by Atlassian JIRA (v6.4.14#64029)