00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include "omdebug.h"
00026
00027 #include <xapian/document.h>
00028 #include <xapian/enquire.h>
00029 #include <xapian/error.h>
00030 #include <xapian/errorhandler.h>
00031 #include <xapian/expanddecider.h>
00032 #include <xapian/termiterator.h>
00033
00034 #include "vectortermlist.h"
00035
00036 #include "rset.h"
00037 #include "multimatch.h"
00038 #include "expand.h"
00039 #include "database.h"
00040 #include "omenquireinternal.h"
00041 #include "stats.h"
00042 #include "utils.h"
00043
00044 #include <vector>
00045 #include "autoptr.h"
00046 #include <algorithm>
00047 #include <cfloat>
00048 #include <math.h>
00049
00050 using namespace std;
00051
00052 namespace Xapian {
00053
00054 MatchDecider::~MatchDecider() { }
00055
00056
00057
00058 RSet::RSet() : internal(new RSet::Internal())
00059 {
00060 }
00061
00062 RSet::RSet(const RSet &other) : internal(other.internal)
00063 {
00064 }
00065
00066 void
00067 RSet::operator=(const RSet &other)
00068 {
00069 internal = other.internal;
00070 }
00071
00072 RSet::~RSet()
00073 {
00074 }
00075
00076 Xapian::doccount
00077 RSet::size() const
00078 {
00079 return internal->items.size();
00080 }
00081
00082 bool
00083 RSet::empty() const
00084 {
00085 return internal->items.empty();
00086 }
00087
00088 void
00089 RSet::add_document(Xapian::docid did)
00090 {
00091 internal->items.insert(did);
00092 }
00093
00094 void
00095 RSet::remove_document(Xapian::docid did)
00096 {
00097 internal->items.erase(did);
00098 }
00099
00100 bool
00101 RSet::contains(Xapian::docid did) const
00102 {
00103 return internal->items.find(did) != internal->items.end();
00104 }
00105
00106 string
00107 RSet::get_description() const
00108 {
00109 return "RSet(" + internal->get_description() + ")";
00110 }
00111
00112 string
00113 RSet::Internal::get_description() const
00114 {
00115 string description("RSet::Internal(");
00116
00117 set<Xapian::docid>::const_iterator i;
00118 for (i = items.begin(); i != items.end(); ++i) {
00119 if (i != items.begin()) description += ", ";
00120 description += om_tostring(*i);
00121 }
00122
00123 description += ')';
00124
00125 return description;
00126 }
00127
00128 namespace Internal {
00129
00130
00131
00132 string
00133 MSetItem::get_description() const
00134 {
00135 string description;
00136
00137 description = om_tostring(did) + ", " + om_tostring(wt) + ", " +
00138 collapse_key;
00139
00140 description = "Xapian::MSetItem(" + description + ")";
00141
00142 return description;
00143 }
00144
00145 }
00146
00147
00148
00149 MSet::MSet() : internal(new MSet::Internal())
00150 {
00151 }
00152
00153 MSet::MSet(MSet::Internal * internal_) : internal(internal_)
00154 {
00155 }
00156
00157 MSet::~MSet()
00158 {
00159 }
00160
00161 MSet::MSet(const MSet & other) : internal(other.internal)
00162 {
00163 }
00164
00165 void
00166 MSet::operator=(const MSet &other)
00167 {
00168 internal = other.internal;
00169 }
00170
00171 void
00172 MSet::fetch(const MSetIterator & beginiter, const MSetIterator & enditer) const
00173 {
00174 DEBUGAPICALL(void, "Xapian::MSet::fetch", beginiter << ", " << enditer);
00175 Assert(internal.get() != 0);
00176 if (beginiter != enditer)
00177 internal->fetch_items(beginiter.index, enditer.index - 1);
00178 }
00179
00180 void
00181 MSet::fetch(const MSetIterator & beginiter) const
00182 {
00183 DEBUGAPICALL(void, "Xapian::MSet::fetch", beginiter);
00184 Assert(internal.get() != 0);
00185 internal->fetch_items(beginiter.index, beginiter.index);
00186 }
00187
00188 void
00189 MSet::fetch() const
00190 {
00191 DEBUGAPICALL(void, "Xapian::MSet::fetch", "");
00192 Assert(internal.get() != 0);
00193 if (!internal->items.empty())
00194 internal->fetch_items(0, internal->items.size() - 1);
00195 }
00196
00197 percent
00198 MSet::convert_to_percent(Xapian::weight wt) const
00199 {
00200 DEBUGAPICALL(Xapian::percent, "Xapian::MSet::convert_to_percent", wt);
00201 Assert(internal.get() != 0);
00202 RETURN(internal->convert_to_percent_internal(wt));
00203 }
00204
00205 percent
00206 MSet::convert_to_percent(const MSetIterator & it) const
00207 {
00208 DEBUGAPICALL(Xapian::percent, "Xapian::MSet::convert_to_percent", it);
00209 Assert(internal.get() != 0);
00210 RETURN(internal->convert_to_percent_internal(it.get_weight()));
00211 }
00212
00213 Xapian::doccount
00214 MSet::get_termfreq(const string &tname) const
00215 {
00216 DEBUGAPICALL(Xapian::doccount, "Xapian::MSet::get_termfreq", tname);
00217 map<string, Internal::TermFreqAndWeight>::const_iterator i;
00218 Assert(internal.get() != 0);
00219 i = internal->termfreqandwts.find(tname);
00220 if (i == internal->termfreqandwts.end()) {
00221 throw InvalidArgumentError("Term frequency of `" + tname +
00222 "' not available.");
00223 }
00224 RETURN(i->second.termfreq);
00225 }
00226
00227 Xapian::weight
00228 MSet::get_termweight(const string &tname) const
00229 {
00230 DEBUGAPICALL(Xapian::weight, "Xapian::MSet::get_termweight", tname);
00231 map<string, Internal::TermFreqAndWeight>::const_iterator i;
00232 Assert(internal.get() != 0);
00233 i = internal->termfreqandwts.find(tname);
00234 if (i == internal->termfreqandwts.end()) {
00235 throw InvalidArgumentError("Term weight of `" + tname +
00236 "' not available.");
00237 }
00238 RETURN(i->second.termweight);
00239 }
00240
00241 Xapian::doccount
00242 MSet::get_firstitem() const
00243 {
00244 Assert(internal.get() != 0);
00245 return internal->firstitem;
00246 }
00247
00248 Xapian::doccount
00249 MSet::get_matches_lower_bound() const
00250 {
00251 Assert(internal.get() != 0);
00252 return internal->matches_lower_bound;
00253 }
00254
00255 Xapian::doccount
00256 MSet::get_matches_estimated() const
00257 {
00258 Assert(internal.get() != 0);
00259 return internal->matches_estimated;
00260 }
00261
00262 Xapian::doccount
00263 MSet::get_matches_upper_bound() const
00264 {
00265 Assert(internal.get() != 0);
00266 return internal->matches_upper_bound;
00267 }
00268
00269 Xapian::weight
00270 MSet::get_max_possible() const
00271 {
00272 Assert(internal.get() != 0);
00273 return internal->max_possible;
00274 }
00275
00276 Xapian::weight
00277 MSet::get_max_attained() const
00278 {
00279 Assert(internal.get() != 0);
00280 return internal->max_attained;
00281 }
00282
00283 Xapian::doccount
00284 MSet::size() const
00285 {
00286 Assert(internal.get() != 0);
00287 return internal->items.size();
00288 }
00289
00290 bool
00291 MSet::empty() const
00292 {
00293 Assert(internal.get() != 0);
00294 return internal->items.empty();
00295 }
00296
00297 void
00298 MSet::swap(MSet & other)
00299 {
00300 std::swap(internal, other.internal);
00301 }
00302
00303 MSetIterator
00304 MSet::begin() const
00305 {
00306 return MSetIterator(0, *this);
00307 }
00308
00309 MSetIterator
00310 MSet::end() const
00311 {
00312 Assert(internal.get() != 0);
00313 return MSetIterator(internal->items.size(), *this);
00314 }
00315
00316 MSetIterator
00317 MSet::operator[](Xapian::doccount i) const
00318 {
00319
00320 Assert(0 < (i + 1) && i < size());
00321 return MSetIterator(i, *this);
00322 }
00323
00324 MSetIterator
00325 MSet::back() const
00326 {
00327 Assert(!empty());
00328 Assert(internal.get() != 0);
00329 return MSetIterator(internal->items.size() - 1, *this);
00330 }
00331
00332 string
00333 MSet::get_description() const
00334 {
00335 Assert(internal.get() != 0);
00336 return "Xapian::MSet(" + internal->get_description() + ")";
00337 }
00338
00339 percent
00340 MSet::Internal::convert_to_percent_internal(Xapian::weight wt) const
00341 {
00342 DEBUGAPICALL(Xapian::percent, "Xapian::MSet::Internal::convert_to_percent_internal", wt);
00343 if (percent_factor == 0) RETURN(100);
00344
00345
00346 double v = wt * percent_factor + 100.0 * DBL_EPSILON;
00347 Xapian::percent pcent = static_cast<Xapian::percent>(v);
00348 DEBUGLINE(API, "wt = " << wt << ", max_possible = "
00349 << max_possible << " => pcent = " << pcent);
00350 if (pcent > 100) pcent = 100;
00351 if (pcent < 0) pcent = 0;
00352 if (pcent == 0 && wt > 0) pcent = 1;
00353
00354 RETURN(pcent);
00355 }
00356
00357 Document
00358 MSet::Internal::get_doc_by_index(Xapian::doccount index) const
00359 {
00360 DEBUGCALL(API, Document, "Xapian::MSet::Internal::Data::get_doc_by_index",
00361 index);
00362 index += firstitem;
00363 map<Xapian::doccount, Document>::const_iterator doc;
00364 doc = indexeddocs.find(index);
00365 if (doc != indexeddocs.end()) {
00366 RETURN(doc->second);
00367 }
00368 if (index < firstitem || index >= firstitem + items.size()) {
00369 throw RangeError("The mset returned from the match does not contain the document at index " + om_tostring(index));
00370 }
00371 fetch_items(index, index);
00372
00373 read_docs();
00374 Assert(indexeddocs.find(index) != indexeddocs.end());
00375 Assert(indexeddocs.find(index)->first == index);
00376 RETURN(indexeddocs.find(index)->second);
00377 }
00378
00379 void
00380 MSet::Internal::fetch_items(Xapian::doccount first, Xapian::doccount last) const
00381 {
00382 DEBUGAPICALL(void, "Xapian::MSet::Internal::Data::fetch_items",
00383 first << ", " << last);
00384 if (enquire.get() == 0) {
00385 throw InvalidOperationError("Can't fetch documents from an MSet which is not derived from a query.");
00386 }
00387 for (Xapian::doccount i = first; i <= last; ++i) {
00388 map<Xapian::doccount, Document>::const_iterator doc;
00389 doc = indexeddocs.find(i);
00390 if (doc == indexeddocs.end()) {
00391
00392 set<Xapian::doccount>::const_iterator s;
00393 s = requested_docs.find(i);
00394 if (s == requested_docs.end()) {
00395
00396 enquire->request_doc(items[i - firstitem]);
00397 requested_docs.insert(i);
00398 }
00399 }
00400 }
00401 }
00402
00403 string
00404 MSet::Internal::get_description() const
00405 {
00406 string description = "Xapian::MSet::Internal(";
00407
00408 description += "firstitem=" + om_tostring(firstitem) + ", " +
00409 "matches_lower_bound=" + om_tostring(matches_lower_bound) + ", " +
00410 "matches_estimated=" + om_tostring(matches_estimated) + ", " +
00411 "matches_upper_bound=" + om_tostring(matches_upper_bound) + ", " +
00412 "max_possible=" + om_tostring(max_possible) + ", " +
00413 "max_attained=" + om_tostring(max_attained);
00414
00415 for (vector<Xapian::Internal::MSetItem>::const_iterator i = items.begin();
00416 i != items.end(); ++i) {
00417 if (!description.empty()) description += ", ";
00418 description += i->get_description();
00419 }
00420
00421 description += ")";
00422
00423 return description;
00424 }
00425
00426 void
00427 MSet::Internal::read_docs() const
00428 {
00429 set<Xapian::doccount>::const_iterator i;
00430 for (i = requested_docs.begin(); i != requested_docs.end(); ++i) {
00431 indexeddocs[*i] = enquire->read_doc(items[*i - firstitem]);
00432 DEBUGLINE(API, "stored doc at index " << *i << " is " << indexeddocs[*i]);
00433 }
00434
00435 requested_docs.clear();
00436 }
00437
00438
00439
00440 string
00441 Xapian::Internal::ESetItem::get_description() const
00442 {
00443 return "Xapian::Internal::ESetItem(" + tname + ", " + om_tostring(wt) + ")";
00444 }
00445
00446
00447
00448 ESet::ESet() : internal(new Internal()) { }
00449
00450 ESet::~ESet()
00451 {
00452 }
00453
00454 ESet::ESet(const ESet & other) : internal(other.internal)
00455 {
00456 }
00457
00458 void
00459 ESet::operator=(const ESet &other)
00460 {
00461 internal = other.internal;
00462 }
00463
00464 Xapian::termcount
00465 ESet::get_ebound() const
00466 {
00467 return internal->ebound;
00468 }
00469
00470 Xapian::termcount
00471 ESet::size() const
00472 {
00473 return internal->items.size();
00474 }
00475
00476 bool
00477 ESet::empty() const
00478 {
00479 return internal->items.empty();
00480 }
00481
00482 void
00483 ESet::swap(ESet & other)
00484 {
00485 std::swap(internal, other.internal);
00486 }
00487
00488 ESetIterator
00489 ESet::begin() const
00490 {
00491 return ESetIterator(0, *this);
00492 }
00493
00494 ESetIterator
00495 ESet::end() const
00496 {
00497 Assert(internal.get() != 0);
00498 return ESetIterator(internal->items.size(), *this);
00499 }
00500
00501 ESetIterator
00502 ESet::operator[](Xapian::termcount i) const
00503 {
00504
00505 Assert(0 < (i + 1) && i < size());
00506 return ESetIterator(i, *this);
00507 }
00508
00509 ESetIterator
00510 ESet::back() const
00511 {
00512 Assert(!empty());
00513 Assert(internal.get() != 0);
00514 return ESetIterator(internal->items.size() - 1, *this);
00515 }
00516
00517 string
00518 ESet::get_description() const
00519 {
00520 Assert(internal.get() != 0);
00521 return "Xapian::ESet(" + internal->get_description() + ")";
00522 }
00523
00525
00527
00528 string
00529 Xapian::ESet::Internal::get_description() const
00530 {
00531 string description = "ebound=" + om_tostring(ebound);
00532
00533 for (vector<Xapian::Internal::ESetItem>::const_iterator i = items.begin();
00534 i != items.end();
00535 i++) {
00536 description += ", " + i->get_description();
00537 }
00538
00539 return "Xapian::ESet::Internal(" + description + ")";
00540 }
00541
00542
00543
00544 const string &
00545 ESetIterator::operator *() const
00546 {
00547 return eset.internal->items[index].tname;
00548 }
00549
00550 Xapian::weight
00551 ESetIterator::get_weight() const
00552 {
00553 return eset.internal->items[index].wt;
00554 }
00555
00556 string
00557 ESetIterator::get_description() const
00558 {
00559 return "Xapian::ESetIterator(" + om_tostring(index) + ")";
00560 }
00561
00562
00563
00564 Xapian::docid
00565 MSetIterator::operator *() const
00566 {
00567 return mset.internal->items[index].did;
00568 }
00569
00570 Document
00571 MSetIterator::get_document() const
00572 {
00573 return mset.internal->get_doc_by_index(index);
00574 }
00575
00576 Xapian::weight
00577 MSetIterator::get_weight() const
00578 {
00579 return mset.internal->items[index].wt;
00580 }
00581
00582 std::string
00583 MSetIterator::get_collapse_key() const
00584 {
00585 return mset.internal->items[index].collapse_key;
00586 }
00587
00588 Xapian::doccount
00589 MSetIterator::get_collapse_count() const
00590 {
00591 return mset.internal->items[index].collapse_count;
00592 }
00593
00594 Xapian::percent
00595 MSetIterator::get_percent() const
00596 {
00597 DEBUGAPICALL(Xapian::percent, "MSetIterator::get_percent", "");
00598 RETURN(mset.internal->convert_to_percent_internal(get_weight()));
00599 }
00600
00601 string
00602 MSetIterator::get_description() const
00603 {
00604 return "Xapian::MSetIterator(" + om_tostring(index) + ")";
00605 }
00606
00607
00608
00609 Enquire::Internal::Internal(const Database &db_, ErrorHandler * errorhandler_)
00610 : db(db_), query(), collapse_key(Xapian::BAD_VALUENO),
00611 order(Enquire::ASCENDING), percent_cutoff(0), weight_cutoff(0),
00612 sort_key(Xapian::BAD_VALUENO), sort_by(REL), sort_value_forward(true),
00613 sorter(0), errorhandler(errorhandler_), weight(0)
00614 {
00615 if (db.internal.empty()) {
00616 throw InvalidArgumentError("Can't make an Enquire object from an uninitialised Database object.");
00617 }
00618 }
00619
00620 Enquire::Internal::~Internal()
00621 {
00622 delete weight;
00623 weight = 0;
00624 }
00625
00626 void
00627 Enquire::Internal::set_query(const Query &query_, termcount qlen_)
00628 {
00629 query = query_;
00630 qlen = qlen_ ? qlen_ : query.get_length();
00631 }
00632
00633 const Query &
00634 Enquire::Internal::get_query()
00635 {
00636 return query;
00637 }
00638
00639 MSet
00640 Enquire::Internal::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
00641 Xapian::doccount check_at_least, const RSet *rset,
00642 const MatchDecider *mdecider,
00643 const MatchDecider *matchspy) const
00644 {
00645 DEBUGCALL(API, MSet, "Enquire::Internal::get_mset", first << ", " <<
00646 maxitems << ", " << check_at_least << ", " << rset << ", " <<
00647 mdecider << ", " << matchspy);
00648
00649 if (percent_cutoff && (sort_by == VAL || sort_by == VAL_REL)) {
00650 throw Xapian::UnimplementedError("Use of a percentage cutoff while sorting primary by value isn't currently supported");
00651 }
00652
00653 if (weight == 0) {
00654 weight = new BM25Weight;
00655 }
00656
00657 {
00658 Xapian::doccount docs = db.get_doccount();
00659 maxitems = min(maxitems, docs);
00660 check_at_least = min(check_at_least, docs);
00661 check_at_least = max(check_at_least, maxitems);
00662 }
00663
00664 Stats stats;
00665 ::MultiMatch match(db, query.internal.get(), qlen, rset, collapse_key,
00666 percent_cutoff, weight_cutoff,
00667 order, sort_key, sort_by, sort_value_forward,
00668 errorhandler, stats, weight,
00669 (sorter != NULL),
00670 (mdecider != NULL || matchspy != NULL));
00671
00672 MSet retval;
00673 match.get_mset(first, maxitems, check_at_least, retval,
00674 stats, mdecider, matchspy, sorter);
00675
00676 Assert(weight->name() != "bool" || retval.get_max_possible() == 0);
00677
00678
00679
00680
00681
00682 retval.internal->enquire = this;
00683
00684 return retval;
00685 }
00686
00687 ESet
00688 Enquire::Internal::get_eset(Xapian::termcount maxitems,
00689 const RSet & rset, int flags, double k,
00690 const ExpandDecider * edecider) const
00691 {
00692 ESet retval;
00693
00694 OmExpand expand(db);
00695 RSetI rseti(db, rset);
00696
00697 DEBUGLINE(API, "rset size is " << rset.size());
00698
00699
00700
00701
00702 AutoPtr<ExpandDecider> decider_noquery;
00703 AutoPtr<ExpandDecider> decider_andnoquery;
00704
00705 if (!query.empty() && !(flags & Enquire::INCLUDE_QUERY_TERMS)) {
00706 AutoPtr<ExpandDecider> temp1(
00707 new ExpandDeciderFilterTerms(query.get_terms_begin(),
00708 query.get_terms_end()));
00709 decider_noquery = temp1;
00710
00711 if (edecider) {
00712 AutoPtr<ExpandDecider> temp2(
00713 new ExpandDeciderAnd(decider_noquery.get(), edecider));
00714 decider_andnoquery = temp2;
00715 edecider = decider_andnoquery.get();
00716 } else {
00717 edecider = decider_noquery.get();
00718 }
00719 }
00720
00721 expand.expand(maxitems, retval, &rseti, edecider,
00722 bool(flags & Enquire::USE_EXACT_TERMFREQ), k);
00723
00724 return retval;
00725 }
00726
00727 class ByQueryIndexCmp {
00728 private:
00729 typedef map<string, unsigned int> tmap_t;
00730 const tmap_t &tmap;
00731 public:
00732 ByQueryIndexCmp(const tmap_t &tmap_) : tmap(tmap_) {}
00733 bool operator()(const string &left,
00734 const string &right) const {
00735 tmap_t::const_iterator l, r;
00736 l = tmap.find(left);
00737 r = tmap.find(right);
00738 Assert((l != tmap.end()) && (r != tmap.end()));
00739
00740 return l->second < r->second;
00741 }
00742 };
00743
00744 TermIterator
00745 Enquire::Internal::get_matching_terms(Xapian::docid did) const
00746 {
00747 if (query.empty())
00748 throw Xapian::InvalidArgumentError("get_matching_terms with empty query");
00749
00750
00751
00752 TermIterator qt = query.get_terms_begin();
00753 TermIterator qt_end = query.get_terms_end();
00754
00755
00756
00757
00758 map<string, unsigned int> tmap;
00759 unsigned int index = 1;
00760 for ( ; qt != qt_end; qt++) {
00761 if (tmap.find(*qt) == tmap.end())
00762 tmap[*qt] = index++;
00763 }
00764
00765 vector<string> matching_terms;
00766
00767 TermIterator docterms = db.termlist_begin(did);
00768 TermIterator docterms_end = db.termlist_end(did);
00769 while (docterms != docterms_end) {
00770 string term = *docterms;
00771 map<string, unsigned int>::iterator t = tmap.find(term);
00772 if (t != tmap.end()) matching_terms.push_back(term);
00773 docterms++;
00774 }
00775
00776
00777 sort(matching_terms.begin(), matching_terms.end(), ByQueryIndexCmp(tmap));
00778
00779 return TermIterator(new VectorTermList(matching_terms.begin(),
00780 matching_terms.end()));
00781 }
00782
00783 TermIterator
00784 Enquire::Internal::get_matching_terms(const MSetIterator &it) const
00785 {
00786
00787
00788 return get_matching_terms(*it);
00789 }
00790
00791 string
00792 Enquire::Internal::get_description() const
00793 {
00794 string description = db.get_description();
00795 description += ", ";
00796 description += query.get_description();
00797 return description;
00798 }
00799
00800
00801
00802 void
00803 Enquire::Internal::request_doc(const Xapian::Internal::MSetItem &item) const
00804 {
00805 try {
00806 unsigned int multiplier = db.internal.size();
00807
00808 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
00809 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
00810
00811 db.internal[dbnumber]->request_document(realdid);
00812 } catch (Error & e) {
00813 if (errorhandler) (*errorhandler)(e);
00814 throw;
00815 }
00816 }
00817
00818 Document
00819 Enquire::Internal::read_doc(const Xapian::Internal::MSetItem &item) const
00820 {
00821 try {
00822 unsigned int multiplier = db.internal.size();
00823
00824 Xapian::docid realdid = (item.did - 1) / multiplier + 1;
00825 Xapian::doccount dbnumber = (item.did - 1) % multiplier;
00826
00827 Xapian::Document::Internal *doc;
00828 doc = db.internal[dbnumber]->collect_document(realdid);
00829 return Document(doc);
00830 } catch (Error & e) {
00831 if (errorhandler) (*errorhandler)(e);
00832 throw;
00833 }
00834 }
00835
00836 void
00837 Enquire::Internal::register_match_decider(const string &,
00838 const MatchDecider *)
00839 {
00840 }
00841
00842
00843
00844 Enquire::Enquire(const Enquire & other) : internal(other.internal)
00845 {
00846 DEBUGAPICALL(void, "Xapian::Enquire::Enquire", other);
00847 }
00848
00849 void
00850 Enquire::operator=(const Enquire & other)
00851 {
00852 DEBUGAPICALL(void, "Xapian::Enquire::operator=", other);
00853 internal = other.internal;
00854 }
00855
00856 Enquire::Enquire(const Database &databases, ErrorHandler * errorhandler)
00857 : internal(new Internal(databases, errorhandler))
00858 {
00859 DEBUGAPICALL(void, "Xapian::Enquire::Enquire", databases);
00860 }
00861
00862 Enquire::~Enquire()
00863 {
00864 DEBUGAPICALL(void, "Xapian::Enquire::~Enquire", "");
00865 }
00866
00867 void
00868 Enquire::set_query(const Query & query, termcount len)
00869 {
00870 DEBUGAPICALL(void, "Xapian::Enquire::set_query", query << ", " << len);
00871 internal->set_query(query, len);
00872 }
00873
00874 const Query &
00875 Enquire::get_query() const
00876 {
00877 DEBUGAPICALL(const Xapian::Query &, "Xapian::Enquire::get_query", "");
00878 try {
00879 RETURN(internal->get_query());
00880 } catch (Error & e) {
00881 if (internal->errorhandler) (*internal->errorhandler)(e);
00882 throw;
00883 }
00884 }
00885
00886 void
00887 Enquire::set_weighting_scheme(const Weight &weight_)
00888 {
00889 DEBUGAPICALL(void, "Xapian::Enquire::set_weighting_scheme", "[Weight]");
00890 delete internal->weight;
00891 internal->weight = weight_.clone();
00892 }
00893
00894 void
00895 Enquire::set_collapse_key(Xapian::valueno collapse_key)
00896 {
00897 internal->collapse_key = collapse_key;
00898 }
00899
00900 void
00901 Enquire::set_docid_order(Enquire::docid_order order)
00902 {
00903 internal->order = order;
00904 }
00905
00906 void
00907 Enquire::set_cutoff(Xapian::percent percent_cutoff, Xapian::weight weight_cutoff)
00908 {
00909 internal->percent_cutoff = percent_cutoff;
00910 internal->weight_cutoff = weight_cutoff;
00911 }
00912
00913 void
00914 Enquire::set_sort_by_relevance()
00915 {
00916 internal->sort_by = Internal::REL;
00917 }
00918
00919 void
00920 Enquire::set_sort_by_value(Xapian::valueno sort_key, bool ascending)
00921 {
00922 internal->sorter = NULL;
00923 internal->sort_key = sort_key;
00924 internal->sort_by = Internal::VAL;
00925 internal->sort_value_forward = ascending;
00926 }
00927
00928 void
00929 Enquire::set_sort_by_value_then_relevance(Xapian::valueno sort_key,
00930 bool ascending)
00931 {
00932 internal->sorter = NULL;
00933 internal->sort_key = sort_key;
00934 internal->sort_by = Internal::VAL_REL;
00935 internal->sort_value_forward = ascending;
00936 }
00937
00938 void
00939 Enquire::set_sort_by_relevance_then_value(Xapian::valueno sort_key,
00940 bool ascending)
00941 {
00942 internal->sorter = NULL;
00943 internal->sort_key = sort_key;
00944 internal->sort_by = Internal::REL_VAL;
00945 internal->sort_value_forward = ascending;
00946 }
00947
00948 void
00949 Enquire::set_sort_by_key(Xapian::Sorter * sorter, bool ascending)
00950 {
00951 if (sorter == NULL)
00952 throw Xapian::InvalidArgumentError("sorter can't be NULL");
00953 internal->sorter = sorter;
00954 internal->sort_by = Internal::VAL;
00955 internal->sort_value_forward = ascending;
00956 }
00957
00958 void
00959 Enquire::set_sort_by_key_then_relevance(Xapian::Sorter * sorter, bool ascending)
00960 {
00961 if (sorter == NULL)
00962 throw Xapian::InvalidArgumentError("sorter can't be NULL");
00963 internal->sorter = sorter;
00964 internal->sort_by = Internal::VAL_REL;
00965 internal->sort_value_forward = ascending;
00966 }
00967
00968 void
00969 Enquire::set_sort_by_relevance_then_key(Xapian::Sorter * sorter, bool ascending)
00970 {
00971 if (sorter == NULL)
00972 throw Xapian::InvalidArgumentError("sorter can't be NULL");
00973 internal->sorter = sorter;
00974 internal->sort_by = Internal::REL_VAL;
00975 internal->sort_value_forward = ascending;
00976 }
00977
00978 MSet
00979 Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
00980 Xapian::doccount check_at_least, const RSet *rset,
00981 const MatchDecider *mdecider) const
00982 {
00983 return get_mset(first, maxitems, check_at_least, rset, mdecider, NULL);
00984 }
00985
00986 MSet
00987 Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
00988 Xapian::doccount check_at_least, const RSet *rset,
00989 const MatchDecider *mdecider,
00990 const MatchDecider *matchspy) const
00991 {
00992
00993 DEBUGAPICALL(Xapian::MSet, "Xapian::Enquire::get_mset", first << ", " <<
00994 maxitems << ", " << check_at_least << ", " << rset << ", " <<
00995 mdecider << ", " << matchspy);
00996
00997 try {
00998 RETURN(internal->get_mset(first, maxitems, check_at_least, rset,
00999 mdecider, matchspy));
01000 } catch (Error & e) {
01001 if (internal->errorhandler) (*internal->errorhandler)(e);
01002 throw;
01003 }
01004 }
01005
01006 ESet
01007 Enquire::get_eset(Xapian::termcount maxitems, const RSet & rset, int flags,
01008 double k, const ExpandDecider * edecider) const
01009 {
01010
01011
01012 DEBUGAPICALL(Xapian::ESet, "Xapian::Enquire::get_eset", maxitems << ", " <<
01013 rset << ", " << flags << ", " << k << ", " << edecider);
01014
01015 try {
01016
01017 RETURN(internal->get_eset(maxitems, rset, flags, k, edecider));
01018 } catch (Error & e) {
01019 if (internal->errorhandler) (*internal->errorhandler)(e);
01020 throw;
01021 }
01022 }
01023
01024 TermIterator
01025 Enquire::get_matching_terms_begin(const MSetIterator &it) const
01026 {
01027 DEBUGAPICALL(Xapian::TermIterator, "Xapian::Enquire::get_matching_terms", it);
01028 try {
01029 RETURN(internal->get_matching_terms(it));
01030 } catch (Error & e) {
01031 if (internal->errorhandler) (*internal->errorhandler)(e);
01032 throw;
01033 }
01034 }
01035
01036 TermIterator
01037 Enquire::get_matching_terms_begin(Xapian::docid did) const
01038 {
01039 DEBUGAPICALL(Xapian::TermIterator, "Xapian::Enquire::get_matching_terms", did);
01040 try {
01041 RETURN(internal->get_matching_terms(did));
01042 } catch (Error & e) {
01043 if (internal->errorhandler) (*internal->errorhandler)(e);
01044 throw;
01045 }
01046 }
01047
01048 void
01049 Enquire::register_match_decider(const string &name,
01050 const MatchDecider *mdecider)
01051 {
01052 internal->register_match_decider(name, mdecider);
01053 }
01054
01055 string
01056 Enquire::get_description() const
01057 {
01058 return "Xapian::Enquire(" + internal->get_description() + ")";
01059 }
01060
01061 }