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.filters;
020
021import org.apache.jena.rdf.model.RDFNode;
022import org.apache.jena.rdf.model.Statement;
023import uk.ac.shef.wit.simmetrics.similaritymetrics.AbstractStringMetric;
024import uk.ac.shef.wit.simmetrics.similaritymetrics.JaroWinkler;
025import uk.ac.shef.wit.simmetrics.similaritymetrics.Levenshtein;
026import uk.ac.shef.wit.simmetrics.similaritymetrics.QGramsDistance;
027
028import java.util.*;
029import java.util.Map.Entry;
030import java.util.function.Predicate;
031
032public class KeywordBasedStatementFilter2 implements Predicate<Statement> {
033        
034        private Set<String> questionWords;
035        
036        private AbstractStringMetric qGramMetric;
037        private AbstractStringMetric levensteinMetric;
038        private AbstractStringMetric jaroWinklerMetric;
039        private I_Sub substringMetric;
040        
041        private double threshold = 0.4;
042        
043        private int topK = 3;
044        private double topKSumThreshold = 0.8;
045        
046        private Map<Statement, Double> statement2Similarity = new HashMap<>();
047        
048        private Map<RDFNode, Boolean> cache = new HashMap<>();
049        
050        private Map<Statement, String> statement2TokenMap = new HashMap<>();
051        
052        private Map<String, String> resource2TokenMap = new HashMap<>();
053        
054        int cnt = 0;
055        
056        public KeywordBasedStatementFilter2(Set<String> questionWords){
057                this.questionWords = questionWords;
058                qGramMetric = new QGramsDistance();
059                levensteinMetric = new Levenshtein();
060                jaroWinklerMetric = new JaroWinkler();
061                substringMetric = new I_Sub();
062                
063        }
064
065        private boolean isSimiliar2QuestionWord(String s, Statement st){
066                for(String word : questionWords){
067                        if(areSimiliar(word, s, st)){
068                                statement2TokenMap.put(st, word);
069                                resource2TokenMap.put(s, word);
070                                return true;
071                        }
072                }
073                return isSimilarWithSubstringMetrik(s, st);
074        }
075        
076        private boolean areSimiliar(String s1, String s2, Statement st){
077                return (qGramMetric.getSimilarity(s1, s2) >= threshold) || 
078                (levensteinMetric.getSimilarity(s1, s2) >= threshold);
079        }
080        
081        private boolean isSimilarWithSubstringMetrik(String s, Statement st){
082                SortedSet<Double> values = new TreeSet<>(Collections.reverseOrder());
083                for(String word : questionWords){
084                        double v = substringMetric.score(word, s, true);
085                        if(v >= threshold){statement2TokenMap.put(st, word);resource2TokenMap.put(s, word);
086                                return true;
087                        } else {
088                                values.add(v);
089                        }
090                } 
091                double sum = 0;
092                for(Double v : getTopK(values)){
093                        if(v >= 0){
094                                sum += v;
095                        }
096                        
097                }
098                if(sum >= topKSumThreshold){
099                        statement2TokenMap.put(st, "ALL");
100                }
101                return sum >= topKSumThreshold;
102        }
103        
104        private Set<Double> getTopK(SortedSet<Double> values){
105                Set<Double> top = new HashSet<>();
106                int k = 0;
107                for(Double v : values){
108                        if(k == topK){
109                                break;
110                        }
111                        top.add(v);
112                        k++;
113                }
114                return top;
115        }
116        
117        
118        private String getFragment(String uri){
119                int i = uri.lastIndexOf("#");
120                if(i > 0){
121                        return uri.substring(i+1);
122                } else {
123                        return uri.substring(uri.lastIndexOf("/")+1);
124                }
125        }
126
127        @Override
128        public boolean test(Statement s) {
129                Boolean similarPredicate = cache.get(s.getPredicate());
130                Boolean similarObject = cache.get(s.getObject());
131                if(similarPredicate != null && similarObject != null){
132                        String object = null;
133                        if(s.getObject().isURIResource()){
134                                object = getFragment(s.getObject().asResource().getURI());
135                        } else if(s.getObject().isLiteral()){
136                                object = s.getObject().asLiteral().getLexicalForm();
137                        }
138                        String token = resource2TokenMap.get(object);
139                        if(token != null){
140                                statement2TokenMap.put(s, token);
141                        } else {
142                                token = resource2TokenMap.get(getFragment(s.getPredicate().getURI()));
143                                if( token != null){
144                                        statement2TokenMap.put(s, token);
145                                } 
146                        }
147                
148                        
149                        return similarPredicate || similarObject;
150                } else if(similarPredicate == null && similarObject != null){
151                        if(similarObject){
152                                String object = null;
153                                if(s.getObject().isURIResource()){
154                                        object = getFragment(s.getObject().asResource().getURI());
155                                } else if(s.getObject().isLiteral()){
156                                        object = s.getObject().asLiteral().getLexicalForm();
157                                }
158                                String token = resource2TokenMap.get(object);
159                                if( token != null){
160                                        statement2TokenMap.put(s, token);
161                                }
162                                return true;
163                        } else {
164                                String predicate = getFragment(s.getPredicate().getURI());
165                                if (isSimiliar2QuestionWord(predicate, s)){
166                                        cache.put(s.getPredicate(), true);
167                                        return true;
168                                } else {
169                                        cache.put(s.getPredicate(), false);
170                                        return false;
171                                }
172                        }
173                } else if(similarPredicate != null && similarObject == null){
174                        if(similarPredicate){
175                                String object = null;
176                                if(s.getObject().isURIResource()){
177                                        object = getFragment(s.getObject().asResource().getURI());
178                                } else if(s.getObject().isLiteral()){
179                                        object = s.getObject().asLiteral().getLexicalForm();
180                                }
181                                if(isSimiliar2QuestionWord(object, s)){
182                                        cache.put(s.getObject(), true);
183                                        String token = resource2TokenMap.get(object);
184                                        if( token != null){
185                                                statement2TokenMap.put(s, token);
186                                        }
187                                        return true;
188                                } else {
189                                        cache.put(s.getObject(), false);
190                                }
191                                
192                                String token = resource2TokenMap.get(getFragment(s.getPredicate().getURI()));
193                                if( token != null){
194                                        statement2TokenMap.put(s, token);
195                                }
196                                return true;
197                        } else {
198                                String object = null;
199                                if(s.getObject().isURIResource()){
200                                        object = getFragment(s.getObject().asResource().getURI());
201                                } else if(s.getObject().isLiteral()){
202                                        object = s.getObject().asLiteral().getLexicalForm();
203                                }
204                                if(isSimiliar2QuestionWord(object, s)){
205                                        cache.put(s.getObject(), true);
206                                        return true;
207                                } else {
208                                        cache.put(s.getObject(), false);
209                                        return false;
210                                }
211                        }
212                } else {
213                        String object = null;
214                        if(s.getObject().isURIResource()){
215                                object = getFragment(s.getObject().asResource().getURI());
216                        } else if(s.getObject().isLiteral()){
217                                object = s.getObject().asLiteral().getLexicalForm();
218                        }
219                        if(isSimiliar2QuestionWord(object, s)){
220                                cache.put(s.getObject(), true);
221                                return true;
222                        } else {
223                                cache.put(s.getObject(), false);
224                        }
225                        
226                        String predicate = getFragment(s.getPredicate().getURI());
227                        if (isSimiliar2QuestionWord(predicate, s)){
228                                cache.put(s.getPredicate(), true);
229                                return true;
230                        } else {
231                                cache.put(s.getPredicate(), false);
232                        }
233                        return false;
234                }
235        }
236        
237//      @Override
238//      public boolean accept(Statement s) {
239//              String predicate = s.getPredicate().getURI().substring(s.getPredicate().getURI().lastIndexOf("/"));
240//              String object = null;
241//              if(s.getObject().isURIResource()){
242//                      object = s.getObject().asResource().getURI();
243//                      object = getFragment(s.getObject().asResource().getURI());
244//              } else if(s.getObject().isLiteral()){
245//                      object = s.getObject().asLiteral().getLexicalForm();
246//              }
247//              return isSimiliar2QuestionWord(predicate, s) || isSimiliar2QuestionWord(object, s);
248//      }
249        
250        public void setThreshold(double threshold){
251                this.threshold = threshold;
252        }
253        
254        public double getThreshold(){
255                return threshold;
256        }
257        
258        public Set<Statement> getStatementsBelowThreshold(double threshold){
259                Set<Statement> statements = new HashSet<>();
260                for(Entry<Statement, Double> entry : statement2Similarity.entrySet()){
261                        if(entry.getValue() < threshold){
262                                statements.add(entry.getKey());
263                        }
264                }
265                return statements;
266        }
267
268        public Map<Statement, String> getStatement2TokenMap() {
269                return statement2TokenMap;
270        }
271
272}