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 com.google.common.collect.ComparisonChain;
022import com.google.common.collect.Sets;
023import org.apache.jena.graph.Node;
024import org.apache.jena.rdf.model.Model;
025import org.apache.jena.rdf.model.RDFNode;
026import org.apache.jena.rdf.model.Resource;
027import org.apache.jena.rdf.model.Statement;
028import org.apache.jena.sparql.util.NodeComparator;
029import org.apache.jena.sparql.vocabulary.FOAF;
030import org.apache.jena.util.iterator.ExtendedIterator;
031import org.dllearner.algorithms.qtl.QueryTreeUtils;
032import org.dllearner.algorithms.qtl.datastructures.impl.RDFResourceTree;
033import org.dllearner.algorithms.qtl.util.StopURIsDBpedia;
034import org.dllearner.algorithms.qtl.util.StopURIsOWL;
035import org.dllearner.algorithms.qtl.util.StopURIsRDFS;
036import org.dllearner.algorithms.qtl.util.filters.NamespaceDropStatementFilter;
037import org.dllearner.algorithms.qtl.util.filters.ObjectDropStatementFilter;
038import org.dllearner.algorithms.qtl.util.filters.PredicateDropStatementFilter;
039import org.dllearner.kb.sparql.ConciseBoundedDescriptionGenerator;
040import org.dllearner.kb.sparql.ConciseBoundedDescriptionGeneratorImpl;
041import org.dllearner.kb.sparql.SparqlEndpoint;
042
043import java.util.*;
044import java.util.function.Predicate;
045
046/**
047 * A base factory for query trees.
048 *
049 * @author Lorenz Bühmann
050 *
051 */
052public class QueryTreeFactoryBase implements QueryTreeFactory {
053
054        private int nodeId;
055        private final Comparator<Statement> comparator = new StatementComparator();
056
057        private int maxDepth = 3;
058
059        private Set<Predicate<Statement>> dropFilters = new HashSet<>();
060
061        public QueryTreeFactoryBase() {
062        }
063
064        /* (non-Javadoc)
065         * @see org.dllearner.algorithms.qtl.impl.QueryTreeFactory#setMaxDepth(int)
066         */
067        @Override
068        public void setMaxDepth(int maxDepth) {
069                this.maxDepth = maxDepth;
070        }
071
072        @Override
073        public int maxDepth() {
074                return maxDepth;
075        }
076
077        /* (non-Javadoc)
078                 * @see org.dllearner.algorithms.qtl.impl.QueryTreeFactory#getQueryTree(org.apache.jena.rdf.model.Resource, org.apache.jena.rdf.model.Model, int)
079                 */
080        @Override
081        public RDFResourceTree getQueryTree(Resource resource, Model model, int maxDepth) {
082                return createTree(resource, model, maxDepth);
083        }
084        
085        /* (non-Javadoc)
086         * @see org.dllearner.algorithms.qtl.impl.QueryTreeFactory#addDropFilters(org.apache.jena.util.iterator.Filter)
087         */
088        @SafeVarargs
089        @Override
090        public final void addDropFilters(Predicate<Statement>... dropFilters) {
091                this.dropFilters.addAll(Arrays.asList(dropFilters));
092        }
093
094        private RDFResourceTree createTree(Resource resource, Model model, int maxDepth) {
095                nodeId = 0;
096                Map<Resource, SortedSet<Statement>> resource2Statements = new HashMap<>();
097
098                fillMap(resource, model, resource2Statements);
099
100                RDFResourceTree tree = new RDFResourceTree(resource.asNode());
101                fillTree(resource, tree, resource2Statements, 0, maxDepth);
102
103                return tree;
104        }
105
106        private void fillMap(Resource s, Model model, Map<Resource, SortedSet<Statement>> resource2Statements) {
107
108                // get all statements with subject s
109                ExtendedIterator<Statement> it = model.listStatements(s, null, (RDFNode) null);
110
111                // filter statement if necessary
112                if (!dropFilters.isEmpty()) {
113                        Iterator<Predicate<Statement>> iter = dropFilters.iterator();
114                        Predicate<Statement> keepFilter = iter.next();
115                        it = it.filterKeep(keepFilter);
116                        while (iter.hasNext()) {it = it.filterKeep(iter.next());
117//                              keepFilter = keepFilter.and(iter.next());
118                        }
119//                      it = it.filterKeep(keepFilter);
120                }
121
122                SortedSet<Statement> statements = resource2Statements.computeIfAbsent(s, k -> new TreeSet<>(comparator));
123
124                while (it.hasNext()) {
125                        Statement st = it.next();
126                        statements.add(st);
127                        if ((st.getObject().isResource()) && !resource2Statements.containsKey(st.getObject().asResource())) {
128                                fillMap(st.getObject().asResource(), model, resource2Statements);
129                        }
130                }
131        }
132
133        private void fillTree(Resource root, RDFResourceTree tree, Map<Resource, SortedSet<Statement>> resource2Statements,
134                        int currentDepth, int maxDepth) {
135                currentDepth++;
136                if (resource2Statements.containsKey(root)) {
137                        RDFResourceTree subTree;
138
139                        for (Statement st : resource2Statements.get(root)) {
140                                Node predicate = st.getPredicate().asNode();
141                                RDFNode object = st.getObject();
142
143                                if (object.isLiteral()) {
144                                        subTree = new RDFResourceTree(nodeId++, object.asNode());
145                                        tree.addChild(subTree, predicate);
146                                } else if (object.isURIResource()) {
147                                        subTree = new RDFResourceTree(nodeId++, object.asNode());
148                                        tree.addChild(subTree, predicate);
149//                                      System.out.println(root + "::" + object + "::" + (currentDepth < maxDepth));
150                                        if (currentDepth < maxDepth) {
151                                                fillTree(object.asResource(), subTree, resource2Statements, currentDepth, maxDepth);
152                                        }
153                                } else if (object.isAnon()) {
154                                        subTree = new RDFResourceTree(nodeId++);
155                                        tree.addChild(subTree, predicate);
156                                        if (currentDepth < maxDepth) {
157                                                fillTree(object.asResource(), subTree, resource2Statements, currentDepth, maxDepth);
158                                        }
159                                }
160                        }
161                }
162                currentDepth--;
163        }
164
165        static class StatementComparator implements Comparator<Statement> {
166                
167                final NodeComparator nodeComparator = new NodeComparator();
168
169                @Override
170                public int compare(Statement s1, Statement s2) {
171                        return ComparisonChain.start()
172                                        .compare(s1.getPredicate().asNode(), s2.getPredicate().asNode(), nodeComparator)
173                                        .compare(s1.getObject().asNode(), s2.getObject().asNode(), nodeComparator)
174                                        .result();
175                }
176        }
177
178        public static String encode(String s) {
179                char[] htmlChars = s.toCharArray();
180                StringBuilder encodedHtml = new StringBuilder();
181                for (char htmlChar : htmlChars) {
182                        switch (htmlChar) {
183                                case '<':
184                                        encodedHtml.append("&lt;");
185                                        break;
186                                case '>':
187                                        encodedHtml.append("&gt;");
188                                        break;
189                                case '&':
190                                        encodedHtml.append("&amp;");
191                                        break;
192                                case '\'':
193                                        encodedHtml.append("&#39;");
194                                        break;
195                                case '"':
196                                        encodedHtml.append("&quot;");
197                                        break;
198                                case '\\':
199                                        encodedHtml.append("&#92;");
200                                        break;
201                                case (char) 133:
202                                        encodedHtml.append("&#133;");
203                                        break;
204                                default:
205                                        encodedHtml.append(htmlChar);
206                                        break;
207                        }
208                }
209                return encodedHtml.toString();
210        }
211
212        
213
214        public static void main(String[] args) throws Exception {
215                QueryTreeFactory factory = new QueryTreeFactoryBase();
216                factory.setMaxDepth(2);
217                factory.addDropFilters(
218                                new PredicateDropStatementFilter(Sets.union(Sets.union(StopURIsDBpedia.get(), StopURIsRDFS.get()), StopURIsOWL.get())),
219                                new ObjectDropStatementFilter(StopURIsOWL.get()),
220                                new NamespaceDropStatementFilter(
221                                                Sets.newHashSet(
222                                                                "http://dbpedia.org/property/", 
223                                                                "http://purl.org/dc/terms/",
224                                                                "http://dbpedia.org/class/yago/",
225                                                                FOAF.getURI()
226                                                                )
227                                                                )
228                                );
229                ConciseBoundedDescriptionGenerator cbdGen = new ConciseBoundedDescriptionGeneratorImpl(
230                                SparqlEndpoint.getEndpointDBpedia());
231                String resourceURI = "http://dbpedia.org/resource/Athens";
232                Model cbd = cbdGen.getConciseBoundedDescription(resourceURI, 2);
233                RDFResourceTree queryTree = factory.getQueryTree(resourceURI, cbd);
234                System.out.println(queryTree.getStringRepresentation());
235                System.out.println(QueryTreeUtils.toSPARQLQuery(queryTree));
236        }
237
238}