Revert "Fix integer type used by ESet"
[xapian.git] / xapian-core / api / omenquire.cc
blobc57b82622d55acd351a04c258c91660e6b0373bc
1 /* omenquire.cc: External interface for running queries
3 * Copyright 1999,2000,2001 BrightStation PLC
4 * Copyright 2001,2002 Ananova Ltd
5 * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2013,2014,2015,2016,2017 Olly Betts
6 * Copyright 2007,2009 Lemur Consulting Ltd
7 * Copyright 2011, Action Without Borders
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 * USA
25 #include <config.h>
26 #include "xapian/enquire.h"
28 #include "xapian/document.h"
29 #include "xapian/error.h"
30 #include "xapian/expanddecider.h"
31 #include "xapian/matchspy.h"
32 #include "xapian/termiterator.h"
33 #include "xapian/weight.h"
35 #include "vectortermlist.h"
37 #include "backends/database.h"
38 #include "debuglog.h"
39 #include "expand/esetinternal.h"
40 #include "expand/expandweight.h"
41 #include "exp10.h"
42 #include "matcher/msetcmp.h"
43 #include "matcher/multimatch.h"
44 #include "omassert.h"
45 #include "api/omenquireinternal.h"
46 #include "roundestimate.h"
47 #include "str.h"
48 #include "weight/weightinternal.h"
50 #include <algorithm>
51 #include "autoptr.h"
52 #include <cfloat>
53 #include <cmath>
54 #include <vector>
56 using namespace std;
58 using Xapian::Internal::ExpandWeight;
59 using Xapian::Internal::Bo1EWeight;
60 using Xapian::Internal::TradEWeight;
62 namespace Xapian {
64 MatchDecider::~MatchDecider() { }
66 // Methods for Xapian::RSet
68 RSet::RSet() : internal(new RSet::Internal)
72 RSet::RSet(const RSet &other) : internal(other.internal)
76 void
77 RSet::operator=(const RSet &other)
79 internal = other.internal;
82 RSet::RSet(RSet &&) = default;
84 RSet&
85 RSet::operator=(RSet &&) = default;
87 RSet::~RSet()
91 Xapian::doccount
92 RSet::size() const
94 return internal->items.size();
97 bool
98 RSet::empty() const
100 return internal->items.empty();
103 void
104 RSet::add_document(Xapian::docid did)
106 if (did == 0) throw Xapian::InvalidArgumentError("Docid 0 not valid");
107 internal->items.insert(did);
110 void
111 RSet::remove_document(Xapian::docid did)
113 internal->items.erase(did);
116 bool
117 RSet::contains(Xapian::docid did) const
119 return internal->items.find(did) != internal->items.end();
122 string
123 RSet::get_description() const
125 return "RSet(" + internal->get_description() + ")";
128 string
129 RSet::Internal::get_description() const
131 string description("RSet::Internal(");
133 set<Xapian::docid>::const_iterator i;
134 for (i = items.begin(); i != items.end(); ++i) {
135 if (i != items.begin()) description += ", ";
136 description += str(*i);
139 description += ')';
141 return description;
144 namespace Internal {
146 // Methods for Xapian::MSetItem
148 string
149 MSetItem::get_description() const
151 string description;
153 description = str(did) + ", " + str(wt) + ", " +
154 collapse_key;
156 description = "Xapian::MSetItem(" + description + ")";
158 return description;
163 // Methods for Xapian::MSet
165 MSet::MSet() : internal(new MSet::Internal)
169 MSet::~MSet()
173 MSet::MSet(const MSet & other) : internal(other.internal)
177 MSet &
178 MSet::operator=(const MSet &other)
180 internal = other.internal;
181 return *this;
184 MSet::MSet(MSet&&) = default;
186 MSet&
187 MSet::operator=(MSet&&) = default;
189 void
190 MSet::fetch_(Xapian::doccount first, Xapian::doccount last) const
192 LOGCALL_VOID(API, "Xapian::MSet::fetch_", first | last);
193 Assert(internal.get() != 0);
194 internal->fetch_items(first, last);
198 MSet::convert_to_percent(double wt) const
200 LOGCALL(API, int, "Xapian::MSet::convert_to_percent", wt);
201 Assert(internal.get() != 0);
202 RETURN(internal->convert_to_percent_internal(wt));
205 Xapian::doccount
206 MSet::get_termfreq(const string &tname) const
208 LOGCALL(API, Xapian::doccount, "Xapian::MSet::get_termfreq", tname);
209 Assert(internal.get() != 0);
210 if (usual(internal->stats)) {
211 Xapian::doccount termfreq;
212 if (internal->stats->get_stats(tname, termfreq))
213 RETURN(termfreq);
215 if (internal->enquire.get() == 0) {
216 throw InvalidOperationError("Can't get termfreq from an MSet which is not derived from a query.");
218 RETURN(internal->enquire->get_termfreq(tname));
221 double
222 MSet::get_termweight(const string &tname) const
224 LOGCALL(API, double, "Xapian::MSet::get_termweight", tname);
225 Assert(internal.get() != 0);
226 if (!internal->stats) {
227 throw InvalidOperationError("Can't get termweight from an MSet which is not derived from a query.");
229 double termweight;
230 if (!internal->stats->get_termweight(tname, termweight)) {
231 string msg = tname;
232 msg += ": termweight not available";
233 throw InvalidArgumentError(msg);
235 RETURN(termweight);
238 Xapian::doccount
239 MSet::get_firstitem() const
241 Assert(internal.get() != 0);
242 return internal->firstitem;
245 Xapian::doccount
246 MSet::get_matches_lower_bound() const
248 Assert(internal.get() != 0);
249 return internal->matches_lower_bound;
252 Xapian::doccount
253 MSet::get_matches_estimated() const
255 Assert(internal.get() != 0);
256 return round_estimate(internal->matches_lower_bound,
257 internal->matches_upper_bound,
258 internal->matches_estimated);
261 Xapian::doccount
262 MSet::get_matches_upper_bound() const
264 Assert(internal.get() != 0);
265 return internal->matches_upper_bound;
268 Xapian::doccount
269 MSet::get_uncollapsed_matches_lower_bound() const
271 Assert(internal.get() != 0);
272 return internal->uncollapsed_lower_bound;
275 Xapian::doccount
276 MSet::get_uncollapsed_matches_estimated() const
278 Assert(internal.get() != 0);
279 return internal->uncollapsed_estimated;
282 Xapian::doccount
283 MSet::get_uncollapsed_matches_upper_bound() const
285 Assert(internal.get() != 0);
286 return internal->uncollapsed_upper_bound;
289 double
290 MSet::get_max_possible() const
292 Assert(internal.get() != 0);
293 return internal->max_possible;
296 double
297 MSet::get_max_attained() const
299 Assert(internal.get() != 0);
300 return internal->max_attained;
303 string
304 MSet::snippet(const string & text,
305 size_t length,
306 const Xapian::Stem & stemmer,
307 unsigned flags,
308 const string & hi_start,
309 const string & hi_end,
310 const string & omit) const
312 Assert(internal.get() != 0);
313 return internal->snippet(text, length, stemmer, flags,
314 hi_start, hi_end, omit);
317 Xapian::doccount
318 MSet::size() const
320 Assert(internal.get() != 0);
321 return internal->items.size();
324 string
325 MSet::get_description() const
327 Assert(internal.get() != 0);
328 return "Xapian::MSet(" + internal->get_description() + ")";
332 MSet::Internal::convert_to_percent_internal(double wt) const
334 LOGCALL(MATCH, int, "Xapian::MSet::Internal::convert_to_percent_internal", wt);
335 if (percent_factor == 0) RETURN(100);
337 // Excess precision on x86 can result in a difference here.
338 double v = wt * percent_factor + 100.0 * DBL_EPSILON;
339 int pcent = static_cast<int>(v);
340 LOGLINE(MATCH, "wt = " << wt << ", max_possible = " << max_possible <<
341 " => pcent = " << pcent);
342 if (pcent > 100) pcent = 100;
343 if (pcent < 0) pcent = 0;
344 if (pcent == 0 && wt > 0) pcent = 1;
346 RETURN(pcent);
349 Document
350 MSet::Internal::get_doc_by_index(Xapian::doccount index) const
352 LOGCALL(MATCH, Document, "Xapian::MSet::Internal::get_doc_by_index", index);
353 index += firstitem;
354 map<Xapian::doccount, Document>::const_iterator doc;
355 doc = indexeddocs.find(index);
356 if (doc != indexeddocs.end()) {
357 RETURN(doc->second);
359 if (index < firstitem || index >= firstitem + items.size()) {
360 throw RangeError("The mset returned from the match does not contain the document at index " + str(index));
362 Assert(enquire.get());
363 if (!requested_docs.empty()) {
364 // There's already a pending request, so handle that.
365 read_docs();
366 // Maybe we just fetched the doc we want.
367 doc = indexeddocs.find(index);
368 if (doc != indexeddocs.end()) {
369 RETURN(doc->second);
373 RETURN(enquire->get_document(items[index - firstitem]));
376 void
377 MSet::Internal::fetch_items(Xapian::doccount first, Xapian::doccount last) const
379 LOGCALL_VOID(MATCH, "Xapian::MSet::Internal::fetch_items", first | last);
380 if (enquire.get() == 0) {
381 throw InvalidOperationError("Can't fetch documents from an MSet which is not derived from a query.");
383 if (items.empty()) return;
384 if (last > items.size() - 1)
385 last = items.size() - 1;
386 for (Xapian::doccount i = first; i <= last; ++i) {
387 map<Xapian::doccount, Document>::const_iterator doc;
388 doc = indexeddocs.find(i);
389 if (doc == indexeddocs.end()) {
390 /* We don't have the document cached */
391 set<Xapian::doccount>::const_iterator s;
392 s = requested_docs.find(i);
393 if (s == requested_docs.end()) {
394 /* We haven't even requested it yet - do so now. */
395 enquire->request_doc(items[i - firstitem]);
396 requested_docs.insert(i);
402 string
403 MSet::Internal::get_description() const
405 string description = "Xapian::MSet::Internal(";
407 description += "firstitem=" + str(firstitem) + ", " +
408 "matches_lower_bound=" + str(matches_lower_bound) + ", " +
409 "matches_estimated=" + str(matches_estimated) + ", " +
410 "matches_upper_bound=" + str(matches_upper_bound) + ", " +
411 "max_possible=" + str(max_possible) + ", " +
412 "max_attained=" + str(max_attained);
414 for (vector<Xapian::Internal::MSetItem>::const_iterator i = items.begin();
415 i != items.end(); ++i) {
416 if (!description.empty()) description += ", ";
417 description += i->get_description();
420 description += ")";
422 return description;
425 void
426 MSet::Internal::read_docs() const
428 set<Xapian::doccount>::const_iterator i;
429 for (i = requested_docs.begin(); i != requested_docs.end(); ++i) {
430 indexeddocs[*i] = enquire->read_doc(items[*i - firstitem]);
431 LOGLINE(MATCH, "stored doc at index " << *i << " is " << indexeddocs[*i]);
433 /* Clear list of requested but not fetched documents. */
434 requested_docs.clear();
437 // MSetIterator
439 Xapian::docid
440 MSetIterator::operator*() const
442 Assert(mset.internal.get());
443 Xapian::doccount size = mset.internal->items.size();
444 Xapian::doccount index = size - off_from_end;
445 AssertRel(index,<,size);
446 return mset.internal->items[index].did;
449 Document
450 MSetIterator::get_document() const
452 Assert(mset.internal.get());
453 Xapian::doccount size = mset.internal->items.size();
454 Xapian::doccount index = size - off_from_end;
455 AssertRel(index,<,size);
456 return mset.internal->get_doc_by_index(index);
459 double
460 MSetIterator::get_weight() const
462 Assert(mset.internal.get());
463 Xapian::doccount size = mset.internal->items.size();
464 Xapian::doccount index = size - off_from_end;
465 AssertRel(index,<,size);
466 return mset.internal->items[index].wt;
469 std::string
470 MSetIterator::get_collapse_key() const
472 Assert(mset.internal.get());
473 Xapian::doccount size = mset.internal->items.size();
474 Xapian::doccount index = size - off_from_end;
475 AssertRel(index,<,size);
476 return mset.internal->items[index].collapse_key;
479 Xapian::doccount
480 MSetIterator::get_collapse_count() const
482 Assert(mset.internal.get());
483 Xapian::doccount size = mset.internal->items.size();
484 Xapian::doccount index = size - off_from_end;
485 AssertRel(index,<,size);
486 return mset.internal->items[index].collapse_count;
489 string
490 MSetIterator::get_sort_key() const
492 Assert(mset.internal.get());
493 Xapian::doccount size = mset.internal->items.size();
494 Xapian::doccount index = size - off_from_end;
495 AssertRel(index,<,size);
496 return mset.internal->items[index].sort_key;
499 string
500 MSetIterator::get_description() const
502 return "Xapian::MSetIterator(" + str(mset.size() - off_from_end) + ")";
505 // Methods for Xapian::Enquire::Internal
507 Enquire::Internal::Internal(const Database &db_)
508 : db(db_), query(), collapse_key(Xapian::BAD_VALUENO), collapse_max(0),
509 order(Enquire::ASCENDING), percent_cutoff(0), weight_cutoff(0),
510 sort_key(Xapian::BAD_VALUENO), sort_by(REL), sort_value_forward(true),
511 sorter(), time_limit(0.0), weight(0),
512 eweightname("trad"), expand_k(1.0)
514 if (db.internal.empty()) {
515 throw InvalidArgumentError("Can't make an Enquire object from an uninitialised Database object.");
519 Enquire::Internal::~Internal()
521 delete weight;
522 weight = 0;
525 void
526 Enquire::Internal::set_query(const Query &query_, termcount qlen_)
528 query = query_;
529 qlen = qlen_ ? qlen_ : query.get_length();
532 const Query &
533 Enquire::Internal::get_query() const
535 return query;
538 MSet
539 Enquire::Internal::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
540 Xapian::doccount check_at_least, const RSet *rset,
541 const MatchDecider *mdecider) const
543 LOGCALL(MATCH, MSet, "Enquire::Internal::get_mset", first | maxitems | check_at_least | rset | mdecider);
545 if (percent_cutoff && (sort_by == VAL || sort_by == VAL_REL)) {
546 throw Xapian::UnimplementedError("Use of a percentage cutoff while sorting primary by value isn't currently supported");
549 if (weight == 0) {
550 weight = new BM25Weight;
553 Xapian::doccount first_orig = first;
555 Xapian::doccount docs = db.get_doccount();
556 first = min(first, docs);
557 maxitems = min(maxitems, docs - first);
558 check_at_least = min(check_at_least, docs);
559 check_at_least = max(check_at_least, first + maxitems);
562 AutoPtr<Xapian::Weight::Internal> stats(new Xapian::Weight::Internal);
563 ::MultiMatch match(db, query, qlen, rset,
564 collapse_max, collapse_key,
565 percent_cutoff, weight_cutoff,
566 order, sort_key, sort_by, sort_value_forward,
567 time_limit, *(stats.get()), weight, spies,
568 (sorter.get() != NULL),
569 (mdecider != NULL));
570 // Run query and put results into supplied Xapian::MSet object.
571 MSet retval;
572 match.get_mset(first, maxitems, check_at_least, retval,
573 *(stats.get()), mdecider, sorter.get());
574 if (first_orig != first && retval.internal.get()) {
575 retval.internal->firstitem = first_orig;
578 Assert(weight->name() != "bool" || retval.get_max_possible() == 0);
580 // The Xapian::MSet needs to have a pointer to ourselves, so that it can
581 // retrieve the documents. This is set here explicitly to avoid having
582 // to pass it into the matcher, which gets messy particularly in the
583 // networked case.
584 retval.internal->enquire = this;
586 if (!retval.internal->stats) {
587 retval.internal->stats = stats.release();
590 RETURN(retval);
593 ESet
594 Enquire::Internal::get_eset(Xapian::termcount maxitems,
595 const RSet & rset, int flags,
596 const ExpandDecider * edecider_,
597 double min_wt) const
599 LOGCALL(MATCH, ESet, "Enquire::Internal::get_eset", maxitems | rset | flags | edecider_ | min_wt);
601 using Xapian::Internal::opt_intrusive_ptr;
602 opt_intrusive_ptr<const ExpandDecider> edecider(edecider_);
603 if (maxitems == 0 || rset.empty()) {
604 // Either we were asked for no results, or wouldn't produce any
605 // because no documents were marked as relevant.
606 RETURN(ESet());
609 LOGVALUE(MATCH, rset.size());
611 if (!query.empty() && !(flags & Enquire::INCLUDE_QUERY_TERMS)) {
612 opt_intrusive_ptr<const ExpandDecider> decider_noquery(
613 (new ExpandDeciderFilterTerms(query.get_terms_begin(),
614 query.get_terms_end()))->release());
615 if (edecider.get()) {
616 edecider = (new ExpandDeciderAnd(decider_noquery.get(),
617 edecider.get()))->release();
618 } else {
619 edecider = decider_noquery;
623 bool use_exact_termfreq(flags & Enquire::USE_EXACT_TERMFREQ);
624 Xapian::ESet eset;
625 eset.internal = new Xapian::ESet::Internal;
627 if (eweightname == "bo1") {
628 Bo1EWeight bo1eweight(db, rset.size(), use_exact_termfreq);
629 eset.internal->expand(maxitems, db, rset, edecider.get(), bo1eweight,
630 min_wt);
631 } else {
632 TradEWeight tradeweight(db, rset.size(), use_exact_termfreq, expand_k);
633 eset.internal->expand(maxitems, db, rset, edecider.get(), tradeweight,
634 min_wt);
637 RETURN(eset);
640 class ByQueryIndexCmp {
641 private:
642 typedef map<string, unsigned int> tmap_t;
643 const tmap_t &tmap;
645 public:
646 explicit ByQueryIndexCmp(const tmap_t &tmap_) : tmap(tmap_) {}
647 bool operator()(const string &left,
648 const string &right) const {
649 tmap_t::const_iterator l, r;
650 l = tmap.find(left);
651 r = tmap.find(right);
652 Assert((l != tmap.end()) && (r != tmap.end()));
654 return l->second < r->second;
658 TermIterator
659 Enquire::Internal::get_matching_terms(Xapian::docid did) const
661 if (query.empty())
662 return TermIterator();
664 // The ordered list of terms in the query.
665 TermIterator qt = query.get_terms_begin();
667 // copy the list of query terms into a map for faster access.
668 // FIXME: a hash would be faster than a map, if this becomes
669 // a problem.
670 map<string, unsigned int> tmap;
671 unsigned int index = 1;
672 for ( ; qt != query.get_terms_end(); ++qt) {
673 if (tmap.find(*qt) == tmap.end())
674 tmap[*qt] = index++;
677 vector<string> matching_terms;
679 TermIterator docterms = db.termlist_begin(did);
680 TermIterator docterms_end = db.termlist_end(did);
681 while (docterms != docterms_end) {
682 string term = *docterms;
683 map<string, unsigned int>::iterator t = tmap.find(term);
684 if (t != tmap.end()) matching_terms.push_back(term);
685 ++docterms;
688 // sort the resulting list by query position.
689 sort(matching_terms.begin(), matching_terms.end(), ByQueryIndexCmp(tmap));
691 return TermIterator(new VectorTermList(matching_terms.begin(),
692 matching_terms.end()));
695 TermIterator
696 Enquire::Internal::get_matching_terms(const MSetIterator &it) const
698 // FIXME: take advantage of MSetIterator to ensure that database
699 // doesn't get modified underneath us.
700 return get_matching_terms(*it);
703 Xapian::doccount
704 Enquire::Internal::get_termfreq(const string &tname) const
706 return db.get_termfreq(tname);
709 string
710 Enquire::Internal::get_description() const
712 string description = db.get_description();
713 description += ", ";
714 description += query.get_description();
715 return description;
718 // Private methods for Xapian::Enquire::Internal
720 void
721 Enquire::Internal::request_doc(const Xapian::Internal::MSetItem &item) const
723 unsigned int multiplier = db.internal.size();
725 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
726 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
728 db.internal[dbnumber]->request_document(realdid);
731 Document
732 Enquire::Internal::read_doc(const Xapian::Internal::MSetItem &item) const
734 unsigned int multiplier = db.internal.size();
736 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
737 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
739 Xapian::Document::Internal *doc;
740 doc = db.internal[dbnumber]->collect_document(realdid);
741 return Document(doc);
744 Document
745 Enquire::Internal::get_document(const Xapian::Internal::MSetItem &item) const
747 unsigned int multiplier = db.internal.size();
749 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
750 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
752 // We know the doc exists, so open lazily.
753 return Document(db.internal[dbnumber]->open_document(realdid, true));
756 // Methods of Xapian::Enquire
758 Enquire::Enquire(const Enquire & other) : internal(other.internal)
760 LOGCALL_CTOR(API, "Enquire", other);
763 void
764 Enquire::operator=(const Enquire & other)
766 LOGCALL_VOID(API, "Xapian::Enquire::operator=", other);
767 internal = other.internal;
770 Enquire::Enquire(Enquire&&) = default;
772 Enquire&
773 Enquire::operator=(Enquire&&) = default;
775 Enquire::Enquire(const Database &databases)
776 : internal(new Internal(databases))
778 LOGCALL_CTOR(API, "Enquire", databases);
781 Enquire::Enquire(const Database &databases, ErrorHandler *)
782 : internal(new Internal(databases))
784 LOGCALL_CTOR(API, "Enquire", databases | Literal("errorhandler"));
787 Enquire::~Enquire()
789 LOGCALL_DTOR(API, "Enquire");
792 void
793 Enquire::set_query(const Query & query, termcount len)
795 LOGCALL_VOID(API, "Xapian::Enquire::set_query", query | len);
796 internal->set_query(query, len);
799 const Query &
800 Enquire::get_query() const
802 LOGCALL(API, const Xapian::Query &, "Xapian::Enquire::get_query", NO_ARGS);
803 RETURN(internal->get_query());
806 void
807 Enquire::add_matchspy(MatchSpy * spy) {
808 LOGCALL_VOID(API, "Xapian::Enquire::add_matchspy", spy);
809 internal->spies.push_back(spy);
812 void
813 Enquire::clear_matchspies() {
814 LOGCALL_VOID(API, "Xapian::Enquire::clear_matchspies", NO_ARGS);
815 internal->spies.clear();
818 void
819 Enquire::set_weighting_scheme(const Weight &weight_)
821 LOGCALL_VOID(API, "Xapian::Enquire::set_weighting_scheme", weight_);
822 // Clone first in case doing so throws an exception.
823 Weight * wt = weight_.clone();
824 swap(wt, internal->weight);
825 delete wt;
828 void
829 Enquire::set_expansion_scheme(const std::string &eweightname_, double expand_k_) const
831 LOGCALL_VOID(API, "Xapian::Enquire::set_expansion_scheme", eweightname_ | expand_k_);
833 if (eweightname_ != "bo1" && eweightname_ != "trad") {
834 throw InvalidArgumentError("Invalid name for query expansion scheme.");
837 internal->eweightname = eweightname_;
838 internal->expand_k = expand_k_;
841 void
842 Enquire::set_collapse_key(Xapian::valueno collapse_key, Xapian::doccount collapse_max)
844 if (collapse_key == Xapian::BAD_VALUENO) collapse_max = 0;
845 internal->collapse_key = collapse_key;
846 internal->collapse_max = collapse_max;
849 void
850 Enquire::set_docid_order(Enquire::docid_order order)
852 internal->order = order;
855 void
856 Enquire::set_cutoff(int percent_cutoff, double weight_cutoff)
858 internal->percent_cutoff = percent_cutoff;
859 internal->weight_cutoff = weight_cutoff;
862 void
863 Enquire::set_sort_by_relevance()
865 internal->sort_by = Internal::REL;
868 void
869 Enquire::set_sort_by_value(valueno sort_key, bool ascending)
871 internal->sorter = NULL;
872 internal->sort_key = sort_key;
873 internal->sort_by = Internal::VAL;
874 internal->sort_value_forward = ascending;
877 void
878 Enquire::set_sort_by_value_then_relevance(valueno sort_key, bool ascending)
880 internal->sorter = NULL;
881 internal->sort_key = sort_key;
882 internal->sort_by = Internal::VAL_REL;
883 internal->sort_value_forward = ascending;
886 void
887 Enquire::set_sort_by_relevance_then_value(valueno sort_key, bool ascending)
889 internal->sorter = NULL;
890 internal->sort_key = sort_key;
891 internal->sort_by = Internal::REL_VAL;
892 internal->sort_value_forward = ascending;
895 void
896 Enquire::set_sort_by_key(KeyMaker * sorter, bool ascending)
898 if (sorter == NULL)
899 throw InvalidArgumentError("sorter can't be NULL");
900 internal->sorter = sorter;
901 internal->sort_by = Internal::VAL;
902 internal->sort_value_forward = ascending;
905 void
906 Enquire::set_sort_by_key_then_relevance(KeyMaker * sorter, bool ascending)
908 if (sorter == NULL)
909 throw InvalidArgumentError("sorter can't be NULL");
910 internal->sorter = sorter;
911 internal->sort_by = Internal::VAL_REL;
912 internal->sort_value_forward = ascending;
915 void
916 Enquire::set_sort_by_relevance_then_key(KeyMaker * sorter, bool ascending)
918 if (sorter == NULL)
919 throw Xapian::InvalidArgumentError("sorter can't be NULL");
920 internal->sorter = sorter;
921 internal->sort_by = Internal::REL_VAL;
922 internal->sort_value_forward = ascending;
925 void
926 Enquire::set_time_limit(double time_limit)
928 internal->time_limit = time_limit;
931 MSet
932 Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
933 Xapian::doccount check_at_least, const RSet *rset,
934 const MatchDecider *mdecider) const
936 LOGCALL(API, Xapian::MSet, "Xapian::Enquire::get_mset", first | maxitems | check_at_least | rset | mdecider);
937 RETURN(internal->get_mset(first, maxitems, check_at_least, rset, mdecider));
940 ESet
941 Enquire::get_eset(Xapian::termcount maxitems, const RSet & rset, int flags,
942 const ExpandDecider * edecider, double min_wt) const
944 LOGCALL(API, Xapian::ESet, "Xapian::Enquire::get_eset", maxitems | rset | flags | edecider | min_wt);
945 RETURN(internal->get_eset(maxitems, rset, flags, edecider, min_wt));
948 TermIterator
949 Enquire::get_matching_terms_begin(const MSetIterator &it) const
951 LOGCALL(API, Xapian::TermIterator, "Xapian::Enquire::get_matching_terms_begin", it);
952 RETURN(internal->get_matching_terms(it));
955 TermIterator
956 Enquire::get_matching_terms_begin(Xapian::docid did) const
958 LOGCALL(API, Xapian::TermIterator, "Xapian::Enquire::get_matching_terms_begin", did);
959 RETURN(internal->get_matching_terms(did));
962 string
963 Enquire::get_description() const
965 return "Xapian::Enquire(" + internal->get_description() + ")";