api/omenquire.cc

Go to the documentation of this file.
00001 /* omenquire.cc: External interface for running queries
00002  *
00003  * Copyright 1999,2000,2001 BrightStation PLC
00004  * Copyright 2001,2002 Ananova Ltd
00005  * Copyright 2002,2003,2004,2005,2006,2007,2008 Olly Betts
00006  * Copyright 2007 Lemur Consulting Ltd
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of the
00011  * License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
00021  * USA
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 // Methods for Xapian::RSet
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 // Methods for Xapian::MSetItem
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 // Methods for Xapian::MSet
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     // Don't test 0 <= i - that gives a compiler warning if i is unsigned
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     // Excess precision on x86 can result in a difference here.
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); // FIXME: this checks indexeddocs AGAIN!
00372     /* Actually read the fetched documents */
00373     read_docs();
00374     Assert(indexeddocs.find(index) != indexeddocs.end());
00375     Assert(indexeddocs.find(index)->first == index); // Paranoid assert
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             /* We don't have the document cached */
00392             set<Xapian::doccount>::const_iterator s;
00393             s = requested_docs.find(i);
00394             if (s == requested_docs.end()) {
00395                 /* We haven't even requested it yet - do so now. */
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     /* Clear list of requested but not fetched documents. */
00435     requested_docs.clear();
00436 }
00437 
00438 // Methods for Xapian::Internal::ESetItem
00439 
00440 string
00441 Xapian::Internal::ESetItem::get_description() const
00442 {
00443     return "Xapian::Internal::ESetItem(" + tname + ", " + om_tostring(wt) + ")";
00444 }
00445 
00446 // Methods for Xapian::ESet
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     // Don't test 0 <= i - that gives a compiler warning if i is unsigned
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 // Methods for Xapian::ESet::Internal //
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 // Xapian::ESetIterator
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 // MSetIterator
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 // Methods for Xapian::Enquire::Internal
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 (weight == 0) {
00650         weight = new BM25Weight;
00651     }
00652 
00653     Stats stats;
00654     ::MultiMatch match(db, query.internal.get(), qlen, rset, collapse_key,
00655                        percent_cutoff, weight_cutoff,
00656                        order, sort_key, sort_by, sort_value_forward, sorter,
00657                        errorhandler, stats, weight);
00658     // Run query and put results into supplied Xapian::MSet object.
00659     MSet retval;
00660     match.get_mset(first, maxitems, check_at_least, retval,
00661                    stats, mdecider, matchspy);
00662 
00663     Assert(weight->name() != "bool" || retval.get_max_possible() == 0);
00664 
00665     // The Xapian::MSet needs to have a pointer to ourselves, so that it can
00666     // retrieve the documents.  This is set here explicitly to avoid having
00667     // to pass it into the matcher, which gets messy particularly in the
00668     // networked case.
00669     retval.internal->enquire = this;
00670 
00671     return retval;
00672 }
00673 
00674 ESet
00675 Enquire::Internal::get_eset(Xapian::termcount maxitems,
00676                     const RSet & rset, int flags, double k,
00677                     const ExpandDecider * edecider) const
00678 {
00679     ESet retval;
00680 
00681     OmExpand expand(db);
00682     RSetI rseti(db, rset);
00683 
00684     DEBUGLINE(API, "rset size is " << rset.size());
00685 
00686     /* The AutoPtrs will clean up any dynamically allocated
00687      * expand deciders automatically.
00688      */
00689     AutoPtr<ExpandDecider> decider_noquery;
00690     AutoPtr<ExpandDecider> decider_andnoquery;
00691 
00692     if (!query.empty() && !(flags & Enquire::INCLUDE_QUERY_TERMS)) {
00693         AutoPtr<ExpandDecider> temp1(
00694             new ExpandDeciderFilterTerms(query.get_terms_begin(),
00695                                          query.get_terms_end()));
00696         decider_noquery = temp1;
00697 
00698         if (edecider) {
00699             AutoPtr<ExpandDecider> temp2(
00700                 new ExpandDeciderAnd(decider_noquery.get(), edecider));
00701             decider_andnoquery = temp2;
00702             edecider = decider_andnoquery.get();
00703         } else {
00704             edecider = decider_noquery.get();
00705         }
00706     }
00707 
00708     expand.expand(maxitems, retval, &rseti, edecider,
00709                   bool(flags & Enquire::USE_EXACT_TERMFREQ), k);
00710 
00711     return retval;
00712 }
00713 
00714 class ByQueryIndexCmp {
00715  private:
00716     typedef map<string, unsigned int> tmap_t;
00717     const tmap_t &tmap;
00718  public:
00719     ByQueryIndexCmp(const tmap_t &tmap_) : tmap(tmap_) {}
00720     bool operator()(const string &left,
00721                     const string &right) const {
00722         tmap_t::const_iterator l, r;
00723         l = tmap.find(left);
00724         r = tmap.find(right);
00725         Assert((l != tmap.end()) && (r != tmap.end()));
00726 
00727         return l->second < r->second;
00728     }
00729 };
00730 
00731 TermIterator
00732 Enquire::Internal::get_matching_terms(Xapian::docid did) const
00733 {
00734     if (query.empty())
00735         throw Xapian::InvalidArgumentError("get_matching_terms with empty query");
00736         //return TermIterator(NULL);
00737 
00738     // The ordered list of terms in the query.
00739     TermIterator qt = query.get_terms_begin();
00740     TermIterator qt_end = query.get_terms_end();
00741 
00742     // copy the list of query terms into a map for faster access.
00743     // FIXME: a hash would be faster than a map, if this becomes
00744     // a problem.
00745     map<string, unsigned int> tmap;
00746     unsigned int index = 1;
00747     for ( ; qt != qt_end; qt++) {
00748         if (tmap.find(*qt) == tmap.end())
00749             tmap[*qt] = index++;
00750     }
00751 
00752     vector<string> matching_terms;
00753 
00754     TermIterator docterms = db.termlist_begin(did);
00755     TermIterator docterms_end = db.termlist_end(did);
00756     while (docterms != docterms_end) {
00757         string term = *docterms;
00758         map<string, unsigned int>::iterator t = tmap.find(term);
00759         if (t != tmap.end()) matching_terms.push_back(term);
00760         docterms++;
00761     }
00762 
00763     // sort the resulting list by query position.
00764     sort(matching_terms.begin(), matching_terms.end(), ByQueryIndexCmp(tmap));
00765 
00766     return TermIterator(new VectorTermList(matching_terms.begin(),
00767                                            matching_terms.end()));
00768 }
00769 
00770 TermIterator
00771 Enquire::Internal::get_matching_terms(const MSetIterator &it) const
00772 {
00773     // FIXME: take advantage of MSetIterator to ensure that database
00774     // doesn't get modified underneath us.
00775     return get_matching_terms(*it);
00776 }
00777 
00778 string
00779 Enquire::Internal::get_description() const
00780 {
00781     string description = db.get_description();
00782     description += ", ";
00783     description += query.get_description();
00784     return description;
00785 }
00786 
00787 // Private methods for Xapian::Enquire::Internal
00788 
00789 void
00790 Enquire::Internal::request_doc(const Xapian::Internal::MSetItem &item) const
00791 {
00792     try {
00793         unsigned int multiplier = db.internal.size();
00794 
00795         Xapian::docid realdid = (item.did - 1) / multiplier + 1;
00796         Xapian::doccount dbnumber = (item.did - 1) % multiplier;
00797 
00798         db.internal[dbnumber]->request_document(realdid);
00799     } catch (Error & e) {
00800         if (errorhandler) (*errorhandler)(e);
00801         throw;
00802     }
00803 }
00804 
00805 Document
00806 Enquire::Internal::read_doc(const Xapian::Internal::MSetItem &item) const
00807 {
00808     try {
00809         unsigned int multiplier = db.internal.size();
00810 
00811         Xapian::docid realdid = (item.did - 1) / multiplier + 1;
00812         Xapian::doccount dbnumber = (item.did - 1) % multiplier;
00813 
00814         Xapian::Document::Internal *doc;
00815         doc = db.internal[dbnumber]->collect_document(realdid);
00816         return Document(doc);
00817     } catch (Error & e) {
00818         if (errorhandler) (*errorhandler)(e);
00819         throw;
00820     }
00821 }
00822 
00823 void
00824 Enquire::Internal::register_match_decider(const string &,
00825         const MatchDecider *)
00826 {
00827 }
00828 
00829 // Methods of Xapian::Enquire
00830 
00831 Enquire::Enquire(const Enquire & other) : internal(other.internal)
00832 {
00833     DEBUGAPICALL(void, "Xapian::Enquire::Enquire", other);
00834 }
00835 
00836 void
00837 Enquire::operator=(const Enquire & other)
00838 {
00839     DEBUGAPICALL(void, "Xapian::Enquire::operator=", other);
00840     internal = other.internal;
00841 }
00842 
00843 Enquire::Enquire(const Database &databases, ErrorHandler * errorhandler)
00844     : internal(new Internal(databases, errorhandler))
00845 {
00846     DEBUGAPICALL(void, "Xapian::Enquire::Enquire", databases);
00847 }
00848 
00849 Enquire::~Enquire()
00850 {
00851     DEBUGAPICALL(void, "Xapian::Enquire::~Enquire", "");
00852 }
00853 
00854 void
00855 Enquire::set_query(const Query & query, termcount len)
00856 {
00857     DEBUGAPICALL(void, "Xapian::Enquire::set_query", query << ", " << len);
00858     internal->set_query(query, len);
00859 }
00860 
00861 const Query &
00862 Enquire::get_query() const
00863 {
00864     DEBUGAPICALL(const Xapian::Query &, "Xapian::Enquire::get_query", "");
00865     try {
00866         RETURN(internal->get_query());
00867     } catch (Error & e) {
00868         if (internal->errorhandler) (*internal->errorhandler)(e);
00869         throw;
00870     }
00871 }
00872 
00873 void
00874 Enquire::set_weighting_scheme(const Weight &weight_)
00875 {
00876     DEBUGAPICALL(void, "Xapian::Enquire::set_weighting_scheme", "[Weight]");
00877     delete internal->weight;
00878     internal->weight = weight_.clone();
00879 }
00880 
00881 void
00882 Enquire::set_collapse_key(Xapian::valueno collapse_key)
00883 {
00884     internal->collapse_key = collapse_key;
00885 }
00886 
00887 void
00888 Enquire::set_docid_order(Enquire::docid_order order)
00889 {
00890     internal->order = order;
00891 }
00892 
00893 void
00894 Enquire::set_cutoff(Xapian::percent percent_cutoff, Xapian::weight weight_cutoff)
00895 {
00896     internal->percent_cutoff = percent_cutoff;
00897     internal->weight_cutoff = weight_cutoff;
00898 }
00899 
00900 void
00901 Enquire::set_sort_by_relevance()
00902 {
00903     internal->sort_by = Internal::REL;
00904 }
00905 
00906 void
00907 Enquire::set_sort_by_value(Xapian::valueno sort_key, bool ascending)
00908 {
00909     internal->sorter = NULL;
00910     internal->sort_key = sort_key;
00911     internal->sort_by = Internal::VAL;
00912     internal->sort_value_forward = ascending;
00913 }
00914 
00915 void
00916 Enquire::set_sort_by_value_then_relevance(Xapian::valueno sort_key,
00917                                           bool ascending)
00918 {
00919     internal->sorter = NULL;
00920     internal->sort_key = sort_key;
00921     internal->sort_by = Internal::VAL_REL;
00922     internal->sort_value_forward = ascending;
00923 }
00924 
00925 void
00926 Enquire::set_sort_by_relevance_then_value(Xapian::valueno sort_key,
00927                                           bool ascending)
00928 {
00929     internal->sorter = NULL;
00930     internal->sort_key = sort_key;
00931     internal->sort_by = Internal::REL_VAL;
00932     internal->sort_value_forward = ascending;
00933 }
00934 
00935 void
00936 Enquire::set_sort_by_key(Xapian::Sorter * sorter, bool ascending)
00937 {
00938     if (sorter == NULL)
00939         throw Xapian::InvalidArgumentError("sorter can't be NULL");
00940     internal->sorter = sorter;
00941     internal->sort_by = Internal::VAL;
00942     internal->sort_value_forward = ascending;
00943 }
00944 
00945 void
00946 Enquire::set_sort_by_key_then_relevance(Xapian::Sorter * sorter, bool ascending)
00947 {
00948     if (sorter == NULL)
00949         throw Xapian::InvalidArgumentError("sorter can't be NULL");
00950     internal->sorter = sorter;
00951     internal->sort_by = Internal::VAL_REL;
00952     internal->sort_value_forward = ascending;
00953 }
00954 
00955 void
00956 Enquire::set_sort_by_relevance_then_key(Xapian::Sorter * sorter, bool ascending)
00957 {
00958     if (sorter == NULL)
00959         throw Xapian::InvalidArgumentError("sorter can't be NULL");
00960     internal->sorter = sorter;
00961     internal->sort_by = Internal::REL_VAL;
00962     internal->sort_value_forward = ascending;
00963 }
00964 
00965 MSet
00966 Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
00967                   Xapian::doccount check_at_least, const RSet *rset,
00968                   const MatchDecider *mdecider) const
00969 {
00970     return get_mset(first, maxitems, check_at_least, rset, mdecider, NULL);
00971 }
00972 
00973 MSet
00974 Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
00975                   Xapian::doccount check_at_least, const RSet *rset,
00976                   const MatchDecider *mdecider,
00977                   const MatchDecider *matchspy) const
00978 {
00979     // FIXME: display contents of pointer params, if they're not null.
00980     DEBUGAPICALL(Xapian::MSet, "Xapian::Enquire::get_mset", first << ", " <<
00981                  maxitems << ", " << check_at_least << ", " << rset << ", " <<
00982                  mdecider << ", " << matchspy);
00983 
00984     try {
00985         RETURN(internal->get_mset(first, maxitems, check_at_least, rset,
00986                                   mdecider, matchspy));
00987     } catch (Error & e) {
00988         if (internal->errorhandler) (*internal->errorhandler)(e);
00989         throw;
00990     }
00991 }
00992 
00993 ESet
00994 Enquire::get_eset(Xapian::termcount maxitems, const RSet & rset, int flags,
00995                     double k, const ExpandDecider * edecider) const
00996 {
00997     // FIXME: display contents of pointer params and rset, if they're not
00998     // null.
00999     DEBUGAPICALL(Xapian::ESet, "Xapian::Enquire::get_eset", maxitems << ", " <<
01000                  rset << ", " << flags << ", " << k << ", " << edecider);
01001 
01002     try {
01003         // FIXME: this copies the eset too much: pass it in by reference?
01004         RETURN(internal->get_eset(maxitems, rset, flags, k, edecider));
01005     } catch (Error & e) {
01006         if (internal->errorhandler) (*internal->errorhandler)(e);
01007         throw;
01008     }
01009 }
01010 
01011 TermIterator
01012 Enquire::get_matching_terms_begin(const MSetIterator &it) const
01013 {
01014     DEBUGAPICALL(Xapian::TermIterator, "Xapian::Enquire::get_matching_terms", it);
01015     try {
01016         RETURN(internal->get_matching_terms(it));
01017     } catch (Error & e) {
01018         if (internal->errorhandler) (*internal->errorhandler)(e);
01019         throw;
01020     }
01021 }
01022 
01023 TermIterator
01024 Enquire::get_matching_terms_begin(Xapian::docid did) const
01025 {
01026     DEBUGAPICALL(Xapian::TermIterator, "Xapian::Enquire::get_matching_terms", did);
01027     try {
01028         RETURN(internal->get_matching_terms(did));
01029     } catch (Error & e) {
01030         if (internal->errorhandler) (*internal->errorhandler)(e);
01031         throw;
01032     }
01033 }
01034 
01035 void
01036 Enquire::register_match_decider(const string &name,
01037                                   const MatchDecider *mdecider)
01038 {
01039     internal->register_match_decider(name, mdecider);
01040 }
01041 
01042 string
01043 Enquire::get_description() const
01044 {
01045     return "Xapian::Enquire(" + internal->get_description() + ")";
01046 }
01047 
01048 }

Documentation for Xapian (version 1.0.10).
Generated on 24 Dec 2008 by Doxygen 1.5.2.