Gaia
view_impl.h
1 /*
2  * Copyright (C) 2006-2013 Music Technology Group - Universitat Pompeu Fabra
3  *
4  * This file is part of Gaia
5  *
6  * Gaia is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License as published by the Free
8  * Software Foundation (FSF), either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the Affero GNU General Public License
17  * version 3 along with this program. If not, see http://www.gnu.org/licenses/
18  */
19 
20 #include "view.h"
21 #include "timer.h"
22 #include "queryoptimizer.h"
23 
24 namespace gaia2 {
25 
26 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
27 BaseView<DataSetType, PointType, SearchPointType, DistanceType>::BaseView(DataSetType* dataset) :
28  _dataset(dataset), _isViewValid(false), _searchSpacePool(dataset) {
29 
30  init();
31 }
32 
33 
34 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
35 void BaseView<DataSetType, PointType, SearchPointType, DistanceType>::init() {
36  if (!_dataset) throw GaiaException("You need to specify a valid DataSet when creating a view");
37 
38  _dataset->addView(this);
39  validate();
40 }
41 
42 
43 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
44 BaseView<DataSetType, PointType, SearchPointType, DistanceType>::~BaseView() {
45  if (_dataset) {
46  _dataset->removeView(this);
47  }
48 }
49 
50 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
52  validate(); // need to revalidate view cause we might have changed a ref dataset meanwhile
53  _searchSpacePool.indexOn(descriptorName);
54 }
55 
56 
57 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
59  G_DEBUG(GView, "invalidating view");
60  _isViewValid = false;
61 }
62 
63 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
65  if (_isViewValid) return;
66 
67  G_DEBUG(GView, "validating view");
68 
69  // check if the dataset still exists
70  if (!_dataset) {
71  throw GaiaException("Cannot revalidate view, as the underlying dataset has been deleted");
72  }
73 
74  // make sure our indices and prepared search spaces are still up-to-date
75  _searchSpacePool.recreate();
76  G_DEBUG(GView, "Search space pool updated! View has been revalidated");
77 
78  _isViewValid = true;
79 }
80 
81 
82 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
83 SearchResults BaseView<DataSetType, PointType, SearchPointType, DistanceType>::formatResults(std::priority_queue<SearchPointType>& resQueue) {
84  SearchResults result;
85 
86  while (!resQueue.empty()) {
87  result.append(Result(resQueue.top().ptr->name(),
88  resQueue.top().dist));
89  resQueue.pop();
90  }
91 
92  std::reverse(result.begin(), result.end());
93 
94  return result;
95 }
96 
97 
98 
99 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
100 void BaseView<DataSetType, PointType, SearchPointType, DistanceType>::bindFilter(const Filter* cfilter, const DataSetType* dataset) {
101  Filter* filter = const_cast<Filter*>(cfilter);
102  filter->updateVariables();
103 
104  // if there are unbound variables in the filter, we need to make sure a
105  // reference dataset is available
106  if (filter->needsBinding()) {
107  const DataSet* refDataSet = dataset->referenceDataSet();
108  if (!refDataSet) {
109  throw GaiaException("Cannot use a filter on this query because no reference DataSet has been set.");
110  }
111  filter->bindToLayout(refDataSet->layout());
112  }
113 
114  // this should be done anyway, because we don't need a specific layout
115  filter->bindToPointAttributes();
116 }
117 
118 
119 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
121 
122  QString filterStr = filterString;
123  if (filterString == "") filterStr = "where true";
124 
125  Filter* filter = Filter::parse(filterStr);
126 
127  return filter;
128 }
129 
130 
131 
132 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
134  const DistanceType* dist,
135  const Filter* filter) {
136  Timer timer;
137  timer.start();
138  bool owns = (filter == 0); // if filter == 0, then we'll have to create it, so we own it
139  ResultSetType result = nnSearch(p, getSearchSpace(0, filter, owns), dist);
140  timer.stop();
141  G_DEBUG(GPerf, "Total time for the full query (optimization + query): " << timer.elapsed() * 1000 << " ms");
142  return result;
143 }
144 
145 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
147  const DistanceType* dist,
148  const QString& filter) {
149  Timer timer;
150  timer.start();
151  ResultSetType result = nnSearch(p, getSearchSpace(0, filter), dist);
152  timer.stop();
153  G_DEBUG(GPerf, "Total time for the full query (optimization + query): " << timer.elapsed() * 1000 << " ms");
154  return result;
155 }
156 
157 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
159  ResultSetType inputSpace,
160  const DistanceType* dist,
161  const Filter* filter) {
162  Timer timer;
163  timer.start();
164  bool owns = (filter == 0); // if filter == 0, then we'll have to create it, so we own it
165  ResultSetType result = nnSearch(p, getSearchSpace(inputSpace.searchSpace(), filter, owns), dist);
166  timer.stop();
167  G_DEBUG(GPerf, "Total time for the full query (optimization + query): " << timer.elapsed() * 1000 << " ms");
168  return result;
169 }
170 
171 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
173  ResultSetType inputSpace,
174  const DistanceType* dist,
175  const QString& filter) {
176  Timer timer;
177  timer.start();
178  ResultSetType result = nnSearch(p, getSearchSpace(inputSpace.searchSpace(), filter), dist);
179  timer.stop();
180  G_DEBUG(GPerf, "Total time for the full query (optimization + query): " << timer.elapsed() * 1000 << " ms");
181  return result;
182 }
183 
184 
185 
186 
187 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
189  const QString& filterString) {
190  return getSearchSpace(sspace, createFilter(filterString), true);
191 }
192 
193 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
195  const Filter* filter,
196  bool spaceOwnsFilter) {
197 
198  // need to (re)validate the view now, because otherwise we might get stale
199  // search spaces...
200  validate();
201 
202  // if no filter has been specified, get a default one
203  if (!filter) {
204  filter = Filter::parse("where true");
205  spaceOwnsFilter = true;
206  }
207 
208  // if no search space has been specified, get all points from dataset and
209  // try to optimize that, otherwise just go with the given search space
210  SearchSpaceType* result = 0;
211  if (sspace) {
212  G_DEBUG(GView, "Query on given SearchSpace, skipping optimization part");
214  result->copyPointsFrom(*sspace);
215  result->setFilter(filter, spaceOwnsFilter);
216  }
217  else {
218  // searching in the whole dataset, trying to optimize the query
219  G_DEBUG(GView, "Query on full dataset, getting optimized search space");
220  Timer timer; timer.start();
221 
222  // if filter is not ours, make a copy, as the optimize function takes ownership
223  // over the given filter
224  if (!spaceOwnsFilter) filter = new Filter(*filter);
225 
227  result = qo.optimize(const_cast<Filter*>(filter));
228  G_DEBUG(GPerf, "Time to do full optimization: " << timer.elapsed() * 1000 << " ms");
229  }
230 
231  return result;
232 }
233 
234 
235 template <typename DataSetType, typename PointType, typename SearchPointType, typename DistanceType>
237  SearchSpaceType* sspace,
238  const DistanceType* dist) {
239 
240  Timer fullTime, timer;
241  fullTime.start();
242 
243  // 1- First make sure everything is in order, our layouts are good, etc...
244 
245  // make sure our filter variables are correctly bound
246  bindFilter(sspace->filter(), _dataset);
247 
248  // make sure we have specified a DistanceFunction
249  if (!dist) {
250  throw GaiaException("View: you are trying to compute the nearest-neighbors of a point, "
251  "but you haven't specified any distance to use... Please do so.");
252  }
253 
254  // revalidate the view, ie: make sure the underlying dataset is still valid
255  timer.restart();
256  validate();
257  G_DEBUG(GPerf, "Time to (re)validate view: " << timer.elapsed() << " ms");
258 
259  // check that all layouts are matching
260  timer.restart();
261  checkPoint(p);
262  checkDistance(dist);
263 
264  G_DEBUG(GPerf, "Time to compare layouts (dataset/query point/distance): "
265  << timer.elapsed() << " ms");
266 
267 
268  // 2- do the actual computation
269 
270  timer.restart();
271  sspace->computeDistance(p, dist);
272  G_DEBUG(GPerf, "Time to compute distances: " << timer.elapsed() * 1000 << " ms");
273 
274  timer.restart();
275  sspace->filterAndSort();
276  G_DEBUG(GPerf, "Time to filter and sort distances: " << timer.elapsed() * 1000 << " ms");
277 
278 
279  G_DEBUG(GPerf, "Time to answer query: " << fullTime.elapsed() * 1000.0 << " ms");
280  return ResultSetType(sspace);
281 }
282 
283 } // namespace gaia2
void filterAndSort(int n=1000)
Filters the points in this SearchSpace using the given Filter and sort them by increasing distance...
Definition: searchspace.h:202
bool needsBinding() const
Returns whether this filter needs to be bound to a specific layout.
Definition: filter.cpp:129
double elapsed() const
Returns the cumulative number of seconds elapsed between each call to the start()/stop() pair...
Definition: timer.cpp:51
void computeDistance(const PointType &query, const DistanceType *dist)
Compute the distance from the given query point to all those contained in this SearchSpace, and presort a few points to have near instant access to them.
static Filter * parse(const QString &str)
Parses a given string and returns the newly created Filter object.
Definition: filter.cpp:181
void restart()
Restarts the timer.
Definition: timer.h:62
This class represents a dataset and all related information.
Definition: dataset.h:91
const PointLayout & layout() const
Return the layout of this dataset.
Definition: dataset.h:136
void copyPointsFrom(const BaseSearchSpace< SearchPointType, DataSetType > &other)
Copy all the points from the other SearchSpace into this one.
Definition: searchspace.h:38
The QueryOptimizer class tries to optimize a query by reducing the SearchSpace on which it is suppose...
Definition: parsertypes.h:30
The Filter class allows to check whether a predicate is true for a given Point.
Definition: filter.h:73
void start()
Starts the timer.
Definition: timer.cpp:32
Main Gaia namespace, which contains all the library functions.
Definition: addfield.cpp:22
SearchSpaceType * optimize(Filter *filter)
Ownership of the SearchSpace is yielded to the caller of the function.
Definition: queryoptimizer_impl.h:255
void init()
Init function that makes sure that all the factories have correctly registered all the types they can...
Definition: gaia.cpp:53
SearchSpaceType * getSearchSpace(SearchSpaceType *sspace=0, const Filter *filter=0, bool spaceOwnsFilter=true)
Returns a valid SearchSpace with associated filter.
Definition: view_impl.h:194
void indexOn(const QString &descriptorName)
This methods creates an index on the given descriptor name, in the hope that future queries using thi...
Definition: view_impl.h:51
The View class contains a specific view on a dataset.
Definition: dataset.h:37
void invalidate()
This function is called whenever the DataSet it points to changes, so it knows it needs to recompute ...
Definition: view_impl.h:58
A SearchSpace is a structure dedicated to the task of storing pointers to Point with an associated di...
Definition: searchspace.h:91
This class serves as a ref-counted wrapper for a SearchSpace, which is much more convenient to deal w...
Definition: searchspace.h:306
void stop()
Stops the timer.
Definition: timer.cpp:42
This class allows you to measure a certain amount of time, for instance if you want to know how long ...
Definition: timer.h:38
Exception class that can take up to 3 arguments of any type, which will be serialized into a QString ...
Definition: gaiaexception.h:46
The SearchSpacePool accomplishes 2 main functions:
Definition: searchspacepool.h:41
void validate()
This function is called to make sure that the View is valid (ie: its sorting structure and filters ac...
Definition: view_impl.h:64
const DataSet * referenceDataSet() const
Return the reference dataset.
Definition: dataset.cpp:295