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.simple;
020
021import org.apache.jena.ontology.OntClass;
022import org.apache.jena.ontology.OntModel;
023import org.apache.jena.ontology.OntModelSpec;
024import org.apache.jena.rdf.model.*;
025import com.jamonapi.Monitor;
026import com.jamonapi.MonitorFactory;
027import org.dllearner.core.AbstractKnowledgeSource;
028import org.dllearner.core.ComponentAnn;
029import org.dllearner.core.ComponentInitException;
030import org.dllearner.core.annotations.OutVariable;
031import org.dllearner.core.config.ConfigOption;
032import org.dllearner.kb.OWLOntologyKnowledgeSource;
033import org.dllearner.utilities.OwlApiJenaUtils;
034import org.dllearner.utilities.analyse.TypeOntology;
035import org.semanticweb.owlapi.model.OWLOntology;
036import org.semanticweb.owlapi.model.OWLOntologyManager;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040import java.util.*;
041
042@ComponentAnn(name = "efficient SPARQL fragment extractor", shortName = "sparqls", version = 0.1)
043public class SparqlSimpleExtractor extends AbstractKnowledgeSource implements OWLOntologyKnowledgeSource{
044
045    @ConfigOption(description = "URL of the SPARQL endpoint", required = true)
046    private String endpointURL = null;
047    @OutVariable
048    private OntModel model = null;
049    @ConfigOption(description = "List of the instances to use", required = true)
050    private List<String> instances = null;
051    @ConfigOption(description = "Filter for the tbox, can use variable ?s, ?p amd ?o", required = false)
052    private String aboxfilter = null;
053    @ConfigOption(description = "Filter for the tbox, can use variable ?example and ?class", required = false)
054    private String tboxfilter = null;
055
056    @ConfigOption(description = "recursion depth", required = true)
057    private int recursionDepth = 0;
058
059    @ConfigOption(description = "default graph URI", required = true)
060    private String defaultGraphURI = null;
061
062    @ConfigOption(description = "Sparql Query", required = false)
063    private String sparqlQuery = null;
064    @ConfigOption(description = "List of Ontology Schema URLs", required = true)
065    private List<String> ontologySchemaUrls = null;
066
067    private SchemaIndexer indexer;
068
069    private static Logger log = LoggerFactory.getLogger(SparqlSimpleExtractor.class);
070
071    public SparqlSimpleExtractor() {
072        model = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM);
073    }
074
075    public static void main(String[] args) throws ComponentInitException {
076        SparqlSimpleExtractor extractor = new SparqlSimpleExtractor();
077        extractor.setEndpointURL("http://live.dbpedia.org/sparql");
078        extractor.setRecursionDepth(1);
079        extractor.setDefaultGraphURI("http://dbpedia.org");
080        List<String> instances = new ArrayList<>(7);
081        instances.add("http://dbpedia.org/resource/Democritus");
082        instances.add("http://dbpedia.org/resource/Zeno_of_Elea");
083        instances.add("http://dbpedia.org/resource/Plato");
084        instances.add("http://dbpedia.org/resource/Socrates");
085        instances.add("http://dbpedia.org/resource/Archytas");
086        instances.add("http://dbpedia.org/resource/Pythagoras");
087        instances.add("http://dbpedia.org/resource/Philolaus");
088
089        extractor.setInstances(instances);
090        extractor.init();
091        List<String> individuals = new LinkedList<>();
092        individuals.add("People");
093        individuals.add("Animals");
094        extractor.setInstances(individuals);
095        // System.out.println(extractor.createQuery());
096    }
097
098    public Set<String> difference(Set<String> alreadyQueriedIndividuals, OntModel model) {
099        Set<String> candidates = new HashSet<>();
100        Set<String> result = new HashSet<>();
101        for (ResIterator it = model.listSubjects(); it.hasNext(); ) {
102            candidates.add(it.next().getURI());
103        }
104        for (NodeIterator it = model.listObjects(); it.hasNext(); ) {
105            RDFNode cur = it.next();
106            if (cur.isURIResource() && !cur.isAnon()) {
107                candidates.add(((Resource) cur).getURI());
108            }
109        }
110
111        for (String candidate : candidates) {
112            if (!alreadyQueriedIndividuals.contains(candidate)) {
113//                System.out.println(candidate);
114                result.add(candidate);
115            }
116        }
117
118        return result;
119    }
120
121    @Override
122    public void init() throws ComponentInitException {
123
124        if (endpointURL == null) {
125            throw new ComponentInitException(
126                    "Parameter endpoint URL is required");
127        }
128        if (instances == null) {
129            throw new ComponentInitException("Parameter instances is required");
130        }
131        if (recursionDepth == 0) {
132            throw new ComponentInitException(
133                    "A value bigger than 0 is required for parameter recursionDepth");
134        }
135        if (ontologySchemaUrls == null) {
136            throw new ComponentInitException(
137                    "An ontology schema OWLClassExpression file (ontologyFile) in RDF is required");
138        }
139
140        Monitor monComp = MonitorFactory.start("Simple SPARQL Component")
141                .start();
142        Monitor monIndexer = MonitorFactory.start("Schema Indexer").start();
143        indexer = new SchemaIndexer();
144        indexer.setOntologySchemaUrls(ontologySchemaUrls);
145        indexer.init();
146        monIndexer.stop();
147
148        TypeOntology typeOntology = new TypeOntology();
149
150        Monitor monQueryingABox;
151        QueryExecutor executor = new QueryExecutor();
152        String queryString;
153        Set<String> instancesSet = new HashSet<>(instances);
154        Set<String> alreadyQueried = new HashSet<>();
155        Monitor typizeModel;
156        if (sparqlQuery == null) {
157            ABoxQueryGenerator aGenerator = new ABoxQueryGenerator();
158            for (int i = 0; i < recursionDepth; i++) {
159                if (instancesSet.isEmpty()) {
160                    log.warn("no new instances found more recursions (recursion {} )  {} new instances", i,instancesSet.size());
161
162                }
163
164                log.info("processing (recursion  {} ) {} new instances",i,instancesSet.size());
165                queryString = aGenerator.createQuery(instancesSet, aboxfilter);
166//                System.out.println(queryString);
167                log.debug("SPARQL: {}", queryString);
168
169                monQueryingABox = MonitorFactory.start("ABox query time");
170                                try {
171                                        executor.executeQuery(queryString, endpointURL, model, defaultGraphURI);
172                                } catch (Exception e) {
173                                        e.printStackTrace();
174                                }
175                monQueryingABox.stop();
176
177                typizeModel=MonitorFactory.start("Typize the model");
178                model=typeOntology.addTypetoJena(model, instances, null);
179                typizeModel.stop();
180
181                alreadyQueried.addAll(instancesSet);
182                instancesSet = difference(alreadyQueried, model);
183
184            }
185
186            log.info("recursion depth: {} reached, {} new instances",recursionDepth,instancesSet.size());
187
188            //queryString = aGenerator.createLastQuery(instances, model, filters);
189            //log.debug("SPARQL: {}", queryString);
190
191            //monQueryingABox = MonitorFactory.start("ABox query time");
192            //Monitor monQueryingABox2 = MonitorFactory.start("ABox query time last query");
193            //executor.executeQuery(queryString, endpointURL, model, defaultGraphURI);
194            //monQueryingABox.stop();
195            //monQueryingABox2.stop();
196
197        } else {
198            monQueryingABox = MonitorFactory.getTimeMonitor("ABox query time").start();
199            executor.executeQuery(sparqlQuery, endpointURL, model, null);
200            monQueryingABox.stop();
201        }
202
203        TBoxQueryGenerator tGenerator = new TBoxQueryGenerator();
204
205        //TODO check if all instances are queried. model.listIndividuals().toSet()
206        queryString = tGenerator.createQuery(alreadyQueried, tboxfilter);
207
208        Monitor monQueryingTBox = MonitorFactory.start("TBox query time");
209
210        executor.executeQuery(queryString, endpointURL, model, defaultGraphURI);
211        monQueryingTBox.stop();
212
213        Monitor monIndexing = MonitorFactory.start("Querying index and conversion");
214        Set<OntClass> classes = model.listClasses().toSet();
215        for (OntClass ontClass : classes) {
216            OntModel hierarchy = indexer.getHierarchyForURI(ontClass.getURI());
217            if (hierarchy != null) {
218                model.add(hierarchy);
219                log.debug("{}", model);
220            }
221        }
222
223        monIndexing.stop();
224        monComp.stop();
225//        log.info("*******Simple SPARQL Extractor********");
226//        /*for (Monitor monitor : MonitorFactory.getRootMonitor().getMonitors()) {
227//            log.info("* {} *", monitor);
228//        }*/
229//        log.info(JamonMonitorLogger.getStringForAllSortedByLabel());
230//        log.info("**************************************");
231        
232        initialized = true;
233    }
234
235    public String getEndpointURL() {
236        return endpointURL;
237    }
238
239    public void setEndpointURL(String endpointURL) {
240        this.endpointURL = endpointURL;
241    }
242
243    public String getDefaultGraphURI() {
244        return defaultGraphURI;
245    }
246
247    public void setDefaultGraphURI(String defaultGraphURI) {
248        this.defaultGraphURI = defaultGraphURI;
249    }
250
251    public Model getModel() {
252        return model;
253    }
254
255    public void setModel(OntModel model) {
256        this.model = model;
257    }
258
259    public String getAboxfilter() {
260        return aboxfilter;
261    }
262
263    public void setAboxfilter(String aboxfilter) {
264        this.aboxfilter = aboxfilter;
265    }
266
267    /**
268     * @return the instances
269     */
270    public List<String> getInstances() {
271        return instances;
272    }
273
274    /**
275     * @param instances the instances to set
276     */
277    public void setInstances(List<String> instances) {
278        this.instances = instances;
279    }
280
281    /**
282     * @return the recursionDepth
283     */
284    public int getRecursionDepth() {
285        return recursionDepth;
286    }
287
288    /**
289     * @param recursionDepth the recursionDepth to set
290     */
291    public void setRecursionDepth(int recursionDepth) {
292        this.recursionDepth = recursionDepth;
293    }
294
295    public List<String> getOntologySchemaUrls() {
296        return ontologySchemaUrls;
297    }
298
299    public void setOntologySchemaUrls(List<String> ontologySchemaUrls) {
300        this.ontologySchemaUrls = ontologySchemaUrls;
301    }
302
303    public String getTboxfilter() {
304        return tboxfilter;
305    }
306
307    public void setTboxfilter(String tboxfilter) {
308        this.tboxfilter = tboxfilter;
309    }
310
311    public String getSparqlQuery() {
312        return sparqlQuery;
313    }
314
315    public void setSparqlQuery(String sparqlQuery) {
316        this.sparqlQuery = sparqlQuery;
317    }
318
319    @Override
320    public OWLOntology createOWLOntology(OWLOntologyManager manager) {
321        return OwlApiJenaUtils.getOWLOntology(model);
322    }
323
324}