Fix whitespace irregularities in code
[xapian.git] / xapian-core / api / omenquire.cc
blob356d268da43922723054a87d64b9d62d27584ee0
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 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 "matcher/multimatch.h"
42 #include "omassert.h"
43 #include "api/omenquireinternal.h"
44 #include "str.h"
45 #include "weight/weightinternal.h"
47 #include <algorithm>
48 #include "autoptr.h"
49 #include <cfloat>
50 #include <cmath>
51 #include <vector>
53 using namespace std;
55 using Xapian::Internal::ExpandWeight;
56 using Xapian::Internal::Bo1EWeight;
57 using Xapian::Internal::TradEWeight;
59 namespace Xapian {
61 MatchDecider::~MatchDecider() { }
63 // Methods for Xapian::RSet
65 RSet::RSet() : internal(new RSet::Internal)
69 RSet::RSet(const RSet &other) : internal(other.internal)
73 void
74 RSet::operator=(const RSet &other)
76 internal = other.internal;
79 RSet::~RSet()
83 Xapian::doccount
84 RSet::size() const
86 return internal->items.size();
89 bool
90 RSet::empty() const
92 return internal->items.empty();
95 void
96 RSet::add_document(Xapian::docid did)
98 if (did == 0) throw Xapian::InvalidArgumentError("Docid 0 not valid");
99 internal->items.insert(did);
102 void
103 RSet::remove_document(Xapian::docid did)
105 internal->items.erase(did);
108 bool
109 RSet::contains(Xapian::docid did) const
111 return internal->items.find(did) != internal->items.end();
114 string
115 RSet::get_description() const
117 return "RSet(" + internal->get_description() + ")";
120 string
121 RSet::Internal::get_description() const
123 string description("RSet::Internal(");
125 set<Xapian::docid>::const_iterator i;
126 for (i = items.begin(); i != items.end(); ++i) {
127 if (i != items.begin()) description += ", ";
128 description += str(*i);
131 description += ')';
133 return description;
136 namespace Internal {
138 // Methods for Xapian::MSetItem
140 string
141 MSetItem::get_description() const
143 string description;
145 description = str(did) + ", " + str(wt) + ", " +
146 collapse_key;
148 description = "Xapian::MSetItem(" + description + ")";
150 return description;
155 // Methods for Xapian::MSet
157 MSet::MSet() : internal(new MSet::Internal)
161 MSet::~MSet()
165 MSet::MSet(const MSet & other) : internal(other.internal)
169 MSet &
170 MSet::operator=(const MSet &other)
172 internal = other.internal;
173 return *this;
176 void
177 MSet::fetch_(Xapian::doccount first, Xapian::doccount last) const
179 LOGCALL_VOID(API, "Xapian::MSet::fetch_", first | last);
180 Assert(internal.get() != 0);
181 internal->fetch_items(first, last);
185 MSet::convert_to_percent(double wt) const
187 LOGCALL(API, int, "Xapian::MSet::convert_to_percent", wt);
188 Assert(internal.get() != 0);
189 RETURN(internal->convert_to_percent_internal(wt));
192 Xapian::doccount
193 MSet::get_termfreq(const string &tname) const
195 LOGCALL(API, Xapian::doccount, "Xapian::MSet::get_termfreq", tname);
196 Assert(internal.get() != 0);
197 if (usual(internal->stats)) {
198 Xapian::doccount termfreq;
199 if (internal->stats->get_stats(tname, termfreq))
200 RETURN(termfreq);
202 if (internal->enquire.get() == 0) {
203 throw InvalidOperationError("Can't get termfreq from an MSet which is not derived from a query.");
205 RETURN(internal->enquire->get_termfreq(tname));
208 double
209 MSet::get_termweight(const string &tname) const
211 LOGCALL(API, double, "Xapian::MSet::get_termweight", tname);
212 Assert(internal.get() != 0);
213 if (!internal->stats) {
214 throw InvalidOperationError("Can't get termweight from an MSet which is not derived from a query.");
216 double termweight;
217 if (!internal->stats->get_termweight(tname, termweight)) {
218 string msg = tname;
219 msg += ": termweight not available";
220 throw InvalidArgumentError(msg);
222 RETURN(termweight);
225 Xapian::doccount
226 MSet::get_firstitem() const
228 Assert(internal.get() != 0);
229 return internal->firstitem;
232 Xapian::doccount
233 MSet::get_matches_lower_bound() const
235 Assert(internal.get() != 0);
236 return internal->matches_lower_bound;
239 Xapian::doccount
240 MSet::get_matches_estimated() const
242 Assert(internal.get() != 0);
243 return internal->matches_estimated;
246 Xapian::doccount
247 MSet::get_matches_upper_bound() const
249 Assert(internal.get() != 0);
250 return internal->matches_upper_bound;
253 Xapian::doccount
254 MSet::get_uncollapsed_matches_lower_bound() const
256 Assert(internal.get() != 0);
257 return internal->uncollapsed_lower_bound;
260 Xapian::doccount
261 MSet::get_uncollapsed_matches_estimated() const
263 Assert(internal.get() != 0);
264 return internal->uncollapsed_estimated;
267 Xapian::doccount
268 MSet::get_uncollapsed_matches_upper_bound() const
270 Assert(internal.get() != 0);
271 return internal->uncollapsed_upper_bound;
274 double
275 MSet::get_max_possible() const
277 Assert(internal.get() != 0);
278 return internal->max_possible;
281 double
282 MSet::get_max_attained() const
284 Assert(internal.get() != 0);
285 return internal->max_attained;
288 string
289 MSet::snippet(const string & text,
290 size_t length,
291 const Xapian::Stem & stemmer,
292 unsigned flags,
293 const string & hi_start,
294 const string & hi_end,
295 const string & omit) const
297 Assert(internal.get() != 0);
298 return internal->snippet(text, length, stemmer, flags,
299 hi_start, hi_end, omit);
302 Xapian::doccount
303 MSet::size() const
305 Assert(internal.get() != 0);
306 return internal->items.size();
309 string
310 MSet::get_description() const
312 Assert(internal.get() != 0);
313 return "Xapian::MSet(" + internal->get_description() + ")";
317 MSet::Internal::convert_to_percent_internal(double wt) const
319 LOGCALL(MATCH, int, "Xapian::MSet::Internal::convert_to_percent_internal", wt);
320 if (percent_factor == 0) RETURN(100);
322 // Excess precision on x86 can result in a difference here.
323 double v = wt * percent_factor + 100.0 * DBL_EPSILON;
324 int pcent = static_cast<int>(v);
325 LOGLINE(MATCH, "wt = " << wt << ", max_possible = " << max_possible <<
326 " => pcent = " << pcent);
327 if (pcent > 100) pcent = 100;
328 if (pcent < 0) pcent = 0;
329 if (pcent == 0 && wt > 0) pcent = 1;
331 RETURN(pcent);
334 Document
335 MSet::Internal::get_doc_by_index(Xapian::doccount index) const
337 LOGCALL(MATCH, Document, "Xapian::MSet::Internal::get_doc_by_index", index);
338 index += firstitem;
339 map<Xapian::doccount, Document>::const_iterator doc;
340 doc = indexeddocs.find(index);
341 if (doc != indexeddocs.end()) {
342 RETURN(doc->second);
344 if (index < firstitem || index >= firstitem + items.size()) {
345 throw RangeError("The mset returned from the match does not contain the document at index " + str(index));
347 Assert(enquire.get());
348 if (!requested_docs.empty()) {
349 // There's already a pending request, so handle that.
350 read_docs();
351 // Maybe we just fetched the doc we want.
352 doc = indexeddocs.find(index);
353 if (doc != indexeddocs.end()) {
354 RETURN(doc->second);
358 RETURN(enquire->get_document(items[index - firstitem]));
361 void
362 MSet::Internal::fetch_items(Xapian::doccount first, Xapian::doccount last) const
364 LOGCALL_VOID(MATCH, "Xapian::MSet::Internal::fetch_items", first | last);
365 if (enquire.get() == 0) {
366 throw InvalidOperationError("Can't fetch documents from an MSet which is not derived from a query.");
368 if (items.empty()) return;
369 if (last > items.size() - 1)
370 last = items.size() - 1;
371 for (Xapian::doccount i = first; i <= last; ++i) {
372 map<Xapian::doccount, Document>::const_iterator doc;
373 doc = indexeddocs.find(i);
374 if (doc == indexeddocs.end()) {
375 /* We don't have the document cached */
376 set<Xapian::doccount>::const_iterator s;
377 s = requested_docs.find(i);
378 if (s == requested_docs.end()) {
379 /* We haven't even requested it yet - do so now. */
380 enquire->request_doc(items[i - firstitem]);
381 requested_docs.insert(i);
387 string
388 MSet::Internal::get_description() const
390 string description = "Xapian::MSet::Internal(";
392 description += "firstitem=" + str(firstitem) + ", " +
393 "matches_lower_bound=" + str(matches_lower_bound) + ", " +
394 "matches_estimated=" + str(matches_estimated) + ", " +
395 "matches_upper_bound=" + str(matches_upper_bound) + ", " +
396 "max_possible=" + str(max_possible) + ", " +
397 "max_attained=" + str(max_attained);
399 for (vector<Xapian::Internal::MSetItem>::const_iterator i = items.begin();
400 i != items.end(); ++i) {
401 if (!description.empty()) description += ", ";
402 description += i->get_description();
405 description += ")";
407 return description;
410 void
411 MSet::Internal::read_docs() const
413 set<Xapian::doccount>::const_iterator i;
414 for (i = requested_docs.begin(); i != requested_docs.end(); ++i) {
415 indexeddocs[*i] = enquire->read_doc(items[*i - firstitem]);
416 LOGLINE(MATCH, "stored doc at index " << *i << " is " << indexeddocs[*i]);
418 /* Clear list of requested but not fetched documents. */
419 requested_docs.clear();
422 // MSetIterator
424 Xapian::docid
425 MSetIterator::operator*() const
427 Assert(mset.internal.get());
428 Xapian::doccount size = mset.internal->items.size();
429 Xapian::doccount index = size - off_from_end;
430 AssertRel(index,<,size);
431 return mset.internal->items[index].did;
434 Document
435 MSetIterator::get_document() const
437 Assert(mset.internal.get());
438 Xapian::doccount size = mset.internal->items.size();
439 Xapian::doccount index = size - off_from_end;
440 AssertRel(index,<,size);
441 return mset.internal->get_doc_by_index(index);
444 double
445 MSetIterator::get_weight() const
447 Assert(mset.internal.get());
448 Xapian::doccount size = mset.internal->items.size();
449 Xapian::doccount index = size - off_from_end;
450 AssertRel(index,<,size);
451 return mset.internal->items[index].wt;
454 std::string
455 MSetIterator::get_collapse_key() const
457 Assert(mset.internal.get());
458 Xapian::doccount size = mset.internal->items.size();
459 Xapian::doccount index = size - off_from_end;
460 AssertRel(index,<,size);
461 return mset.internal->items[index].collapse_key;
464 Xapian::doccount
465 MSetIterator::get_collapse_count() const
467 Assert(mset.internal.get());
468 Xapian::doccount size = mset.internal->items.size();
469 Xapian::doccount index = size - off_from_end;
470 AssertRel(index,<,size);
471 return mset.internal->items[index].collapse_count;
474 string
475 MSetIterator::get_description() const
477 return "Xapian::MSetIterator(" + str(mset.size() - off_from_end) + ")";
480 // Methods for Xapian::Enquire::Internal
482 Enquire::Internal::Internal(const Database &db_)
483 : db(db_), query(), collapse_key(Xapian::BAD_VALUENO), collapse_max(0),
484 order(Enquire::ASCENDING), percent_cutoff(0), weight_cutoff(0),
485 sort_key(Xapian::BAD_VALUENO), sort_by(REL), sort_value_forward(true),
486 sorter(), time_limit(0.0), weight(0),
487 eweightname("trad"), expand_k(1.0)
489 if (db.internal.empty()) {
490 throw InvalidArgumentError("Can't make an Enquire object from an uninitialised Database object.");
494 Enquire::Internal::~Internal()
496 delete weight;
497 weight = 0;
500 void
501 Enquire::Internal::set_query(const Query &query_, termcount qlen_)
503 query = query_;
504 qlen = qlen_ ? qlen_ : query.get_length();
507 const Query &
508 Enquire::Internal::get_query() const
510 return query;
513 MSet
514 Enquire::Internal::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
515 Xapian::doccount check_at_least, const RSet *rset,
516 const MatchDecider *mdecider) const
518 LOGCALL(MATCH, MSet, "Enquire::Internal::get_mset", first | maxitems | check_at_least | rset | mdecider);
520 if (percent_cutoff && (sort_by == VAL || sort_by == VAL_REL)) {
521 throw Xapian::UnimplementedError("Use of a percentage cutoff while sorting primary by value isn't currently supported");
524 if (weight == 0) {
525 weight = new BM25Weight;
528 Xapian::doccount first_orig = first;
530 Xapian::doccount docs = db.get_doccount();
531 first = min(first, docs);
532 maxitems = min(maxitems, docs);
533 check_at_least = min(check_at_least, docs);
534 check_at_least = max(check_at_least, maxitems);
537 AutoPtr<Xapian::Weight::Internal> stats(new Xapian::Weight::Internal);
538 ::MultiMatch match(db, query, qlen, rset,
539 collapse_max, collapse_key,
540 percent_cutoff, weight_cutoff,
541 order, sort_key, sort_by, sort_value_forward,
542 time_limit, *(stats.get()), weight, spies,
543 (sorter.get() != NULL),
544 (mdecider != NULL));
545 // Run query and put results into supplied Xapian::MSet object.
546 MSet retval;
547 match.get_mset(first, maxitems, check_at_least, retval,
548 *(stats.get()), mdecider, sorter.get());
549 if (first_orig != first && retval.internal.get()) {
550 retval.internal->firstitem = first_orig;
553 Assert(weight->name() != "bool" || retval.get_max_possible() == 0);
555 // The Xapian::MSet needs to have a pointer to ourselves, so that it can
556 // retrieve the documents. This is set here explicitly to avoid having
557 // to pass it into the matcher, which gets messy particularly in the
558 // networked case.
559 retval.internal->enquire = this;
561 if (!retval.internal->stats) {
562 retval.internal->stats = stats.release();
565 RETURN(retval);
568 ESet
569 Enquire::Internal::get_eset(Xapian::termcount maxitems,
570 const RSet & rset, int flags,
571 const ExpandDecider * edecider_,
572 double min_wt) const
574 LOGCALL(MATCH, ESet, "Enquire::Internal::get_eset", maxitems | rset | flags | edecider_ | min_wt);
576 using Xapian::Internal::opt_intrusive_ptr;
577 opt_intrusive_ptr<const ExpandDecider> edecider(edecider_);
578 if (maxitems == 0 || rset.empty()) {
579 // Either we were asked for no results, or wouldn't produce any
580 // because no documents were marked as relevant.
581 RETURN(ESet());
584 LOGVALUE(MATCH, rset.size());
586 if (!query.empty() && !(flags & Enquire::INCLUDE_QUERY_TERMS)) {
587 opt_intrusive_ptr<const ExpandDecider> decider_noquery(
588 (new ExpandDeciderFilterTerms(query.get_terms_begin(),
589 query.get_terms_end()))->release());
590 if (edecider.get()) {
591 edecider = (new ExpandDeciderAnd(decider_noquery.get(),
592 edecider.get()))->release();
593 } else {
594 edecider = decider_noquery;
598 bool use_exact_termfreq(flags & Enquire::USE_EXACT_TERMFREQ);
599 Xapian::ESet eset;
600 eset.internal = new Xapian::ESet::Internal;
602 if (eweightname == "bo1") {
603 Bo1EWeight bo1eweight(db, rset.size(), use_exact_termfreq);
604 eset.internal->expand(maxitems, db, rset, edecider.get(), bo1eweight,
605 min_wt);
606 } else {
607 TradEWeight tradeweight(db, rset.size(), use_exact_termfreq, expand_k);
608 eset.internal->expand(maxitems, db, rset, edecider.get(), tradeweight,
609 min_wt);
612 RETURN(eset);
615 class ByQueryIndexCmp {
616 private:
617 typedef map<string, unsigned int> tmap_t;
618 const tmap_t &tmap;
619 public:
620 ByQueryIndexCmp(const tmap_t &tmap_) : tmap(tmap_) {}
621 bool operator()(const string &left,
622 const string &right) const {
623 tmap_t::const_iterator l, r;
624 l = tmap.find(left);
625 r = tmap.find(right);
626 Assert((l != tmap.end()) && (r != tmap.end()));
628 return l->second < r->second;
632 TermIterator
633 Enquire::Internal::get_matching_terms(Xapian::docid did) const
635 if (query.empty())
636 return TermIterator();
638 // The ordered list of terms in the query.
639 TermIterator qt = query.get_terms_begin();
641 // copy the list of query terms into a map for faster access.
642 // FIXME: a hash would be faster than a map, if this becomes
643 // a problem.
644 map<string, unsigned int> tmap;
645 unsigned int index = 1;
646 for ( ; qt != query.get_terms_end(); ++qt) {
647 if (tmap.find(*qt) == tmap.end())
648 tmap[*qt] = index++;
651 vector<string> matching_terms;
653 TermIterator docterms = db.termlist_begin(did);
654 TermIterator docterms_end = db.termlist_end(did);
655 while (docterms != docterms_end) {
656 string term = *docterms;
657 map<string, unsigned int>::iterator t = tmap.find(term);
658 if (t != tmap.end()) matching_terms.push_back(term);
659 ++docterms;
662 // sort the resulting list by query position.
663 sort(matching_terms.begin(), matching_terms.end(), ByQueryIndexCmp(tmap));
665 return TermIterator(new VectorTermList(matching_terms.begin(),
666 matching_terms.end()));
669 TermIterator
670 Enquire::Internal::get_matching_terms(const MSetIterator &it) const
672 // FIXME: take advantage of MSetIterator to ensure that database
673 // doesn't get modified underneath us.
674 return get_matching_terms(*it);
677 Xapian::doccount
678 Enquire::Internal::get_termfreq(const string &tname) const
680 return db.get_termfreq(tname);
683 string
684 Enquire::Internal::get_description() const
686 string description = db.get_description();
687 description += ", ";
688 description += query.get_description();
689 return description;
692 // Private methods for Xapian::Enquire::Internal
694 void
695 Enquire::Internal::request_doc(const Xapian::Internal::MSetItem &item) const
697 unsigned int multiplier = db.internal.size();
699 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
700 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
702 db.internal[dbnumber]->request_document(realdid);
705 Document
706 Enquire::Internal::read_doc(const Xapian::Internal::MSetItem &item) const
708 unsigned int multiplier = db.internal.size();
710 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
711 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
713 Xapian::Document::Internal *doc;
714 doc = db.internal[dbnumber]->collect_document(realdid);
715 return Document(doc);
718 Document
719 Enquire::Internal::get_document(const Xapian::Internal::MSetItem &item) const
721 unsigned int multiplier = db.internal.size();
723 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
724 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
726 // We know the doc exists, so open lazily.
727 return Document(db.internal[dbnumber]->open_document(realdid, true));
730 // Methods of Xapian::Enquire
732 Enquire::Enquire(const Enquire & other) : internal(other.internal)
734 LOGCALL_CTOR(API, "Enquire", other);
737 void
738 Enquire::operator=(const Enquire & other)
740 LOGCALL_VOID(API, "Xapian::Enquire::operator=", other);
741 internal = other.internal;
744 Enquire::Enquire(const Database &databases)
745 : internal(new Internal(databases))
747 LOGCALL_CTOR(API, "Enquire", databases);
750 Enquire::Enquire(const Database &databases, ErrorHandler *)
751 : internal(new Internal(databases))
753 LOGCALL_CTOR(API, "Enquire", databases | Literal("errorhandler"));
756 Enquire::~Enquire()
758 LOGCALL_DTOR(API, "Enquire");
761 void
762 Enquire::set_query(const Query & query, termcount len)
764 LOGCALL_VOID(API, "Xapian::Enquire::set_query", query | len);
765 internal->set_query(query, len);
768 const Query &
769 Enquire::get_query() const
771 LOGCALL(API, const Xapian::Query &, "Xapian::Enquire::get_query", NO_ARGS);
772 RETURN(internal->get_query());
775 void
776 Enquire::add_matchspy(MatchSpy * spy) {
777 LOGCALL_VOID(API, "Xapian::Enquire::add_matchspy", spy);
778 internal->spies.push_back(spy);
781 void
782 Enquire::clear_matchspies() {
783 LOGCALL_VOID(API, "Xapian::Enquire::clear_matchspies", NO_ARGS);
784 internal->spies.clear();
787 void
788 Enquire::set_weighting_scheme(const Weight &weight_)
790 LOGCALL_VOID(API, "Xapian::Enquire::set_weighting_scheme", weight_);
791 // Clone first in case doing so throws an exception.
792 Weight * wt = weight_.clone();
793 swap(wt, internal->weight);
794 delete wt;
797 void
798 Enquire::set_expansion_scheme(const std::string &eweightname_, double expand_k_) const
800 LOGCALL_VOID(API, "Xapian::Enquire::set_expansion_scheme", eweightname_ | expand_k_);
802 if (eweightname_ != "bo1" && eweightname_ != "trad") {
803 throw InvalidArgumentError("Invalid name for query expansion scheme.");
806 internal->eweightname = eweightname_;
807 internal->expand_k = expand_k_;
810 void
811 Enquire::set_collapse_key(Xapian::valueno collapse_key, Xapian::doccount collapse_max)
813 if (collapse_key == Xapian::BAD_VALUENO) collapse_max = 0;
814 internal->collapse_key = collapse_key;
815 internal->collapse_max = collapse_max;
818 void
819 Enquire::set_docid_order(Enquire::docid_order order)
821 internal->order = order;
824 void
825 Enquire::set_cutoff(int percent_cutoff, double weight_cutoff)
827 internal->percent_cutoff = percent_cutoff;
828 internal->weight_cutoff = weight_cutoff;
831 void
832 Enquire::set_sort_by_relevance()
834 internal->sort_by = Internal::REL;
837 void
838 Enquire::set_sort_by_value(valueno sort_key, bool ascending)
840 internal->sorter = NULL;
841 internal->sort_key = sort_key;
842 internal->sort_by = Internal::VAL;
843 internal->sort_value_forward = ascending;
846 void
847 Enquire::set_sort_by_value_then_relevance(valueno sort_key, bool ascending)
849 internal->sorter = NULL;
850 internal->sort_key = sort_key;
851 internal->sort_by = Internal::VAL_REL;
852 internal->sort_value_forward = ascending;
855 void
856 Enquire::set_sort_by_relevance_then_value(valueno sort_key, bool ascending)
858 internal->sorter = NULL;
859 internal->sort_key = sort_key;
860 internal->sort_by = Internal::REL_VAL;
861 internal->sort_value_forward = ascending;
864 void
865 Enquire::set_sort_by_key(KeyMaker * sorter, bool ascending)
867 if (sorter == NULL)
868 throw InvalidArgumentError("sorter can't be NULL");
869 internal->sorter = sorter;
870 internal->sort_by = Internal::VAL;
871 internal->sort_value_forward = ascending;
874 void
875 Enquire::set_sort_by_key_then_relevance(KeyMaker * sorter, bool ascending)
877 if (sorter == NULL)
878 throw InvalidArgumentError("sorter can't be NULL");
879 internal->sorter = sorter;
880 internal->sort_by = Internal::VAL_REL;
881 internal->sort_value_forward = ascending;
884 void
885 Enquire::set_sort_by_relevance_then_key(KeyMaker * sorter, bool ascending)
887 if (sorter == NULL)
888 throw Xapian::InvalidArgumentError("sorter can't be NULL");
889 internal->sorter = sorter;
890 internal->sort_by = Internal::REL_VAL;
891 internal->sort_value_forward = ascending;
894 void
895 Enquire::set_time_limit(double time_limit)
897 internal->time_limit = time_limit;
900 MSet
901 Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
902 Xapian::doccount check_at_least, const RSet *rset,
903 const MatchDecider *mdecider) const
905 LOGCALL(API, Xapian::MSet, "Xapian::Enquire::get_mset", first | maxitems | check_at_least | rset | mdecider);
906 RETURN(internal->get_mset(first, maxitems, check_at_least, rset, mdecider));
909 ESet
910 Enquire::get_eset(Xapian::termcount maxitems, const RSet & rset, int flags,
911 const ExpandDecider * edecider, double min_wt) const
913 LOGCALL(API, Xapian::ESet, "Xapian::Enquire::get_eset", maxitems | rset | flags | edecider | min_wt);
914 RETURN(internal->get_eset(maxitems, rset, flags, edecider, min_wt));
917 TermIterator
918 Enquire::get_matching_terms_begin(const MSetIterator &it) const
920 LOGCALL(API, Xapian::TermIterator, "Xapian::Enquire::get_matching_terms_begin", it);
921 RETURN(internal->get_matching_terms(it));
924 TermIterator
925 Enquire::get_matching_terms_begin(Xapian::docid did) const
927 LOGCALL(API, Xapian::TermIterator, "Xapian::Enquire::get_matching_terms_begin", did);
928 RETURN(internal->get_matching_terms(did));
931 string
932 Enquire::get_description() const
934 return "Xapian::Enquire(" + internal->get_description() + ")";