001/** 002 * Copyright (C) 2007 - 2016, Jens Lehmann 003 * 004 * This file is part of DL-Learner. 005 * 006 * DL-Learner is free software; you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation; either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * DL-Learner is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package org.dllearner.algorithms.qtl.impl; 020 021import java.util.*; 022import java.util.function.Predicate; 023 024import com.google.common.collect.Sets; 025import org.apache.jena.graph.Node; 026import org.apache.jena.rdf.model.Model; 027import org.apache.jena.rdf.model.RDFNode; 028import org.apache.jena.rdf.model.Resource; 029import org.apache.jena.rdf.model.Statement; 030import org.apache.jena.sparql.vocabulary.FOAF; 031import org.apache.jena.util.iterator.ExtendedIterator; 032import org.apache.jena.vocabulary.RDF; 033import org.dllearner.algorithms.qtl.QueryTreeUtils; 034import org.dllearner.algorithms.qtl.datastructures.NodeInv; 035import org.dllearner.algorithms.qtl.datastructures.impl.RDFResourceTree; 036import org.dllearner.algorithms.qtl.util.StatementComparator; 037import org.dllearner.algorithms.qtl.util.StopURIsDBpedia; 038import org.dllearner.algorithms.qtl.util.StopURIsOWL; 039import org.dllearner.algorithms.qtl.util.StopURIsRDFS; 040import org.dllearner.algorithms.qtl.util.filters.NamespaceDropStatementFilter; 041import org.dllearner.algorithms.qtl.util.filters.ObjectDropStatementFilter; 042import org.dllearner.algorithms.qtl.util.filters.PredicateDropStatementFilter; 043import org.dllearner.kb.sparql.ConciseBoundedDescriptionGenerator; 044import org.dllearner.kb.sparql.SparqlEndpoint; 045import org.dllearner.kb.sparql.SymmetricConciseBoundedDescriptionGeneratorImpl; 046 047/** 048 * A factory for query trees that also considers incoming triples. 049 * 050 * @author Lorenz Bühmann 051 * 052 */ 053public class QueryTreeFactoryBaseInv implements QueryTreeFactory { 054 055 private int nodeId; 056 private final Comparator<Statement> comparator = new StatementComparator(); 057 058 private int maxDepth = 3; 059 060 private Set<Predicate<Statement>> dropFilters = new HashSet<>(); 061 062 /* (non-Javadoc) 063 * @see org.dllearner.algorithms.qtl.impl.QueryTreeFactory#setMaxDepth(int) 064 */ 065 @Override 066 public void setMaxDepth(int maxDepth) { 067 this.maxDepth = maxDepth; 068 } 069 070 @Override 071 public int maxDepth() { 072 return maxDepth; 073 } 074 075 /* (non-Javadoc) 076 * @see org.dllearner.algorithms.qtl.impl.QueryTreeFactory#getQueryTree(org.apache.jena.rdf.model.Resource, org.apache.jena.rdf.model.Model, int) 077 */ 078 @Override 079 public RDFResourceTree getQueryTree(Resource resource, Model model, int maxDepth) { 080 return createTree(resource, model, maxDepth); 081 } 082 083 /* (non-Javadoc) 084 * @see org.dllearner.algorithms.qtl.impl.QueryTreeFactory#addDropFilters(org.apache.jena.util.iterator.Filter) 085 */ 086 @Override 087 @SuppressWarnings("unchecked") 088 public void addDropFilters(Predicate<Statement>... dropFilters) { 089 this.dropFilters.addAll(Arrays.asList(dropFilters)); 090 } 091 092 private RDFResourceTree createTree(Resource resource, Model model, int maxDepth) { 093 nodeId = 0; 094 095 // create mapping from resources to statements, both in subject an object position 096 Map<Resource, SortedSet<Statement>> resource2InStatements = new HashMap<>(); 097 Map<Resource, SortedSet<Statement>> resource2OutStatements = new HashMap<>(); 098 fillMaps(resource, model, resource2InStatements, resource2OutStatements, 0, maxDepth); 099 100 // start with an empty tree whose root is the resource 101 RDFResourceTree tree = new RDFResourceTree(resource.asNode()); 102 103 // fill the tree 104 fillTree(resource, null, tree, resource2InStatements, resource2OutStatements, 0, maxDepth); 105 106 return tree; 107 } 108 109 @SuppressWarnings("unchecked") 110 private void fillMaps(Resource s, Model model, 111 Map<Resource, SortedSet<Statement>> resource2InStatements, 112 Map<Resource, SortedSet<Statement>> resource2OutStatements, 113 int currentDepth, int maxDepth) { 114 115 if(currentDepth < maxDepth) { 116 // incoming triples 117 SortedSet<Statement> statements = resource2InStatements.computeIfAbsent(s, k -> new TreeSet<>(comparator)); 118 ExtendedIterator stmtIterator = model.listStatements(null, null, s); 119 for (Predicate<Statement> filter : dropFilters) { 120 stmtIterator = stmtIterator.filterKeep(filter); 121 } 122 statements.addAll(stmtIterator.toSet()); 123 statements.forEach(st -> fillMaps(st.getSubject(), model, resource2InStatements, resource2OutStatements, currentDepth + 1, maxDepth)); 124 125 // outgoing triples 126 statements = resource2OutStatements.computeIfAbsent(s, k -> new TreeSet<>(comparator)); 127 stmtIterator = model.listStatements(s, null, (RDFNode) null); 128 for (Predicate<Statement> filter : dropFilters) { 129 stmtIterator = stmtIterator.filterKeep(filter); 130 } 131 statements.addAll(stmtIterator.toSet()); 132 statements.stream().filter(st -> st.getObject().isResource()).forEach(st -> 133 fillMaps(st.getObject().asResource(), model, resource2InStatements, resource2OutStatements, currentDepth + 1, maxDepth) 134 ); 135 } 136 } 137 138 private int nextNodeId() { 139 return nodeId++; 140 } 141 142 private void fillTree(Resource root, Statement statementFromParent, RDFResourceTree tree, 143 Map<Resource, SortedSet<Statement>> resource2InStatements, 144 Map<Resource, SortedSet<Statement>> resource2OutStatements, 145 int currentDepth, int maxDepth) { 146 if(resource2InStatements.containsKey(root)) { 147 resource2InStatements.get(root).stream().filter(st -> !st.equals(statementFromParent)).forEach(st -> { 148 149 // check if path to parent is rdf:type, i.e. we have a class node 150 // if so, we avoid incoming edges 151 if(!tree.isRoot() && tree.getEdgeToParent().matches(RDF.type.asNode())) { 152 return; 153 } 154 155 Node predicate = new NodeInv(st.getPredicate().asNode()); 156 157 RDFNode data = st.getSubject(); 158 159 // create the subtree 160 RDFResourceTree subTree = new RDFResourceTree(nextNodeId(), data.asNode()); 161 tree.addChild(subTree, predicate); 162 163 // if current depth is < max depth recursive call 164 if (currentDepth + 1 < maxDepth) { 165 fillTree(data.asResource(), st, subTree, resource2InStatements, resource2OutStatements, currentDepth + 1, maxDepth); 166 } 167 }); 168 } 169 if(resource2OutStatements.containsKey(root)) { 170 resource2OutStatements.get(root).stream().filter(st -> !st.equals(statementFromParent)).forEach(st -> { 171 Node predicate = st.getPredicate().asNode(); 172 173 RDFNode data = st.getObject(); 174 175 // create the subtree 176 RDFResourceTree subTree = new RDFResourceTree(nextNodeId(), data.asNode()); 177 tree.addChild(subTree, predicate); 178 179 // if root of subtree is not a literal and current depth is < max depth recursive call 180 if (!data.isLiteral() && (currentDepth + 1 < maxDepth)) { 181 fillTree(data.asResource(), st, subTree, resource2InStatements, resource2OutStatements, currentDepth + 1, maxDepth); 182 } 183 }); 184 } 185 } 186 187 public static void main(String[] args) throws Exception { 188 QueryTreeFactory factory = new QueryTreeFactoryBaseInv(); 189 factory.setMaxDepth(2); 190 factory.addDropFilters( 191 new PredicateDropStatementFilter(Sets.union(Sets.union(StopURIsDBpedia.get(), StopURIsRDFS.get()), StopURIsOWL.get())), 192 new ObjectDropStatementFilter(StopURIsOWL.get()), 193 new NamespaceDropStatementFilter( 194 Sets.newHashSet( 195 "http://dbpedia.org/property/", 196 "http://purl.org/dc/terms/", 197 "http://dbpedia.org/class/yago/", 198 FOAF.getURI() 199 ) 200 ) 201 ); 202 ConciseBoundedDescriptionGenerator cbdGen = new SymmetricConciseBoundedDescriptionGeneratorImpl( 203 SparqlEndpoint.getEndpointDBpedia()); 204 String resourceURI = "http://dbpedia.org/resource/Athens"; 205 Model cbd = cbdGen.getConciseBoundedDescription(resourceURI, 1); 206 RDFResourceTree queryTree = factory.getQueryTree(resourceURI, cbd); 207 System.out.println(queryTree.getStringRepresentation()); 208 System.out.println(QueryTreeUtils.toSPARQLQuery(queryTree)); 209 } 210 211}