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 org.dllearner.utilities.datastructures.StringTuple;
022import org.dllearner.utilities.owl.OWLVocabulary;
023
024import java.util.ArrayList;
025import java.util.List;
026import java.util.Set;
027import java.util.TreeSet;
028
029/**
030 * Can assemble sparql queries. can make queries for subject, predicate, object
031 * according to the filter settings object SparqlQueryType, which gives the
032 * predicate and object lists
033 * 
034 * @author Sebastian Hellmann
035 * 
036 */
037public class SparqlQueryMaker {
038
039        private static final String MODE_ALLOW = "allow";
040
041        private static final String MODE_FORBID = "forbid";
042
043        private static final String lineend = "\n";
044
045        // allow false is forbid
046        private boolean allowMode = false;
047
048        private boolean assembled = false;
049
050        private String filter = "";
051
052        private Set<String> objectFilterList;
053
054        private Set<String> predicateFilterList;
055        
056        private Set<StringTuple> predicateobjectFilterList;
057
058        private boolean literals = false;
059
060        public void setLiterals(boolean literals) {
061                this.literals = literals;
062        }
063
064        public SparqlQueryMaker(Set<String> objectFilterList,
065                        Set<String> predicateFilterList, boolean literals) {
066                super();
067                this.objectFilterList = objectFilterList;
068                this.predicateFilterList = predicateFilterList;
069                this.predicateobjectFilterList = new TreeSet<>();
070                this.literals = literals;
071        }
072
073        public SparqlQueryMaker(boolean allowMode,
074                        Set<String> objectFilterList,
075                        Set<String> predicateFilterList, boolean literals) {
076
077                this(objectFilterList, predicateFilterList, literals);
078                this.allowMode = allowMode;
079        }
080
081        public SparqlQueryMaker(String mode, Set<String> objectFilterList,
082                        Set<String> predicateFilterList, boolean literals) {
083                this(objectFilterList, predicateFilterList, literals);
084                if (mode.equalsIgnoreCase(MODE_ALLOW)) {
085                        this.allowMode = true;
086                } else if (mode.equalsIgnoreCase(MODE_FORBID)) {
087                        this.allowMode = false;
088                } else {
089                        this.allowMode = false;
090                }
091        }
092
093        public String makeSubjectQueryUsingFilters(String subject) {
094
095                // String filter = internalFilterAssemblySubject();
096                if (!assembled) {
097                        filter = internalFilterAssemblySubject("predicate", "object");
098                        filter = (filter.length() > 0) ? "FILTER( " + lineend + filter
099                                        + "). " : " ";
100                        assembled = true;
101                }
102
103                String returnString = "SELECT * WHERE { " + lineend + "<" + subject
104                                + "> ?predicate ?object. " + lineend + filter + " } ";
105
106                return returnString;
107        }
108        
109        //QUALITY optimize
110        public String makeClassQueryUsingFilters(String subject) {
111
112                // String filter = internalFilterAssemblySubject();
113                String tmpFilter = internalFilterAssemblySubject("predicate", "object");
114                        tmpFilter = (tmpFilter.length() > 0) ? "FILTER( " + lineend + tmpFilter
115                                        + "). " : " ";
116                
117                String returnString = "SELECT * WHERE {" +lineend + 
118                        "<" + subject + "> ?predicate ?object;" +
119                        "a ?object . "+lineend+
120                        tmpFilter + "}";
121                
122                //String returnString = "SELECT * WHERE {" +lineend + 
123                //      "<" + subject + ">  <"+OWLVocabulary.RDF_TYPE+"> ?object. " +lineend+
124                //      tmpFilter + "}";
125
126                return returnString;
127        }
128
129        public String makeSubjectQueryLevel(String subject, int level) {
130                
131                // String filter = internalFilterAssemblySubject();
132                // if (!assembled) {
133                String filtertmp = "";
134                filtertmp = internalFilterAssemblySubject("predicate0", "object0");
135                filtertmp = (filtertmp.length() > 0) ? "FILTER( " + filtertmp + "). "
136                                : " ";
137
138                StringBuffer sbuff = new StringBuffer(1400);
139                sbuff.append("SELECT * WHERE { " + lineend + "{<").append(subject).append("> ?predicate0 ?object0 .").append(lineend);
140                sbuff.append(filtertmp).append("} ").append(lineend);
141
142                // " + lineend + filter +" } ";
143                for (int i = 1; i < level; i++) {
144                        sbuff.append("OPTIONAL { ");
145                        sbuff.append("?object").append(i - 1).append(" ?predicate").append(i).append(" ?object").append(i).append(" . ").append(lineend);
146
147                        filtertmp = internalFilterAssemblySubject("predicate" + i, "object"
148                                        + i);
149                        filtertmp = (filtertmp.length() > 0) ? "FILTER " + filtertmp + ". "
150                                        : " ";
151
152                        sbuff.append(filtertmp).append(" }");
153                }
154
155                sbuff.append(lineend + "} ");
156
157                return sbuff.toString();
158        }
159
160        private String internalFilterAssemblySubject(String predicateVariable,
161                        String objectVariable) {
162                predicateVariable = (predicateVariable.startsWith("?")) ? predicateVariable
163                                : "?" + predicateVariable;
164                objectVariable = (objectVariable.startsWith("?")) ? objectVariable
165                                : "?" + objectVariable;
166
167                List<String> terms = new ArrayList<>();
168                String not = (isAllowMode()) ? "" : "!";
169                /*new filter type */
170                
171                for (StringTuple tuple : getPredicateObjectFilterList()) {
172                        List<String> tmpterms = new ArrayList<>();
173                        tmpterms.add(not + "regex(str(" + predicateVariable + "), '" + tuple.a+ "')");
174                        tmpterms.add(not + "regex(str(" + objectVariable + "), '" + tuple.b+ "')");
175                        terms.add(assembleTerms(tmpterms, "&&"));
176                }
177                
178                for (String pred : getPredicateFilterList()) {
179                        terms.add(not + "regex(str(" + predicateVariable + "), '" + pred
180                                        + "')");
181                }
182                for (String obj : getObjectFilterList()) {
183                        terms
184                                        .add(not + "regex(str(" + objectVariable + "), '" + obj
185                                                        + "')");
186                }
187                String assembled =  assembleTerms(terms, getOperator());
188                
189                terms = new ArrayList<>();
190                // the next line could be removed as it is included in assemble terms
191                if(!assembled.isEmpty()){
192                        terms.add(assembled);
193                }
194                if (!isLiterals()) {
195                        terms.add("!isLiteral(" + objectVariable + ")");
196                }
197                return assembleTerms(terms, "&&");
198                
199
200        }
201        
202        private String getOperator(){
203                return (isAllowMode())?"||":"&&";
204                
205        }
206
207        
208        private String assembleTerms(List<String> terms, String operator) {
209                if((!operator.equals("||")) && (!operator.equals("&&"))){
210                        System.out.println("in SparqlQuerymaker assembleTerms recieved wrong operator");
211                        System.exit(0);
212                }
213                
214                if (terms.isEmpty())
215                        return "";
216                else if (terms.size() == 1)
217                        return (terms.get(0).isEmpty())?"": brackets(terms.get(0));
218                else {
219                        StringBuffer sbuf = new StringBuffer(1400);
220                        String first = terms.remove(0);
221                        sbuf.append(brackets(first));
222                        for (String term : terms) {
223                                sbuf.append(lineend).append(operator);
224                                sbuf.append(brackets(term));
225                        }
226                        return brackets(sbuf.toString());
227                }
228
229        }
230
231        private static String brackets(String s) {
232                return "(" + s + ")";
233        }
234
235        public boolean isLiterals() {
236                return literals;
237        }
238
239        public boolean isAllowMode() {
240                return allowMode;
241        }
242
243        public Set<String> getObjectFilterList() {
244                return objectFilterList;
245        }
246
247        public Set<String> getPredicateFilterList() {
248                return predicateFilterList;
249        }
250        public Set<StringTuple> getPredicateObjectFilterList() {
251                return predicateobjectFilterList;
252        }
253
254        public void addPredicateFilter(String newFilter) {
255                assembled = false;
256                predicateFilterList.add(newFilter);
257        }
258        
259        public void addObjectFilter(String newFilter) {
260                assembled = false;
261                objectFilterList.add(newFilter);
262        }
263        public void addPredicateObjectFilter(String pred, String object) {
264                assembled = false;
265                predicateobjectFilterList.add(new StringTuple(pred, object));
266        }
267        
268        public void combineWith(SparqlQueryMaker sqm){
269                predicateFilterList.addAll(sqm.predicateFilterList);
270                objectFilterList.addAll(sqm.objectFilterList);
271        }
272
273        public static SparqlQueryMaker getSparqlQueryMakerByName(String name) {
274
275                if (name.equalsIgnoreCase("YAGO"))
276                        return getAllowYAGOFilter();
277                else if (name.equalsIgnoreCase("SKOS"))
278                        return getAllowSKOSFilter();
279                else if (name.equalsIgnoreCase("YAGOSKOS"))
280                        return getAllowYAGOandSKOSFilter();
281                else if (name.equalsIgnoreCase("YAGOSPECIALHIERARCHY"))
282                        return getYagoSpecialHierarchyFilter();
283                else if (name.equalsIgnoreCase("YAGOONLY"))
284                        return getAllowYAGO_ONLYFilter();
285                else if (name.equalsIgnoreCase("TEST"))
286                        return getTestFilter();
287                else if (name.equalsIgnoreCase("DBPEDIA-NAVIGATOR"))
288                        return getDBpediaNavigatorFilter();
289                else
290                        return null;
291        }
292        
293        private void addFiltersForDBpediaSKOS() {
294                addPredicateFilter("http://www.w3.org/2004/02/skos/core");
295                addObjectFilter("http://www.w3.org/2004/02/skos/core");
296                addObjectFilter("http://dbpedia.org/resource/Category:");
297                addObjectFilter("http://dbpedia.org/resource/Template");
298        }
299        
300        private void addFiltersForDBpediaUMBEL() {
301                addObjectFilter("http://umbel.org/umbel/");
302        }
303        @SuppressWarnings("unused")
304        private void addFiltersForDBpediaOntology() {
305                addObjectFilter("http://dbpedia.org/ontology/");
306        }
307        @SuppressWarnings("unused")
308        private void addFiltersForDBpediaCyc() {
309                addObjectFilter("http://sw.opencyc.org/2008/06/10/concept/");
310        }
311        
312        private void addFiltersForYago() {
313                addObjectFilter("http://dbpedia.org/class/yago");
314                
315        }
316        
317        private void addFiltersForOWLSameAs() {
318                addPredicateFilter("http://www.w3.org/2002/07/owl#sameAs");
319        }
320        private void addFiltersForFOAF() {
321                addPredicateFilter("http://xmlns.com/foaf/0.1/");
322                addObjectFilter("http://xmlns.com/foaf/0.1/");
323                
324        }
325        
326        private void addFiltersForWordNet() {
327                addObjectFilter("http://www.w3.org/2006/03/wn/wn20/instances/synset");
328                
329        }
330        private void addFiltersForGeonames() {
331                addObjectFilter("http://www.geonames.org");
332                
333        }
334        private void addFiltersForFlickrwrappr() {
335                addObjectFilter("http://www4.wiwiss.fu-berlin.de/flickrwrappr");
336                
337        }
338        
339        private void addFiltersForDBpedia() {
340                addPredicateFilter("http://dbpedia.org/property/reference");
341                addPredicateFilter("http://dbpedia.org/property/website");
342                addPredicateFilter("http://dbpedia.org/property/wikipage");
343                addPredicateFilter("http://dbpedia.org/property/wikiPageUsesTemplate");
344                addPredicateFilter("http://dbpedia.org/property/relatedInstance");
345                addPredicateFilter("http://dbpedia.org/property/owner");
346                addPredicateFilter("http://dbpedia.org/property/standard");             
347                addObjectFilter("http://upload.wikimedia.org/wikipedia/commons");
348                addObjectFilter("http://upload.wikimedia.org/wikipedia");       
349        }
350        
351        public static SparqlQueryMaker getAllowSKOSFilter() {
352                SparqlQueryMaker sqm = new SparqlQueryMaker("forbid", new TreeSet<>(), new TreeSet<>(), false);
353                sqm.combineWith(getAllowYAGOandSKOSFilter());
354                sqm.addFiltersForYago();
355                                
356                sqm.addPredicateFilter("http://www.w3.org/2004/02/skos/core#narrower");
357                sqm.addObjectFilter("http://dbpedia.org/resource/Template");
358                
359                return sqm;
360        }
361
362        public static SparqlQueryMaker getAllowYAGOFilter() {
363                SparqlQueryMaker sqm = new SparqlQueryMaker("forbid", new TreeSet<>(), new TreeSet<>(), false);
364                sqm.combineWith(getAllowYAGOandSKOSFilter());
365                sqm.addFiltersForDBpediaSKOS();
366                return sqm;
367        }
368        
369        public static SparqlQueryMaker getAllowYAGO_ONLYFilter() {
370                SparqlQueryMaker sqm = new SparqlQueryMaker("forbid", new TreeSet<>(), new TreeSet<>(), false);
371                sqm.combineWith(getAllowYAGOandSKOSFilter());
372                sqm.addFiltersForDBpediaSKOS();
373                sqm.addFiltersForDBpediaUMBEL();
374                return sqm;
375        }
376
377        public static SparqlQueryMaker getDBpediaNavigatorFilter() {
378//              SparqlQueryMaker sqm = new SparqlQueryMaker("allow", new TreeSet<String>(), new TreeSet<String>(), false);
379                SparqlQueryMaker sqm = new SparqlQueryMaker("allow", new TreeSet<>(), new TreeSet<>(), true);
380//              sqm.addPredicateFilter("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
381//              sqm.addPredicateFilter("http://www.w3.org/2000/01/rdf-schema#subClassOf");
382//              sqm.addPredicateFilter("http://www.w3.org/2003/01/geo/wgs84_pos#lat");
383//              sqm.addPredicateFilter("http://www.w3.org/2003/01/geo/wgs84_pos#long");
384//              sqm.addPredicateFilter("http://www.w3.org/2000/01/rdf-schema#label");
385                
386                String dbont = "http://dbpedia.org/ontology/";
387                sqm.addPredicateFilter(dbont);
388                sqm.addPredicateFilter(OWLVocabulary.RDFS_range);
389                sqm.addPredicateFilter(OWLVocabulary.RDFS_domain);
390                sqm.addPredicateObjectFilter(dbont, dbont);
391                sqm.addPredicateObjectFilter(OWLVocabulary.RDF_TYPE, dbont);
392                sqm.addPredicateObjectFilter(OWLVocabulary.RDFS_SUBCLASS_OF, dbont);
393                sqm.setLiterals(true);
394                
395                // pred.add("http://dbpedia.org/property/wikipage");
396                // pred.add("http://dbpedia.org/property/wikiPageUsesTemplate");
397                // pred.add("http://dbpedia.org/property/relatedInstance");
398                // pred.add("http://dbpedia.org/property/owner");
399                // pred.add("http://dbpedia.org/property/standard");
400                return sqm;
401        }
402
403        public static SparqlQueryMaker getYagoSpecialHierarchyFilter() {
404                SparqlQueryMaker sqm = new SparqlQueryMaker("forbid", new TreeSet<>(), new TreeSet<>(), false);
405                sqm.combineWith(getAllowYAGOFilter());
406                sqm.addPredicateFilter("http://dbpedia.org/property/monarch");
407                return sqm;
408        }
409
410
411
412        public static SparqlQueryMaker getAllowYAGOandSKOSFilter() {
413                SparqlQueryMaker sqm = new SparqlQueryMaker("forbid", new TreeSet<>(), new TreeSet<>(), false);
414                sqm.addFiltersForFOAF();
415                sqm.addFiltersForDBpedia();
416
417                sqm.addFiltersForGeonames();
418                sqm.addFiltersForWordNet();
419                sqm.addFiltersForFlickrwrappr();
420                sqm.addFiltersForOWLSameAs();
421                
422                sqm.addPredicateFilter("http://www.w3.org/2004/02/skos/core#narrower");
423                sqm.addObjectFilter("http://dbpedia.org/resource/Template");
424                return sqm;
425        }
426
427        public static SparqlQueryMaker getTestFilter() {
428                SparqlQueryMaker sqm = new SparqlQueryMaker("forbid", new TreeSet<>(), new TreeSet<>(), true);
429                sqm.combineWith(getAllowYAGOFilter());
430                return sqm;
431        }
432
433        public static void main(String[] args) {
434
435                String uri = "http://dbpedia.org/resource/Angela_Merkel";
436                // System.out.println(getSparqlQueryMakerByName("YAGO").makeSubjectQueryUsingFilters(uri));
437                // System.out.println(getSparqlQueryMakerByName("YAGO").makeSubjectQueryUsingFilters(uri).length());
438                // System.out.println(getDBpediaNavigatorFilter().makeSubjectQueryUsingFilters(uri));
439                System.out.println();
440                System.out.println(getSparqlQueryMakerByName("YAGO")
441                                .makeSubjectQueryLevel(uri, 3));
442
443        }
444
445
446}