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.kb.sparql; 020 021import com.google.common.collect.Sets; 022import org.aksw.jena_sparql_api.cache.core.QueryExecutionFactoryCacheEx; 023import org.aksw.jena_sparql_api.cache.extra.CacheFrontend; 024import org.aksw.jena_sparql_api.cache.h2.CacheUtilsH2; 025import org.aksw.jena_sparql_api.core.FluentQueryExecutionFactory; 026import org.aksw.jena_sparql_api.core.QueryExecutionFactory; 027import org.aksw.jena_sparql_api.http.QueryExecutionHttpWrapper; 028import org.aksw.jena_sparql_api.model.QueryExecutionFactoryModel; 029import org.aksw.jena_sparql_api.pagination.core.QueryExecutionFactoryPaginated; 030import org.apache.jena.query.ParameterizedSparqlString; 031import org.apache.jena.query.QueryExecution; 032import org.apache.jena.rdf.model.Model; 033import org.apache.jena.riot.WebContent; 034import org.apache.jena.sparql.core.Var; 035import org.apache.jena.sparql.engine.http.QueryEngineHTTP; 036import org.apache.jena.sparql.util.FmtUtils; 037import org.apache.jena.vocabulary.RDF; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041import java.util.Set; 042import java.util.TreeSet; 043import java.util.concurrent.TimeUnit; 044import java.util.stream.Collectors; 045 046/** 047 * {@inheritDoc} 048 * @author Lorenz Buehmann 049 * 050 */ 051public class ConciseBoundedDescriptionGeneratorImpl extends AbstractConciseBoundedDescriptionGenerator { 052 053 private boolean useSingleQuery = false; 054 055 public ConciseBoundedDescriptionGeneratorImpl(QueryExecutionFactory qef) { 056 super(qef); 057 } 058 059 /** 060 * @deprecated Will be removed in next release as it is redundant. Please use {@link ConciseBoundedDescriptionGeneratorImpl#ConciseBoundedDescriptionGeneratorImpl(QueryExecutionFactory)} 061 * @param endpoint 062 * @param cacheDir 063 */ 064 @Deprecated() 065 public ConciseBoundedDescriptionGeneratorImpl(SparqlEndpoint endpoint, String cacheDir) { 066 this(FluentQueryExecutionFactory 067 .http(endpoint.getURL().toString(), endpoint.getDefaultGraphURIs()) 068 .config().withPostProcessor(qe -> ((QueryEngineHTTP) ((QueryExecutionHttpWrapper) qe).getDecoratee()) 069 .setModelContentType(WebContent.contentTypeRDFXML)) 070 .end() 071 .create()); 072 073 if(cacheDir != null){ 074 long timeToLive = TimeUnit.DAYS.toMillis(30); 075 CacheFrontend cacheFrontend = CacheUtilsH2.createCacheFrontend(cacheDir, true, timeToLive); 076 qef = new QueryExecutionFactoryCacheEx(qef, cacheFrontend); 077 } 078 qef = new QueryExecutionFactoryPaginated(qef, 10000); 079 } 080 081 public ConciseBoundedDescriptionGeneratorImpl(SparqlEndpoint endpoint) { 082 this(endpoint, null); 083 } 084 085 public ConciseBoundedDescriptionGeneratorImpl(Model model) { 086 this(new QueryExecutionFactoryModel(model)); 087 } 088 089 @Override 090 public Model getConciseBoundedDescription(Set<String> resources, int depth, boolean withTypesForLeafs) { 091 if (useSingleQuery) { 092 log.trace("Computing CBDs for {} ...", resources); 093 long start = System.currentTimeMillis(); 094 // build the template 095 ParameterizedSparqlString template = generateQueryTemplate(depth, withTypesForLeafs, true); 096 097 // set the VALUES clause 098 String query = template.toString().replace("%VALUES%", resources.stream().map(r -> "<" + r + ">").collect(Collectors.joining(" "))); 099 log.trace(query); 100 System.out.println(query); 101 102 try (QueryExecution qe = qef.createQueryExecution(query)) { 103 Model model = qe.execConstruct(); 104 log.trace("Got {} triples in {} ms.", model.size(), (System.currentTimeMillis() - start)); 105 return model; 106 } catch (Exception e) { 107 log.error("Failed to computed CBD for resources {}", resources); 108 throw new RuntimeException("Failed to computed CBD for resource " + resources, e); 109 } 110 } else { 111 return super.getConciseBoundedDescription(resources, depth, withTypesForLeafs); 112 } 113 } 114 115 116 /** 117 * A SPARQL CONSTRUCT query is created, to get a RDF graph for the given example with a specific recursion depth. 118 * @param resource The example resource for which a CONSTRUCT query is created. 119 * @return the SPARQL query 120 */ 121 protected String generateQuery(String resource, int depth, boolean withTypesForLeafs){ 122 ParameterizedSparqlString template = generateQueryTemplate(depth, withTypesForLeafs, false); 123 template.setIri("s", resource); 124 return template.toString(); 125 } 126 127 private ParameterizedSparqlString generateQueryTemplate(int depth, boolean withTypesForLeafs, boolean withValuesSubjectAnchor){ 128 int lastIndex = Math.max(0, depth - 1); 129 130 131 StringBuilder sb = new StringBuilder(); 132 sb.append("CONSTRUCT {\n"); 133 sb.append(triplePattern("?s", "?p0", "?o0")); 134// sb.append("?p0 a ?type0.\n"); 135 for(int i = 1; i < depth; i++){ 136 sb.append(triplePattern("?o" + (i-1), "?p" + i, "?o" + i)); 137 } 138 if(withTypesForLeafs){ 139 sb.append("?o").append(lastIndex).append(" a ?type.\n"); 140 } 141 sb.append("} WHERE {\n"); 142 if(withValuesSubjectAnchor) { 143 sb.append("VALUES ?s {%VALUES%}"); 144 } 145 sb.append(triplePattern("?s", "?p0", "?o0")); 146 sb.append(createPredicateFilter(Var.alloc("p0"))); 147 sb.append(createObjectFilter(Var.alloc("p0"), Var.alloc("o0"))); 148// sb.append("?p0 a ?type0.\n"); 149 for(int i = 1; i < depth; i++){ 150 sb.append("OPTIONAL{\n"); 151 sb.append(triplePattern("?o" + (i-1), "?p" + i, "?o" + i)); 152 sb.append(createPredicateFilter(Var.alloc("p" + i))); 153 sb.append(createObjectFilter(Var.alloc("p" + i), Var.alloc("o" + i))); 154 } 155 if(withTypesForLeafs){ 156 sb.append("OPTIONAL{?o").append(lastIndex).append(" a ?type.}\n"); 157 } 158 for(int i = 1; i < depth; i++){ 159 sb.append("}"); 160 } 161 sb.append("}\n"); 162 163 return new ParameterizedSparqlString(sb.toString()); 164 } 165 166 public static void main(String[] args) { 167 SparqlEndpoint endpoint = SparqlEndpoint.getEndpointDBpedia(); 168 Set<String> ignoredProperties = Sets.newHashSet( 169 "http://dbpedia.org/ontology/abstract", 170 "http://dbpedia.org/ontology/wikiPageID", 171 "http://dbpedia.org/ontology/wikiPageRevisionID", 172 "http://dbpedia.org/ontology/wikiPageID"); 173 174 ConciseBoundedDescriptionGenerator cbdGen = new ConciseBoundedDescriptionGeneratorImpl(endpoint); 175// cbdGen.setIgnoredProperties(ignoredProperties); 176// cbdGen.setAllowedPropertyNamespaces(Sets.newHashSet("http://dbpedia.org/ontology/")); 177// cbdGen.setAllowedClassNamespaces(Sets.newHashSet("http://dbpedia.org/ontology/")); 178// cbdGen.setAllowedObjectNamespaces(Sets.newHashSet("http://dbpedia.org/resource/")); 179 cbdGen = new CachingConciseBoundedDescriptionGenerator(cbdGen); 180// cbdGen.setRestrictToNamespaces(Arrays.asList(new String[]{"http://dbpedia.org/ontology/", RDF.getURI(), RDFS.getURI()})); 181 Model cbd = cbdGen.getConciseBoundedDescription(Sets.newHashSet("http://dbpedia.org/resource/Leipzig", "http://dbpedia.org/resource/Dresden"),2); 182 183 System.out.println(cbd.size()); 184 } 185 186 187 188}