xapian-core  2.0.0
protomset.h
Go to the documentation of this file.
1 
4 /* Copyright (C) 2004-2026 Olly Betts
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see
18  * <https://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef XAPIAN_INCLUDED_PROTOMSET_H
22 #define XAPIAN_INCLUDED_PROTOMSET_H
23 
24 #include "api/enquireinternal.h"
25 #include "api/result.h"
26 #include "api/smallvector.h"
27 #include "collapser.h"
28 #include "heap.h"
29 #include "matchtimeout.h"
30 #include "msetcmp.h"
31 #include "omassert.h"
32 #include "spymaster.h"
33 
34 #include <algorithm>
35 
37 
38 class ProtoMSet {
40  class MCmpAdaptor {
42 
43  public:
44  explicit MCmpAdaptor(ProtoMSet* protomset_) : protomset(protomset_) {}
45 
47  return protomset->mcmp(protomset->results[a],
48  protomset->results[b]);
49  }
50  };
51 
52  friend class MCmpAdaptor;
53 
59 
61 
63 
65 
77  double min_weight = 0.0;
78 
84  double max_weight = 0.0;
85 
86  bool min_weight_pending = false;
87 
93 
95  std::vector<Result> results;
96 
101  std::vector<Xapian::doccount> min_heap;
102 
105 
112 
115 
117 
119 
120  double percent_scale = 0.0;
121 
123 
125 
126  double max_possible;
127 
129 
131 
132  Xapian::doccount size() const { return Xapian::doccount(results.size()); }
133 
134  public:
136  Xapian::doccount max_items,
137  Xapian::doccount check_at_least_,
138  MSetCmp mcmp_,
140  Xapian::termcount total_subqs_,
141  PostListTree& pltree_,
142  Xapian::valueno collapse_key,
143  Xapian::doccount collapse_max,
144  int percent_threshold_,
145  double percent_threshold_factor_,
146  double max_possible_,
147  bool stop_once_full_,
148  double time_limit)
149  : max_size(first_ + max_items),
150  check_at_least(check_at_least_),
151  sort_by(sort_by_),
152  mcmp(mcmp_),
153  first(first_),
154  total_subqs(total_subqs_),
155  percent_threshold(percent_threshold_),
156  percent_threshold_factor(percent_threshold_factor_),
157  pltree(pltree_),
158  collapser(collapse_key, collapse_max, results, mcmp),
159  max_possible(max_possible_),
160  stop_once_full(stop_once_full_),
161  timeout(time_limit)
162  {
163  results.reserve(max_size);
164  }
165 
166  ProtoMSet(const ProtoMSet&) = delete;
167 
168  ProtoMSet& operator=(const ProtoMSet&) = delete;
169 
171 
172  bool full() const { return size() == max_size; }
173 
174  double get_min_weight() const { return min_weight; }
175 
176  void update_max_weight(double weight) {
177  if (weight <= max_weight)
178  return;
179 
180  max_weight = weight;
182  if (percent_threshold) {
184  }
185  }
186 
187  bool checked_enough() {
189  return true;
190  }
193  return true;
194  }
195  return false;
196  }
197 
202  bool handle_min_weight_pending(bool finalising = false) {
203  // min_weight_pending shouldn't get set when unweighted.
205  min_weight_pending = false;
206  bool weight_first = (sort_by == Xapian::Enquire::Internal::REL ||
208  double new_min_weight = HUGE_VAL;
209  Xapian::doccount j = 0;
210  Xapian::doccount min_elt = 0;
211  for (Xapian::doccount i = 0; i != size(); ++i) {
212  if (results[i].get_weight() < min_weight) {
213  continue;
214  }
215  if (i != j) {
216  results[j] = std::move(results[i]);
217  if (collapser) {
219  }
220  }
221  if (weight_first && results[j].get_weight() < new_min_weight) {
222  new_min_weight = results[j].get_weight();
223  min_elt = j;
224  }
225  ++j;
226  }
227  if (weight_first) {
228  if (finalising) {
230  min_weight = new_min_weight;
231  } else {
232  if (checked_enough())
233  min_weight = new_min_weight;
234  }
235  }
236  if (j != size()) {
237  results.erase(results.begin() + j, results.end());
238  if (!finalising) {
239  return false;
240  }
241  }
242  if (!finalising && min_elt != 0 && !collapser) {
243  // Install the correct element at the tip of the heap, so
244  // that Heap::make() has less to do. NB Breaks collapsing.
245  std::swap(results[0], results[min_elt]);
246  }
247  return true;
248  }
249 
250  bool early_reject(Result& new_item,
251  bool calculated_weight,
252  SpyMaster& spymaster,
253  const Xapian::Document& doc) {
254  if (min_heap.empty())
255  return false;
256 
257  // We're sorting by value (in part at least), so compare the item
258  // against the lowest currently in the proto-mset. If sort_by is VAL,
259  // then new_item.get_weight() won't be set yet, but that doesn't matter
260  // since it's not used by the sort function.
261  Xapian::doccount worst_idx = min_heap.front();
262  if (mcmp(new_item, results[worst_idx]))
263  return false;
264 
265  // The candidate isn't good enough to make the proto-mset, but there
266  // are still things we may need to do with it.
267  if (!collapser) {
268  // We're not collapsing so we can perform an early reject.
270  double weight =
271  calculated_weight ? new_item.get_weight() : pltree.get_weight();
272  spymaster(doc, weight);
273  update_max_weight(weight);
274  return true;
275  }
276 
277  // We're collapsing - the question is should we increment
278  // known_matching_docs?
279 
280  if (checked_enough()) {
281  // We are collapsing but known_matching_docs has already reached
282  // check_at_least so we don't need to worry about whether we can
283  // increment it further.
284  double weight =
285  calculated_weight ? new_item.get_weight() : pltree.get_weight();
286  update_max_weight(weight);
287  return true;
288  }
289 
290  // We can't early reject but need to continue on and check if this item
291  // would be collapsed or not (and if not ProtoMSet::add() will get
292  // called and known_matching_docs incremented there.
293  return false;
294  }
295 
301  bool process(Result&& new_item,
302  ValueStreamDocument& vsdoc) {
303  update_max_weight(new_item.get_weight());
304 
305  if (!collapser) {
306  // No collapsing, so just add the item.
307  add(std::move(new_item));
308  } else {
309  auto res = collapser.check(new_item, vsdoc);
310  switch (res) {
311  case REJECT:
312  return true;
313 
314  case REPLACE:
315  // There was a previous item in the collapse tab so the
316  // MSet can't be empty.
317  Assert(!results.empty());
318 
319  // This is one of the best collapse_max potential MSet
320  // entries with this key which we've seen so far. The
321  // entry with this key which it displaced is still in the
322  // proto-MSet so replace it.
323  replace(collapser.old_item, std::move(new_item));
324  return true;
325 
326  default:
327  break;
328  }
329 
330  auto elt = add(std::move(new_item));
331  if (res != EMPTY && elt != Xapian::doccount(-1)) {
332  collapser.process(res, elt);
333  }
334  }
335 
336  if (stop_once_full) {
337  if (full() && checked_enough()) {
338  return false;
339  }
340  }
341 
342  return true;
343  }
344 
345  // Returns the new item's index, or Xapian::doccount(-1) if not added.
348 
349  if (item.get_weight() < min_weight) {
350  return Xapian::doccount(-1);
351  }
352 
353  if (item.get_weight() > max_weight) {
354  update_max_weight(item.get_weight());
355  }
356 
357  if (!full()) {
358  // We're still filling, or just about to become full.
359  results.push_back(std::move(item));
360  Assert(min_heap.empty());
361  return size() - 1;
362  }
363 
364  if (min_heap.empty()) {
365  // This breaks if we're collapsing because it moves elements around
366  // but can be used if we aren't (and could be for elements with
367  // no collapse key too - FIXME).
368  if (min_weight_pending) {
369  if (!handle_min_weight_pending()) {
370  results.push_back(std::move(item));
371  return size() - 1;
372  }
373  }
374 
375  if (size() == 0) {
376  // E.g. get_mset(0, 0, 10);
377  return Xapian::doccount(-1);
378  }
379  min_heap.reserve(size());
380  for (Xapian::doccount i = 0; i != size(); ++i)
381  min_heap.push_back(i);
382  Heap::make(min_heap.begin(), min_heap.end(), MCmpAdaptor(this));
385  if (checked_enough()) {
386  min_weight = results[min_heap.front()].get_weight();
387  }
388  }
389  }
390 
391  Xapian::doccount worst_idx = min_heap.front();
392  if (!mcmp(item, results[worst_idx])) {
393  // The new item is less than what we already had.
394  return Xapian::doccount(-1);
395  }
396 
397  results[worst_idx] = std::move(item);
398  Heap::replace(min_heap.begin(), min_heap.end(), MCmpAdaptor(this));
401  if (checked_enough()) {
402  min_weight = results[min_heap.front()].get_weight();
403  }
404  }
405  return worst_idx;
406  }
407 
408  void replace(Xapian::doccount old_item, Result&& b) {
409  results[old_item] = std::move(b);
410  if (min_heap.empty())
411  return;
412 
413  // We need to find the entry in min_heap corresponding to old_item.
414  // The simplest way is just to linear-scan for it, and that's actually
415  // fairly efficient as we're just searching for an integer in a
416  // vector of integers. The heap structure means that the lowest ranked
417  // entry is first and lower ranked entries will tend to be nearer the
418  // start, so intuitively scanning forwards for an entry which we're
419  // removing because we found a higher ranking one seems sensible, but
420  // I've not actually profiled this.
421  auto it = std::find(min_heap.begin(), min_heap.end(), old_item);
422  if (rare(it == min_heap.end())) {
423  // min_heap should contain all indices of results.
424  Assert(false);
425  return;
426  }
427 
428  // siftdown() here is correct (because it's on a min-heap).
429  Heap::siftdown(min_heap.begin(), min_heap.end(), it, MCmpAdaptor(this));
430  }
431 
432  void set_new_min_weight(double min_wt) {
433  if (min_wt <= min_weight)
434  return;
435 
436  min_weight = min_wt;
437 
438  if (results.empty()) {
439  // This method gets called before we start matching to set the
440  // fixed weight_threshold threshold.
441  return;
442  }
443 
444 #if 0
445  // FIXME: Is this possible? set_new_min_weight() from a percentage
446  // threshold can't do this...
447  if (min_wt > max_weight) {
448  // The new threshold invalidates all current entries.
449  results.resize(0);
450  min_heap.resize(0);
451  return;
452  }
453 #endif
454 
455  if (!min_heap.empty()) {
456  // If sorting primarily by weight, we could pop the heap while the
457  // tip's weight is < min_wt, but each pop needs 2*log(n)
458  // comparisons, and then pushing replacements for each of those
459  // items needs log(n) comparisons.
460  //
461  // Instead we just discard the heap - if we need to rebuild it,
462  // that'll require 3*n comparisons. The break even is about 3
463  // discarded items for n=10 or about 5 for n=100, but we may never
464  // need to rebuild the heap.
465  min_heap.clear();
466  }
467 
468  // Note that we need to check items against min_weight at some point.
469  min_weight_pending = true;
470  }
471 
473  if (results.empty() || max_weight == 0.0)
474  return;
475 
478  Assert(percent_scale > 0);
479  if (!percent_threshold) {
480  return;
481  }
482 
483  // Truncate the results if necessary.
485  if (min_weight_pending) {
487  }
488  }
489 
492  const std::vector<std::unique_ptr<LocalSubMatch>>& locals,
493  const Xapian::VecUniquePtr<EstimateOp>& estimates) {
495 
496  Xapian::doccount matches_lower_bound;
497  Xapian::doccount matches_estimated;
498  Xapian::doccount matches_upper_bound;
499  Xapian::doccount uncollapsed_lower_bound;
500  Xapian::doccount uncollapsed_estimated;
501  Xapian::doccount uncollapsed_upper_bound;
502 
503  if (!collapser && (!full() || known_matching_docs < check_at_least)) {
504  // Under these conditions we know exactly how many matching docs
505  // there are for the full match so we don't need to resolve the
506  // EstimateOp stack.
508  if (!full()) {
509  // We didn't get all the results requested, so we know that
510  // we've got all there are, and the bounds and estimate are
511  // all equal to that number.
512  m = size();
513  // And that should equal known_matching_docs, unless a percentage
514  // threshold caused some matches to be excluded.
515  if (!percent_threshold) {
517  } else {
519  }
520  } else {
521  // Otherwise we didn't reach check_at_least, so
522  // known_matching_docs gives the exact size.
524  }
525 
526  matches_lower_bound = matches_estimated = matches_upper_bound = m;
527 
528  // When not collapsing the uncollapsed bounds are just the same.
529  uncollapsed_lower_bound = matches_lower_bound;
530  uncollapsed_estimated = matches_estimated;
531  uncollapsed_upper_bound = matches_upper_bound;
532  } else {
533  matches_lower_bound = 0;
534  matches_estimated = 0;
535  matches_upper_bound = 0;
536  for (size_t i = 0; i != estimates.size(); ++i) {
537  if (estimates[i]) {
538  Assert(locals[i].get());
539  Estimates e = locals[i]->resolve(estimates[i]);
540  matches_lower_bound += e.min;
541  matches_estimated += e.est;
542  matches_upper_bound += e.max;
543  }
544  }
545 
546  AssertRel(matches_estimated, >=, matches_lower_bound);
547  AssertRel(matches_estimated, <=, matches_upper_bound);
548 
549  uncollapsed_lower_bound = matches_lower_bound;
550  uncollapsed_estimated = matches_estimated;
551  uncollapsed_upper_bound = matches_upper_bound;
552 
553  if (!full()) {
554  // We didn't get all the results requested, so we know that we've
555  // got all there are, and the bounds and estimate are all equal to
556  // that number.
557  matches_lower_bound = size();
558  matches_estimated = matches_lower_bound;
559  matches_upper_bound = matches_lower_bound;
560 
561  // And that should equal known_matching_docs, unless a percentage
562  // threshold caused some matches to be excluded.
563  if (!percent_threshold) {
564  AssertEq(matches_estimated, known_matching_docs);
565  } else {
566  AssertRel(matches_estimated, <=, known_matching_docs);
567  }
568 
569  if (matches_lower_bound > uncollapsed_lower_bound) {
570  // Clamp the uncollapsed bound to be at least the collapsed
571  // one.
572  uncollapsed_lower_bound = matches_lower_bound;
573  }
574  } else {
575  // We can end up scaling the estimate more than once, so collect
576  // the scale factors and apply them in one go to avoid rounding
577  // more than once.
578  double estimate_scale = 1.0;
579  double unique_rate = 1.0;
580 
581  if (collapser) {
582  matches_lower_bound = collapser.get_matches_lower_bound();
583 
584  Xapian::doccount docs_considered =
587  if (docs_considered > 0) {
588  // Scale the estimate by the rate at which we've been
589  // finding unique documents.
590  double unique = double(docs_considered - dups_ignored);
591  unique_rate = unique / double(docs_considered);
592  }
593 
594  // We can safely reduce the upper bound by the number of
595  // duplicates we've ignored.
596  matches_upper_bound -= dups_ignored;
597  }
598 
599  if (mdecider) {
600  if (!percent_threshold && !collapser) {
601  if (known_matching_docs > matches_lower_bound) {
602  // We're not collapsing or doing a percentage
603  // threshold, so known_matching_docs is a lower bound
604  // on the total number of matches.
605  matches_lower_bound = known_matching_docs;
606  }
607  }
608  }
609 
610  if (percent_threshold) {
611  // Scale the estimate assuming that document weights are evenly
612  // distributed from 0 to the maximum weight seen.
613  estimate_scale *= (1.0 - percent_threshold_factor);
614 
615  // This is all we can be sure of without additional work.
616  matches_lower_bound = size();
617 
618  if (collapser) {
619  uncollapsed_lower_bound = matches_lower_bound;
620  }
621  }
622 
623  if (collapser && estimate_scale != 1.0) {
624  uncollapsed_estimated =
625  Xapian::doccount(uncollapsed_estimated * estimate_scale +
626  0.5);
627  }
628 
629  estimate_scale *= unique_rate;
630 
631  if (estimate_scale != 1.0) {
632  matches_estimated =
633  Xapian::doccount(matches_estimated * estimate_scale + 0.5);
634  if (matches_estimated < matches_lower_bound)
635  matches_estimated = matches_lower_bound;
636  }
637 
638  if (collapser || mdecider) {
639  // Clamp the estimate to the range given by the bounds.
640  AssertRel(matches_lower_bound, <=, matches_upper_bound);
641  matches_estimated = std::clamp(matches_estimated,
642  matches_lower_bound,
643  matches_upper_bound);
644  } else if (!percent_threshold) {
645  AssertRel(known_matching_docs, <=, matches_upper_bound);
646  if (known_matching_docs > matches_lower_bound)
647  matches_lower_bound = known_matching_docs;
648  if (known_matching_docs > matches_estimated)
649  matches_estimated = known_matching_docs;
650  }
651 
652  if (collapser) {
653  if (!mdecider && !percent_threshold) {
654  AssertRel(known_matching_docs, <=, uncollapsed_upper_bound);
655  if (known_matching_docs > uncollapsed_lower_bound)
656  uncollapsed_lower_bound = known_matching_docs;
657  }
658 
659  if (matches_lower_bound > uncollapsed_lower_bound) {
660  // Clamp the uncollapsed bound to be at least the collapsed
661  // one.
662  uncollapsed_lower_bound = matches_lower_bound;
663  }
664 
665  // Clamp the estimate to lie within the known bounds.
666  if (uncollapsed_estimated < uncollapsed_lower_bound) {
667  uncollapsed_estimated = uncollapsed_lower_bound;
668  } else if (uncollapsed_estimated > uncollapsed_upper_bound) {
669  uncollapsed_estimated = uncollapsed_upper_bound;
670  }
671  } else {
672  // When not collapsing the uncollapsed bounds are just the same.
673  uncollapsed_lower_bound = matches_lower_bound;
674  uncollapsed_estimated = matches_estimated;
675  uncollapsed_upper_bound = matches_upper_bound;
676  }
677  }
678  }
679 
680  // FIXME: Profile using min_heap here (when it's been created) to
681  // handle "first" and perform the sort.
682  if (first != 0) {
683  if (first > size()) {
684  results.clear();
685  } else {
686  // We perform nth_element() on reverse iterators so that the
687  // unwanted elements end up at the end of items, which means
688  // that the call to erase() to remove them doesn't have to copy
689  // any elements.
690  auto nth = results.rbegin() + first;
691  std::nth_element(results.rbegin(), nth, results.rend(), mcmp);
692  // Discard the unwanted elements.
693  results.erase(results.end() - first, results.end());
694  }
695  }
696 
697  std::sort(results.begin(), results.end(), mcmp);
698 
700 
701  // The estimates should lie between the bounds.
702  AssertRel(matches_lower_bound, <=, matches_estimated);
703  AssertRel(matches_estimated, <=, matches_upper_bound);
704  AssertRel(uncollapsed_lower_bound, <=, uncollapsed_estimated);
705  AssertRel(uncollapsed_estimated, <=, uncollapsed_upper_bound);
706 
707  // Collapsing should only reduce the bounds and estimate.
708  AssertRel(matches_lower_bound, <=, uncollapsed_lower_bound);
709  AssertRel(matches_estimated, <=, uncollapsed_estimated);
710  AssertRel(matches_upper_bound, <=, uncollapsed_upper_bound);
711 
713  matches_upper_bound,
714  matches_lower_bound,
715  matches_estimated,
716  uncollapsed_upper_bound,
717  uncollapsed_lower_bound,
718  uncollapsed_estimated,
719  max_possible,
720  max_weight,
721  std::move(results),
722  percent_scale * 100.0));
723  }
724 };
725 
726 #endif // XAPIAN_INCLUDED_PROTOMSET_H
The Collapser class tracks collapse keys and the documents they match.
Definition: collapser.h:135
Xapian::doccount get_docs_considered() const
Definition: collapser.h:243
collapse_result check(Result &result, Xapian::Document::Internal &vsdoc)
Check a new result.
Definition: collapser.cc:126
void finalise(double min_weight, int percent_threshold)
Definition: collapser.cc:237
Xapian::doccount old_item
Replaced item when REPLACE is returned by collapse().
Definition: collapser.h:182
Xapian::doccount get_dups_ignored() const
Definition: collapser.h:245
void process(collapse_result action, Xapian::doccount item)
Handle a new Result.
Definition: collapser.cc:164
Xapian::doccount get_matches_lower_bound() const
Definition: collapser.cc:212
void result_has_moved(Xapian::doccount from, Xapian::doccount to)
Process relocation of entry in results.
Definition: collapser.h:223
Xapian::termcount count_matching_subqs() const
Definition: postlisttree.h:202
double get_weight() const
Definition: postlisttree.h:137
Adapt MSetCmp to be usable with min_heap.
Definition: protomset.h:40
bool operator()(Xapian::doccount a, Xapian::doccount b) const
Definition: protomset.h:46
MCmpAdaptor(ProtoMSet *protomset_)
Definition: protomset.h:44
ProtoMSet * protomset
Definition: protomset.h:41
double max_weight
The highest document weight seen.
Definition: protomset.h:84
Collapser & get_collapser()
Definition: protomset.h:170
std::vector< Result > results
The items in the proto-MSet.
Definition: protomset.h:95
bool process(Result &&new_item, ValueStreamDocument &vsdoc)
Process new_item.
Definition: protomset.h:301
double percent_threshold_factor
Definition: protomset.h:118
void replace(Xapian::doccount old_item, Result &&b)
Definition: protomset.h:408
Xapian::doccount add(Result &&item)
Definition: protomset.h:346
ProtoMSet & operator=(const ProtoMSet &)=delete
Xapian::doccount first
First entry wanted in MSet.
Definition: protomset.h:104
double min_weight
Minimum threshold on the weight.
Definition: protomset.h:77
double max_possible
Definition: protomset.h:126
Xapian::termcount total_subqs
How many weighted leaf subqueries there are.
Definition: protomset.h:111
ProtoMSet(const ProtoMSet &)=delete
TimeOut timeout
Definition: protomset.h:130
bool stop_once_full
Definition: protomset.h:128
std::vector< Xapian::doccount > min_heap
A heap of offsets into results.
Definition: protomset.h:101
MSetCmp mcmp
Definition: protomset.h:64
bool early_reject(Result &new_item, bool calculated_weight, SpyMaster &spymaster, const Xapian::Document &doc)
Definition: protomset.h:250
Collapser collapser
Definition: protomset.h:124
void set_new_min_weight(double min_wt)
Definition: protomset.h:432
Xapian::termcount max_weight_subqs_matched
The number of subqueries which matched to give max_weight.
Definition: protomset.h:114
Xapian::doccount check_at_least
Definition: protomset.h:60
PostListTree & pltree
Definition: protomset.h:122
Xapian::Enquire::Internal::sort_setting sort_by
Definition: protomset.h:62
bool min_weight_pending
Definition: protomset.h:86
ProtoMSet(Xapian::doccount first_, Xapian::doccount max_items, Xapian::doccount check_at_least_, MSetCmp mcmp_, Xapian::Enquire::Internal::sort_setting sort_by_, Xapian::termcount total_subqs_, PostListTree &pltree_, Xapian::valueno collapse_key, Xapian::doccount collapse_max, int percent_threshold_, double percent_threshold_factor_, double max_possible_, bool stop_once_full_, double time_limit)
Definition: protomset.h:135
bool full() const
Definition: protomset.h:172
Xapian::doccount known_matching_docs
Count of how many known matching documents have been processed so far.
Definition: protomset.h:92
void update_max_weight(double weight)
Definition: protomset.h:176
double percent_scale
Definition: protomset.h:120
bool handle_min_weight_pending(bool finalising=false)
Resolve a pending min_weight change.
Definition: protomset.h:202
double get_min_weight() const
Definition: protomset.h:174
void finalise_percentages()
Definition: protomset.h:472
int percent_threshold
Definition: protomset.h:116
Xapian::doccount size() const
Definition: protomset.h:132
Xapian::MSet finalise(const Xapian::MatchDecider *mdecider, const std::vector< std::unique_ptr< LocalSubMatch >> &locals, const Xapian::VecUniquePtr< EstimateOp > &estimates)
Definition: protomset.h:491
Xapian::doccount max_size
Maximum size the ProtoMSet needs to grow to.
Definition: protomset.h:58
bool checked_enough()
Definition: protomset.h:187
A result in an MSet.
Definition: result.h:30
double get_weight() const
Definition: result.h:70
bool timed_out() const
Definition: matchtimeout.h:115
A document which gets its values from a ValueStreamManager.
Class representing a document.
Definition: document.h:64
A smart pointer that uses intrusive reference counting.
Definition: intrusive_ptr.h:83
Xapian::MSet internals.
Definition: msetinternal.h:44
Class representing a list of search results.
Definition: mset.h:46
Abstract base class for match deciders.
Definition: matchdecider.h:37
Suitable for "simple" type T.
Definition: smallvector.h:62
size_type size() const
Definition: smallvector.h:135
Collapse documents with the same collapse key during the match.
@ EMPTY
Definition: collapser.h:34
@ REPLACE
Definition: collapser.h:38
@ REJECT
Definition: collapser.h:37
#define rare(COND)
Definition: config.h:607
Xapian::Enquire internals.
C++ STL heap implementation with extensions.
Time limits for the matcher.
Result comparison functions.
bool(* MSetCmp)(const Result &, const Result &)
Definition: msetcmp.h:29
void replace(_RandomAccessIterator first, _RandomAccessIterator last, _Compare comp)
Definition: heap.h:230
void siftdown(_RandomAccessIterator first, _RandomAccessIterator last, _RandomAccessIterator elt, _Compare comp)
Definition: heap.h:249
void make(_RandomAccessIterator first, _RandomAccessIterator last, _Compare comp)
Definition: heap.h:259
void sort(_RandomAccessIterator first, _RandomAccessIterator last, _Compare comp)
Definition: heap.h:277
unsigned XAPIAN_TERMCOUNT_BASE_TYPE termcount
A counts of terms.
Definition: types.h:64
unsigned valueno
The number for a value slot in a document.
Definition: types.h:90
unsigned XAPIAN_DOCID_BASE_TYPE doccount
A count of documents.
Definition: types.h:37
Various assertion macros.
#define AssertEq(A, B)
Definition: omassert.h:124
#define AssertRel(A, REL, B)
Definition: omassert.h:123
#define Assert(COND)
Definition: omassert.h:122
A result in an MSet.
Custom vector implementations using small vector optimisation.
Class for managing MatchSpy objects during the match.
Xapian::doccount est
Definition: estimateop.h:33
Xapian::doccount min
Definition: estimateop.h:33
Xapian::doccount max
Definition: estimateop.h:33