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.aquisitors;
020
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025import java.util.SortedSet;
026
027import org.apache.log4j.Logger;
028import org.dllearner.kb.sparql.SPARQLTasks;
029import org.dllearner.kb.sparql.SparqlQueryMaker;
030import org.dllearner.utilities.JamonMonitorLogger;
031import org.dllearner.utilities.datastructures.RDFNodeTuple;
032import org.dllearner.utilities.owl.OWLVocabulary;
033
034import org.apache.jena.query.QuerySolution;
035import org.apache.jena.query.ResultSetRewindable;
036import org.apache.jena.rdf.model.RDFNode;
037import com.jamonapi.Monitor;
038
039/**
040 * Can execute different queries.
041 * 
042 * @author Sebastian Hellmann
043 * 
044 */
045public class SparqlTupleAquisitor extends TupleAquisitor {
046        
047        
048        private static Logger logger = Logger.getLogger(SparqlTupleAquisitor.class);
049        protected static final String PREDICATE = "predicate";
050        protected static final String OBJECT = "object";
051        
052        protected SparqlQueryMaker sparqlQueryMaker;
053        protected SPARQLTasks sparqlTasks;
054        
055        
056        
057        
058
059        public SparqlTupleAquisitor(SparqlQueryMaker sparqlQueryMaker, SPARQLTasks sparqlTasks) {
060                
061                this.sparqlQueryMaker = sparqlQueryMaker;
062                this.sparqlTasks = sparqlTasks;
063        }
064        
065        @Override
066        public SortedSet<RDFNodeTuple> retrieveTupel(String uri){
067                // getQuery
068                String sparqlQueryString = sparqlQueryMaker.makeSubjectQueryUsingFilters(uri);
069                SortedSet<RDFNodeTuple> ret = sparqlTasks.queryAsRDFNodeTuple(sparqlQueryString, PREDICATE, OBJECT);
070                disambiguateBlankNodes(uri, ret);
071                
072                return ret;
073        }
074        @Override
075        public SortedSet<RDFNodeTuple> retrieveClassesForInstances(String uri){
076                // getQuery
077                String sparqlQueryString = sparqlQueryMaker.makeClassQueryUsingFilters(uri);
078                SortedSet<RDFNodeTuple> ret = sparqlTasks.queryAsRDFNodeTuple(sparqlQueryString, PREDICATE, OBJECT);
079                disambiguateBlankNodes(uri, ret);
080                return ret;
081                
082        }
083        @Override
084        public SortedSet<RDFNodeTuple> retrieveTuplesForClassesOnly(String uri){
085                SortedSet<RDFNodeTuple> ret = retrieveTupel(uri);
086                //the next line is not necessary
087                //disambiguateBlankNodes(uri, ret);
088                return ret;
089        }
090        
091        @Override
092        public SortedSet<RDFNodeTuple> getBlankNode(int id){
093                return BlankNodeCollector.getBlankNode(id);
094        }
095        
096        public void printHM(){
097                
098                        for (int j = 0; j <  BlankNodeCollector.getBlankNodeMap().size(); j++) {
099                                System.out.println(j);
100                                for(RDFNodeTuple t :BlankNodeCollector.getBlankNodeMap().get(j)){
101                                        System.out.println(t);
102                                }
103                        }
104                
105        }
106        
107        // main function for resolving blanknodes
108        @Override
109        protected void disambiguateBlankNodes(String uri, SortedSet<RDFNodeTuple> resultSet){
110                if(!isDissolveBlankNodes()){
111                        return;
112                }
113                Monitor bnodeMonitor = JamonMonitorLogger.getTimeMonitor(SparqlTupleAquisitor.class, "blanknode time").start();
114                try{
115                for (RDFNodeTuple tuple : resultSet) {
116                        
117                        if(tuple.b.isAnon()){
118                                int currentId = BlankNodeCollector.getNextGlobalBNodeId();
119                                // replace the blanknode
120                                tuple.b = new RDFBlankNode(currentId, tuple.b);
121                                //System.out.println(uri+" replaced blanknode "+tuple.b);
122                                dissolveBlankNodes(currentId, uri, tuple);
123                                //System.out.println(BlankNodeCollector.getBlankNodeMap());
124                                
125                        }
126                }
127                }catch (Exception e) {
128                        e.printStackTrace();
129                        System.exit(0);
130                }finally{
131                        bnodeMonitor.stop();
132                }
133                
134        }
135        
136        // extends a sparql query as long as there are undissolved blanknodes
137        private void dissolveBlankNodes(int currentId, String uri, RDFNodeTuple tuple){
138                try{
139                        int currentDepth = 1;
140                        int lastDepth = 1;
141                        ResultSetRewindable rsw=null;
142                        do{
143                        String p = tuple.a.toString();
144                        if(p.equals(OWLVocabulary.RDFS_COMMENT) || p.equals(OWLVocabulary.RDFS_LABEL)  ){
145                                return ;
146                        }
147                        String q = BlankNodeCollector.makeQuery(uri, p, currentDepth);
148//                      System.out.println(q);
149                        rsw = sparqlTasks.queryAsResultSet(q);
150                        rsw.reset();
151                        lastDepth = currentDepth;
152                        }while (!BlankNodeCollector.testResultSet(rsw, currentDepth++));
153                        
154                        assignIds( currentId,  rsw, lastDepth);
155                }catch (Exception e) {
156                        logger.info("An error occurred while dissolving blanknodes");
157                        logger.debug("Error was:", e);
158                }
159        }
160        
161        //takes the resultset and assigns internal ids
162        private void assignIds(int currentId, ResultSetRewindable rsw, int lastDepth){
163                //prepare variables according to last depth
164                List<String> vars = new ArrayList<>();
165                vars.add("o0");
166                for (int i = 1; i <= lastDepth; i++) {
167                        vars.add("p"+i);
168                        vars.add("o"+i);
169                }
170                
171                final List<String> tmpVars = new ArrayList<>();
172                
173                Map<String, Integer> lastNodes = new HashMap<>();
174                // the resultset first variable is o0
175                // iteration over each tuple of the set
176                while (rsw.hasNext()){
177                        tmpVars.clear();
178                        tmpVars.addAll(vars);
179                        QuerySolution q = rsw.nextSolution();
180                        
181                        //skip all that do not start with a blanknode
182                        // could be two different blank nodes here, but unlikely
183                        if(!q.get("o0").isAnon()){
184                                lastNodes.put(q.get("o0").toString(), currentId);
185                        }else{
186                                
187                                // remove the first node
188                                tmpVars.remove(0);
189                                assignIdRec(currentId, q, tmpVars,lastNodes);
190                        }
191                        
192                
193                }
194                rsw.reset();
195                
196        }
197        
198        private void assignIdRec(int currentId, QuerySolution q, List<String> vars, Map<String, Integer> lastNodes ){
199                if(vars.isEmpty()){return;}
200                String pvar = vars.remove(0);
201                String ovar = vars.remove(0);
202                
203                // the next node
204                RDFNode n = q.get(ovar);
205                if(n.isAnon()){
206                        int nextId;
207                        if(lastNodes.get(n.toString())==null){
208                                nextId = BlankNodeCollector.getNextGlobalBNodeId();
209                                lastNodes.put(n.toString(), nextId);
210                                //System.out.println(n.toString());
211                        }else{
212                                nextId = lastNodes.get(n.toString());
213                        }
214                        RDFNodeTuple tuple = new RDFNodeTuple(q.get(pvar), new RDFBlankNode(nextId,n));
215                        BlankNodeCollector.addBlankNode(currentId, tuple);
216                        assignIdRec(nextId, q, vars, lastNodes);
217                }else{
218                        BlankNodeCollector.addBlankNode(currentId, new RDFNodeTuple(q.get(pvar), n));
219                }
220                
221                
222        }
223        
224        
225        
226
227
228        
229        
230        
231        
232        
233        
234
235
236}