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
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"
39 #include "expand/esetinternal.h"
40 #include "expand/expandweight.h"
41 #include "matcher/multimatch.h"
43 #include "api/omenquireinternal.h"
45 #include "weight/weightinternal.h"
55 using Xapian::Internal::ExpandWeight
;
56 using Xapian::Internal::Bo1EWeight
;
57 using Xapian::Internal::TradEWeight
;
61 MatchDecider::~MatchDecider() { }
63 // Methods for Xapian::RSet
65 RSet::RSet() : internal(new RSet::Internal
)
69 RSet::RSet(const RSet
&other
) : internal(other
.internal
)
74 RSet::operator=(const RSet
&other
)
76 internal
= other
.internal
;
86 return internal
->items
.size();
92 return internal
->items
.empty();
96 RSet::add_document(Xapian::docid did
)
98 if (did
== 0) throw Xapian::InvalidArgumentError("Docid 0 not valid");
99 internal
->items
.insert(did
);
103 RSet::remove_document(Xapian::docid did
)
105 internal
->items
.erase(did
);
109 RSet::contains(Xapian::docid did
) const
111 return internal
->items
.find(did
) != internal
->items
.end();
115 RSet::get_description() const
117 return "RSet(" + internal
->get_description() + ")";
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
);
138 // Methods for Xapian::MSetItem
141 MSetItem::get_description() const
145 description
= str(did
) + ", " + str(wt
) + ", " +
148 description
= "Xapian::MSetItem(" + description
+ ")";
155 // Methods for Xapian::MSet
157 MSet::MSet() : internal(new MSet::Internal
)
165 MSet::MSet(const MSet
& other
) : internal(other
.internal
)
170 MSet::operator=(const MSet
&other
)
172 internal
= other
.internal
;
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
));
193 MSet::convert_to_percent(const MSetIterator
& it
) const
195 LOGCALL(API
, int, "Xapian::MSet::convert_to_percent", it
);
196 Assert(internal
.get() != 0);
197 RETURN(internal
->convert_to_percent_internal(it
.get_weight()));
201 MSet::get_termfreq(const string
&tname
) const
203 LOGCALL(API
, Xapian::doccount
, "Xapian::MSet::get_termfreq", tname
);
204 Assert(internal
.get() != 0);
205 if (usual(internal
->stats
)) {
206 Xapian::doccount termfreq
;
207 if (internal
->stats
->get_stats(tname
, termfreq
))
210 if (internal
->enquire
.get() == 0) {
211 throw InvalidOperationError("Can't get termfreq from an MSet which is not derived from a query.");
213 RETURN(internal
->enquire
->get_termfreq(tname
));
217 MSet::get_termweight(const string
&tname
) const
219 LOGCALL(API
, double, "Xapian::MSet::get_termweight", tname
);
220 Assert(internal
.get() != 0);
221 if (!internal
->stats
) {
222 throw InvalidOperationError("Can't get termweight from an MSet which is not derived from a query.");
225 if (!internal
->stats
->get_termweight(tname
, termweight
)) {
227 msg
+= ": termweight not available";
228 throw InvalidArgumentError(msg
);
234 MSet::get_firstitem() const
236 Assert(internal
.get() != 0);
237 return internal
->firstitem
;
241 MSet::get_matches_lower_bound() const
243 Assert(internal
.get() != 0);
244 return internal
->matches_lower_bound
;
248 MSet::get_matches_estimated() const
250 Assert(internal
.get() != 0);
251 return internal
->matches_estimated
;
255 MSet::get_matches_upper_bound() const
257 Assert(internal
.get() != 0);
258 return internal
->matches_upper_bound
;
262 MSet::get_uncollapsed_matches_lower_bound() const
264 Assert(internal
.get() != 0);
265 return internal
->uncollapsed_lower_bound
;
269 MSet::get_uncollapsed_matches_estimated() const
271 Assert(internal
.get() != 0);
272 return internal
->uncollapsed_estimated
;
276 MSet::get_uncollapsed_matches_upper_bound() const
278 Assert(internal
.get() != 0);
279 return internal
->uncollapsed_upper_bound
;
283 MSet::get_max_possible() const
285 Assert(internal
.get() != 0);
286 return internal
->max_possible
;
290 MSet::get_max_attained() const
292 Assert(internal
.get() != 0);
293 return internal
->max_attained
;
297 MSet::snippet(const string
& text
,
299 const Xapian::Stem
& stemmer
,
301 const string
& hi_start
,
302 const string
& hi_end
,
303 const string
& omit
) const
305 Assert(internal
.get() != 0);
306 return internal
->snippet(text
, length
, stemmer
, flags
,
307 hi_start
, hi_end
, omit
);
313 Assert(internal
.get() != 0);
314 return internal
->items
.size();
318 MSet::get_description() const
320 Assert(internal
.get() != 0);
321 return "Xapian::MSet(" + internal
->get_description() + ")";
325 MSet::Internal::convert_to_percent_internal(double wt
) const
327 LOGCALL(MATCH
, int, "Xapian::MSet::Internal::convert_to_percent_internal", wt
);
328 if (percent_factor
== 0) RETURN(100);
330 // Excess precision on x86 can result in a difference here.
331 double v
= wt
* percent_factor
+ 100.0 * DBL_EPSILON
;
332 int pcent
= static_cast<int>(v
);
333 LOGLINE(MATCH
, "wt = " << wt
<< ", max_possible = " << max_possible
<<
334 " => pcent = " << pcent
);
335 if (pcent
> 100) pcent
= 100;
336 if (pcent
< 0) pcent
= 0;
337 if (pcent
== 0 && wt
> 0) pcent
= 1;
343 MSet::Internal::get_doc_by_index(Xapian::doccount index
) const
345 LOGCALL(MATCH
, Document
, "Xapian::MSet::Internal::get_doc_by_index", index
);
347 map
<Xapian::doccount
, Document
>::const_iterator doc
;
348 doc
= indexeddocs
.find(index
);
349 if (doc
!= indexeddocs
.end()) {
352 if (index
< firstitem
|| index
>= firstitem
+ items
.size()) {
353 throw RangeError("The mset returned from the match does not contain the document at index " + str(index
));
355 Assert(enquire
.get());
356 if (!requested_docs
.empty()) {
357 // There's already a pending request, so handle that.
359 // Maybe we just fetched the doc we want.
360 doc
= indexeddocs
.find(index
);
361 if (doc
!= indexeddocs
.end()) {
366 RETURN(enquire
->get_document(items
[index
- firstitem
]));
370 MSet::Internal::fetch_items(Xapian::doccount first
, Xapian::doccount last
) const
372 LOGCALL_VOID(MATCH
, "Xapian::MSet::Internal::fetch_items", first
| last
);
373 if (enquire
.get() == 0) {
374 throw InvalidOperationError("Can't fetch documents from an MSet which is not derived from a query.");
376 if (items
.empty()) return;
377 if (last
> items
.size() - 1)
378 last
= items
.size() - 1;
379 for (Xapian::doccount i
= first
; i
<= last
; ++i
) {
380 map
<Xapian::doccount
, Document
>::const_iterator doc
;
381 doc
= indexeddocs
.find(i
);
382 if (doc
== indexeddocs
.end()) {
383 /* We don't have the document cached */
384 set
<Xapian::doccount
>::const_iterator s
;
385 s
= requested_docs
.find(i
);
386 if (s
== requested_docs
.end()) {
387 /* We haven't even requested it yet - do so now. */
388 enquire
->request_doc(items
[i
- firstitem
]);
389 requested_docs
.insert(i
);
396 MSet::Internal::get_description() const
398 string description
= "Xapian::MSet::Internal(";
400 description
+= "firstitem=" + str(firstitem
) + ", " +
401 "matches_lower_bound=" + str(matches_lower_bound
) + ", " +
402 "matches_estimated=" + str(matches_estimated
) + ", " +
403 "matches_upper_bound=" + str(matches_upper_bound
) + ", " +
404 "max_possible=" + str(max_possible
) + ", " +
405 "max_attained=" + str(max_attained
);
407 for (vector
<Xapian::Internal::MSetItem
>::const_iterator i
= items
.begin();
408 i
!= items
.end(); ++i
) {
409 if (!description
.empty()) description
+= ", ";
410 description
+= i
->get_description();
419 MSet::Internal::read_docs() const
421 set
<Xapian::doccount
>::const_iterator i
;
422 for (i
= requested_docs
.begin(); i
!= requested_docs
.end(); ++i
) {
423 indexeddocs
[*i
] = enquire
->read_doc(items
[*i
- firstitem
]);
424 LOGLINE(MATCH
, "stored doc at index " << *i
<< " is " << indexeddocs
[*i
]);
426 /* Clear list of requested but not fetched documents. */
427 requested_docs
.clear();
430 // Methods for Xapian::ESet
432 ESet::ESet() : internal(new Internal
) { }
438 ESet::ESet(const ESet
& other
) : internal(other
.internal
)
443 ESet::operator=(const ESet
&other
)
445 internal
= other
.internal
;
449 ESet::get_ebound() const
451 return internal
->ebound
;
457 return internal
->items
.size();
463 return internal
->items
.empty();
467 ESet::swap(ESet
& other
)
469 std::swap(internal
, other
.internal
);
475 return ESetIterator(0, *this);
481 Assert(internal
.get() != 0);
482 return ESetIterator(internal
->items
.size(), *this);
486 ESet::operator[](Xapian::termcount i
) const
488 // Don't test 0 <= i - that gives a compiler warning if i is unsigned
489 Assert(0 < (i
+ 1) && i
< size());
490 return ESetIterator(i
, *this);
497 Assert(internal
.get() != 0);
498 return ESetIterator(internal
->items
.size() - 1, *this);
502 ESet::get_description() const
504 Assert(internal
.get() != 0);
505 return "Xapian::ESet(" + internal
->get_description() + ")";
508 // Xapian::ESetIterator
511 ESetIterator::operator *() const
513 Assert(eset
.internal
.get());
514 AssertRel(index
,<,eset
.internal
->items
.size());
515 return eset
.internal
->items
[index
].term
;
519 ESetIterator::get_weight() const
521 Assert(eset
.internal
.get());
522 AssertRel(index
,<,eset
.internal
->items
.size());
523 return eset
.internal
->items
[index
].wt
;
527 ESetIterator::get_description() const
529 return "Xapian::ESetIterator(" + str(index
) + ")";
535 MSetIterator::operator *() const
537 Assert(mset
.internal
.get());
538 Xapian::doccount size
= mset
.internal
->items
.size();
539 Xapian::doccount index
= size
- off_from_end
;
540 AssertRel(index
,<,size
);
541 return mset
.internal
->items
[index
].did
;
545 MSetIterator::get_document() const
547 Assert(mset
.internal
.get());
548 Xapian::doccount size
= mset
.internal
->items
.size();
549 Xapian::doccount index
= size
- off_from_end
;
550 AssertRel(index
,<,size
);
551 return mset
.internal
->get_doc_by_index(index
);
555 MSetIterator::get_weight() const
557 Assert(mset
.internal
.get());
558 Xapian::doccount size
= mset
.internal
->items
.size();
559 Xapian::doccount index
= size
- off_from_end
;
560 AssertRel(index
,<,size
);
561 return mset
.internal
->items
[index
].wt
;
565 MSetIterator::get_collapse_key() const
567 Assert(mset
.internal
.get());
568 Xapian::doccount size
= mset
.internal
->items
.size();
569 Xapian::doccount index
= size
- off_from_end
;
570 AssertRel(index
,<,size
);
571 return mset
.internal
->items
[index
].collapse_key
;
575 MSetIterator::get_collapse_count() const
577 Assert(mset
.internal
.get());
578 Xapian::doccount size
= mset
.internal
->items
.size();
579 Xapian::doccount index
= size
- off_from_end
;
580 AssertRel(index
,<,size
);
581 return mset
.internal
->items
[index
].collapse_count
;
585 MSetIterator::get_description() const
587 return "Xapian::MSetIterator(" + str(mset
.size() - off_from_end
) + ")";
590 // Methods for Xapian::Enquire::Internal
592 Enquire::Internal::Internal(const Database
&db_
)
593 : db(db_
), query(), collapse_key(Xapian::BAD_VALUENO
), collapse_max(0),
594 order(Enquire::ASCENDING
), percent_cutoff(0), weight_cutoff(0),
595 sort_key(Xapian::BAD_VALUENO
), sort_by(REL
), sort_value_forward(true),
596 sorter(0), time_limit(0.0), weight(0),
597 eweightname("trad"), expand_k(1.0)
599 if (db
.internal
.empty()) {
600 throw InvalidArgumentError("Can't make an Enquire object from an uninitialised Database object.");
604 Enquire::Internal::~Internal()
611 Enquire::Internal::set_query(const Query
&query_
, termcount qlen_
)
614 qlen
= qlen_
? qlen_
: query
.get_length();
618 Enquire::Internal::get_query() const
624 Enquire::Internal::get_mset(Xapian::doccount first
, Xapian::doccount maxitems
,
625 Xapian::doccount check_at_least
, const RSet
*rset
,
626 const MatchDecider
*mdecider
) const
628 LOGCALL(MATCH
, MSet
, "Enquire::Internal::get_mset", first
| maxitems
| check_at_least
| rset
| mdecider
);
630 if (percent_cutoff
&& (sort_by
== VAL
|| sort_by
== VAL_REL
)) {
631 throw Xapian::UnimplementedError("Use of a percentage cutoff while sorting primary by value isn't currently supported");
635 weight
= new BM25Weight
;
638 Xapian::doccount first_orig
= first
;
640 Xapian::doccount docs
= db
.get_doccount();
641 first
= min(first
, docs
);
642 maxitems
= min(maxitems
, docs
);
643 check_at_least
= min(check_at_least
, docs
);
644 check_at_least
= max(check_at_least
, maxitems
);
647 AutoPtr
<Xapian::Weight::Internal
> stats(new Xapian::Weight::Internal
);
648 ::MultiMatch
match(db
, query
, qlen
, rset
,
649 collapse_max
, collapse_key
,
650 percent_cutoff
, weight_cutoff
,
651 order
, sort_key
, sort_by
, sort_value_forward
,
652 time_limit
, *(stats
.get()), weight
, spies
,
653 (sorter
.get() != NULL
),
655 // Run query and put results into supplied Xapian::MSet object.
657 match
.get_mset(first
, maxitems
, check_at_least
, retval
,
658 *(stats
.get()), mdecider
, sorter
.get());
659 if (first_orig
!= first
&& retval
.internal
.get()) {
660 retval
.internal
->firstitem
= first_orig
;
663 Assert(weight
->name() != "bool" || retval
.get_max_possible() == 0);
665 // The Xapian::MSet needs to have a pointer to ourselves, so that it can
666 // retrieve the documents. This is set here explicitly to avoid having
667 // to pass it into the matcher, which gets messy particularly in the
669 retval
.internal
->enquire
= this;
671 if (!retval
.internal
->stats
) {
672 retval
.internal
->stats
= stats
.release();
679 Enquire::Internal::get_eset(Xapian::termcount maxitems
,
680 const RSet
& rset
, int flags
,
681 const ExpandDecider
* edecider_
,
684 LOGCALL(MATCH
, ESet
, "Enquire::Internal::get_eset", maxitems
| rset
| flags
| edecider_
| min_wt
);
686 using Xapian::Internal::opt_intrusive_ptr
;
687 opt_intrusive_ptr
<const ExpandDecider
> edecider(edecider_
);
688 if (maxitems
== 0 || rset
.empty()) {
689 // Either we were asked for no results, or wouldn't produce any
690 // because no documents were marked as relevant.
694 LOGVALUE(MATCH
, rset
.size());
696 if (!query
.empty() && !(flags
& Enquire::INCLUDE_QUERY_TERMS
)) {
697 opt_intrusive_ptr
<const ExpandDecider
> decider_noquery(
698 (new ExpandDeciderFilterTerms(query
.get_terms_begin(),
699 query
.get_terms_end()))->release());
700 if (edecider
.get()) {
701 edecider
= (new ExpandDeciderAnd(decider_noquery
.get(),
702 edecider
.get()))->release();
704 edecider
= decider_noquery
;
708 bool use_exact_termfreq(flags
& Enquire::USE_EXACT_TERMFREQ
);
711 if (eweightname
== "bo1") {
712 Bo1EWeight
bo1eweight(db
, rset
.size(), use_exact_termfreq
);
713 eset
.internal
->expand(maxitems
, db
, rset
, edecider
.get(), bo1eweight
,
716 TradEWeight
tradeweight(db
, rset
.size(), use_exact_termfreq
, expand_k
);
717 eset
.internal
->expand(maxitems
, db
, rset
, edecider
.get(), tradeweight
,
724 class ByQueryIndexCmp
{
726 typedef map
<string
, unsigned int> tmap_t
;
729 ByQueryIndexCmp(const tmap_t
&tmap_
) : tmap(tmap_
) {}
730 bool operator()(const string
&left
,
731 const string
&right
) const {
732 tmap_t::const_iterator l
, r
;
734 r
= tmap
.find(right
);
735 Assert((l
!= tmap
.end()) && (r
!= tmap
.end()));
737 return l
->second
< r
->second
;
742 Enquire::Internal::get_matching_terms(Xapian::docid did
) const
745 return TermIterator();
747 // The ordered list of terms in the query.
748 TermIterator qt
= query
.get_terms_begin();
750 // copy the list of query terms into a map for faster access.
751 // FIXME: a hash would be faster than a map, if this becomes
753 map
<string
, unsigned int> tmap
;
754 unsigned int index
= 1;
755 for ( ; qt
!= query
.get_terms_end(); ++qt
) {
756 if (tmap
.find(*qt
) == tmap
.end())
760 vector
<string
> matching_terms
;
762 TermIterator docterms
= db
.termlist_begin(did
);
763 TermIterator docterms_end
= db
.termlist_end(did
);
764 while (docterms
!= docterms_end
) {
765 string term
= *docterms
;
766 map
<string
, unsigned int>::iterator t
= tmap
.find(term
);
767 if (t
!= tmap
.end()) matching_terms
.push_back(term
);
771 // sort the resulting list by query position.
772 sort(matching_terms
.begin(), matching_terms
.end(), ByQueryIndexCmp(tmap
));
774 return TermIterator(new VectorTermList(matching_terms
.begin(),
775 matching_terms
.end()));
779 Enquire::Internal::get_matching_terms(const MSetIterator
&it
) const
781 // FIXME: take advantage of MSetIterator to ensure that database
782 // doesn't get modified underneath us.
783 return get_matching_terms(*it
);
787 Enquire::Internal::get_termfreq(const string
&tname
) const
789 return db
.get_termfreq(tname
);
793 Enquire::Internal::get_description() const
795 string description
= db
.get_description();
797 description
+= query
.get_description();
801 // Private methods for Xapian::Enquire::Internal
804 Enquire::Internal::request_doc(const Xapian::Internal::MSetItem
&item
) const
806 unsigned int multiplier
= db
.internal
.size();
808 Xapian::docid realdid
= (item
.did
- 1) / multiplier
+ 1;
809 Xapian::doccount dbnumber
= (item
.did
- 1) % multiplier
;
811 db
.internal
[dbnumber
]->request_document(realdid
);
815 Enquire::Internal::read_doc(const Xapian::Internal::MSetItem
&item
) const
817 unsigned int multiplier
= db
.internal
.size();
819 Xapian::docid realdid
= (item
.did
- 1) / multiplier
+ 1;
820 Xapian::doccount dbnumber
= (item
.did
- 1) % multiplier
;
822 Xapian::Document::Internal
*doc
;
823 doc
= db
.internal
[dbnumber
]->collect_document(realdid
);
824 return Document(doc
);
828 Enquire::Internal::get_document(const Xapian::Internal::MSetItem
&item
) const
830 unsigned int multiplier
= db
.internal
.size();
832 Xapian::docid realdid
= (item
.did
- 1) / multiplier
+ 1;
833 Xapian::doccount dbnumber
= (item
.did
- 1) % multiplier
;
835 // We know the doc exists, so open lazily.
836 return Document(db
.internal
[dbnumber
]->open_document(realdid
, true));
839 // Methods of Xapian::Enquire
841 Enquire::Enquire(const Enquire
& other
) : internal(other
.internal
)
843 LOGCALL_CTOR(API
, "Enquire", other
);
847 Enquire::operator=(const Enquire
& other
)
849 LOGCALL_VOID(API
, "Xapian::Enquire::operator=", other
);
850 internal
= other
.internal
;
853 Enquire::Enquire(const Database
&databases
)
854 : internal(new Internal(databases
))
856 LOGCALL_CTOR(API
, "Enquire", databases
);
859 Enquire::Enquire(const Database
&databases
, ErrorHandler
*)
860 : internal(new Internal(databases
))
862 LOGCALL_CTOR(API
, "Enquire", databases
| Literal("errorhandler"));
867 LOGCALL_DTOR(API
, "Enquire");
871 Enquire::set_query(const Query
& query
, termcount len
)
873 LOGCALL_VOID(API
, "Xapian::Enquire::set_query", query
| len
);
874 internal
->set_query(query
, len
);
878 Enquire::get_query() const
880 LOGCALL(API
, const Xapian::Query
&, "Xapian::Enquire::get_query", NO_ARGS
);
881 RETURN(internal
->get_query());
885 Enquire::add_matchspy(MatchSpy
* spy
) {
886 LOGCALL_VOID(API
, "Xapian::Enquire::add_matchspy", spy
);
887 internal
->spies
.push_back(spy
);
891 Enquire::clear_matchspies() {
892 LOGCALL_VOID(API
, "Xapian::Enquire::clear_matchspies", NO_ARGS
);
893 internal
->spies
.clear();
897 Enquire::set_weighting_scheme(const Weight
&weight_
)
899 LOGCALL_VOID(API
, "Xapian::Enquire::set_weighting_scheme", weight_
);
900 // Clone first in case doing so throws an exception.
901 Weight
* wt
= weight_
.clone();
902 swap(wt
, internal
->weight
);
907 Enquire::set_expansion_scheme(const std::string
&eweightname_
, double expand_k_
) const
909 LOGCALL_VOID(API
, "Xapian::Enquire::set_expansion_scheme", eweightname_
| expand_k_
);
911 if (eweightname_
!= "bo1" && eweightname_
!= "trad") {
912 throw InvalidArgumentError("Invalid name for query expansion scheme.");
915 internal
->eweightname
= eweightname_
;
916 internal
->expand_k
= expand_k_
;
920 Enquire::set_collapse_key(Xapian::valueno collapse_key
, Xapian::doccount collapse_max
)
922 if (collapse_key
== Xapian::BAD_VALUENO
) collapse_max
= 0;
923 internal
->collapse_key
= collapse_key
;
924 internal
->collapse_max
= collapse_max
;
928 Enquire::set_docid_order(Enquire::docid_order order
)
930 internal
->order
= order
;
934 Enquire::set_cutoff(int percent_cutoff
, double weight_cutoff
)
936 internal
->percent_cutoff
= percent_cutoff
;
937 internal
->weight_cutoff
= weight_cutoff
;
941 Enquire::set_sort_by_relevance()
943 internal
->sort_by
= Internal::REL
;
947 Enquire::set_sort_by_value(valueno sort_key
, bool ascending
)
949 internal
->sorter
= NULL
;
950 internal
->sort_key
= sort_key
;
951 internal
->sort_by
= Internal::VAL
;
952 internal
->sort_value_forward
= ascending
;
956 Enquire::set_sort_by_value_then_relevance(valueno sort_key
, bool ascending
)
958 internal
->sorter
= NULL
;
959 internal
->sort_key
= sort_key
;
960 internal
->sort_by
= Internal::VAL_REL
;
961 internal
->sort_value_forward
= ascending
;
965 Enquire::set_sort_by_relevance_then_value(valueno sort_key
, bool ascending
)
967 internal
->sorter
= NULL
;
968 internal
->sort_key
= sort_key
;
969 internal
->sort_by
= Internal::REL_VAL
;
970 internal
->sort_value_forward
= ascending
;
974 Enquire::set_sort_by_key(KeyMaker
* sorter
, bool ascending
)
977 throw InvalidArgumentError("sorter can't be NULL");
978 internal
->sorter
= sorter
;
979 internal
->sort_by
= Internal::VAL
;
980 internal
->sort_value_forward
= ascending
;
984 Enquire::set_sort_by_key_then_relevance(KeyMaker
* sorter
, bool ascending
)
987 throw InvalidArgumentError("sorter can't be NULL");
988 internal
->sorter
= sorter
;
989 internal
->sort_by
= Internal::VAL_REL
;
990 internal
->sort_value_forward
= ascending
;
994 Enquire::set_sort_by_relevance_then_key(KeyMaker
* sorter
, bool ascending
)
997 throw Xapian::InvalidArgumentError("sorter can't be NULL");
998 internal
->sorter
= sorter
;
999 internal
->sort_by
= Internal::REL_VAL
;
1000 internal
->sort_value_forward
= ascending
;
1004 Enquire::set_time_limit(double time_limit
)
1006 internal
->time_limit
= time_limit
;
1010 Enquire::get_mset(Xapian::doccount first
, Xapian::doccount maxitems
,
1011 Xapian::doccount check_at_least
, const RSet
*rset
,
1012 const MatchDecider
*mdecider
) const
1014 LOGCALL(API
, Xapian::MSet
, "Xapian::Enquire::get_mset", first
| maxitems
| check_at_least
| rset
| mdecider
);
1015 RETURN(internal
->get_mset(first
, maxitems
, check_at_least
, rset
, mdecider
));
1019 Enquire::get_eset(Xapian::termcount maxitems
, const RSet
& rset
, int flags
,
1020 const ExpandDecider
* edecider
, double min_wt
) const
1022 LOGCALL(API
, Xapian::ESet
, "Xapian::Enquire::get_eset", maxitems
| rset
| flags
| edecider
| min_wt
);
1023 RETURN(internal
->get_eset(maxitems
, rset
, flags
, edecider
, min_wt
));
1027 Enquire::get_matching_terms_begin(const MSetIterator
&it
) const
1029 LOGCALL(API
, Xapian::TermIterator
, "Xapian::Enquire::get_matching_terms_begin", it
);
1030 RETURN(internal
->get_matching_terms(it
));
1034 Enquire::get_matching_terms_begin(Xapian::docid did
) const
1036 LOGCALL(API
, Xapian::TermIterator
, "Xapian::Enquire::get_matching_terms_begin", did
);
1037 RETURN(internal
->get_matching_terms(did
));
1041 Enquire::get_description() const
1043 return "Xapian::Enquire(" + internal
->get_description() + ")";