1 /* 2 * This file is part of ELKI: 3 * Environment for Developing KDD-Applications Supported by Index-Structures 4 * 5 * Copyright (C) 2018 6 * ELKI Development Team 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 package de.lmu.ifi.dbs.elki.database.query.knn; 22 23 import java.util.ArrayList; 24 import java.util.List; 25 26 import de.lmu.ifi.dbs.elki.database.ids.*; 27 import de.lmu.ifi.dbs.elki.database.relation.Relation; 28 import de.lmu.ifi.dbs.elki.index.preprocessed.knn.AbstractMaterializeKNNPreprocessor; 29 import de.lmu.ifi.dbs.elki.logging.Logging; 30 import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException; 31 32 /** 33 * Instance for a particular database, invoking the preprocessor. 34 * 35 * @author Erich Schubert 36 * @since 0.4.0 37 * 38 * @param <O> Data object type 39 */ 40 public class PreprocessorKNNQuery<O> implements KNNQuery<O> { 41 /** 42 * Class logger 43 */ 44 private static final Logging LOG = Logging.getLogger(PreprocessorKNNQuery.class); 45 46 /** 47 * The data to use for this query 48 */ 49 final protected Relation<? extends O> relation; 50 51 /** 52 * The last preprocessor result 53 */ 54 final private AbstractMaterializeKNNPreprocessor<O> preprocessor; 55 56 /** 57 * Warn only once. 58 */ 59 private boolean warned = false; 60 61 /** 62 * Constructor. 63 * 64 * @param relation Relation to query 65 * @param preprocessor Preprocessor instance to use 66 */ PreprocessorKNNQuery(Relation<? extends O> relation, AbstractMaterializeKNNPreprocessor<O> preprocessor)67 public PreprocessorKNNQuery(Relation<? extends O> relation, AbstractMaterializeKNNPreprocessor<O> preprocessor) { 68 super(); 69 this.relation = relation; 70 this.preprocessor = preprocessor; 71 } 72 73 @Override getKNNForDBID(DBIDRef id, int k)74 public KNNList getKNNForDBID(DBIDRef id, int k) { 75 if(!warned && k > preprocessor.getK()) { 76 getLogger().warning("Requested more neighbors than preprocessed: requested " + k + " preprocessed " + preprocessor.getK(), new Throwable()); 77 warned = true; 78 } 79 return preprocessor.get(id).subList(k); 80 } 81 82 @Override getKNNForBulkDBIDs(ArrayDBIDs ids, int k)83 public List<KNNList> getKNNForBulkDBIDs(ArrayDBIDs ids, int k) { 84 if(!warned && k > preprocessor.getK()) { 85 getLogger().warning("Requested more neighbors than preprocessed: requested " + k + " preprocessed " + preprocessor.getK(), new Throwable()); 86 warned = true; 87 } 88 if(k < preprocessor.getK()) { 89 List<KNNList> result = new ArrayList<>(ids.size()); 90 for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { 91 result.add(preprocessor.get(iter).subList(k)); 92 } 93 return result; 94 } 95 List<KNNList> result = new ArrayList<>(ids.size()); 96 for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) { 97 result.add(preprocessor.get(iter)); 98 } 99 return result; 100 } 101 102 @Override getKNNForObject(O obj, int k)103 public KNNList getKNNForObject(O obj, int k) { 104 throw new AbortException("Preprocessor KNN query only supports ID queries."); 105 } 106 107 /** 108 * Get the preprocessor instance. 109 * 110 * @return preprocessor instance 111 */ getPreprocessor()112 public AbstractMaterializeKNNPreprocessor<O> getPreprocessor() { 113 return preprocessor; 114 } 115 116 /** 117 * Get the class logger. Override when subclassing! 118 * 119 * @return Class logger. 120 */ getLogger()121 protected Logging getLogger() { 122 return LOG; 123 } 124 } 125