Ticket #394: phrase-settling-pond.patch
File phrase-settling-pond.patch, 23.3 KB (added by , 15 years ago) |
---|
-
matcher/Makefile.mk
3 3 matcher/andnotpostlist.h\ 4 4 matcher/branchpostlist.h\ 5 5 matcher/collapser.h\ 6 matcher/exactphrasecheck.h\ 6 7 matcher/exactphrasepostlist.h\ 7 8 matcher/externalpostlist.h\ 8 9 matcher/extraweightpostlist.h\ … … 38 39 matcher/andnotpostlist.cc\ 39 40 matcher/branchpostlist.cc\ 40 41 matcher/collapser.cc\ 42 matcher/exactphrasecheck.cc\ 41 43 matcher/exactphrasepostlist.cc\ 42 44 matcher/externalpostlist.cc\ 43 45 matcher/localmatch.cc\ -
matcher/exactphrasecheck.cc
1 /** @file exactphrasecheck.cc 2 * @brief Check if terms form a particular exact phrase. 3 */ 4 /* Copyright (C) 2006,2007,2009 Olly Betts 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 // FIXME: this could probably share code with ExactPhrasePostList. 22 23 #include <config.h> 24 25 #include "exactphrasecheck.h" 26 #include "positionlist.h" 27 #include "postlist.h" 28 #include "omassert.h" 29 #include "omdebug.h" 30 31 #include <algorithm> 32 #include <vector> 33 34 using namespace std; 35 36 namespace { 37 38 class TermCompare { 39 const Xapian::Database & db; 40 vector<string> & terms; 41 42 public: 43 TermCompare(const Xapian::Database & db_, 44 vector<string> & terms_) 45 : db(db_), terms(terms_) { } 46 47 bool operator()(unsigned a, unsigned b) const { 48 return db.get_collection_freq(terms[a]) < db.get_collection_freq(terms[b]); 49 } 50 }; 51 52 } 53 54 ExactPhraseCheck::ExactPhraseCheck(const Xapian::Database & db_, 55 const vector<string> &terms_) 56 : db(db_), terms(terms_) 57 { 58 if (terms.empty()) { 59 poslists = NULL; 60 order = NULL; 61 return; 62 } 63 64 AssertRel(terms.size(),>,1); 65 size_t n = terms_.size(); 66 poslists = new PositionList*[n]; 67 try { 68 order = new unsigned[n]; 69 } catch (...) { 70 delete [] poslists; 71 throw; 72 } 73 for (size_t i = 0; i < n; ++i) { 74 poslists[i] = NULL; 75 order[i] = unsigned(i); 76 } 77 78 // We often don't need to read all the position lists, so rather than using 79 // the shortest position lists first, we approximate by using the terms 80 // with the lowest collection freq first. Overall this should give a 81 // similar order. 82 sort(order, order + terms.size(), TermCompare(db, terms)); 83 } 84 85 ExactPhraseCheck::~ExactPhraseCheck() 86 { 87 delete [] poslists; 88 delete [] order; 89 } 90 91 bool 92 ExactPhraseCheck::start_position_list(unsigned i, Xapian::docid did) 93 { 94 AssertRel(i,<,terms.size()); 95 unsigned index = order[i]; 96 // FIXME: nasty hacking around with internals and refcount - we should 97 // just add a new Databse::Internal method to do what we want. 98 Xapian::PositionIterator p = db.positionlist_begin(did, terms[index]); 99 PositionList * tmp = p.internal.get(); 100 if (!tmp) 101 return false; 102 ++tmp->ref_count; 103 p.internal = poslists[i]; 104 poslists[i] = tmp; 105 poslists[i]->index = index; 106 return true; 107 } 108 109 bool 110 ExactPhraseCheck::operator()(Xapian::docid did) 111 { 112 DEBUGCALL(MATCH, bool, "ExactPhraseCheck::operator()", did); 113 114 AssertRel(terms.size(),>,1); 115 116 bool result = false; 117 // If the first term we check only occurs too close to the start of the 118 // document, we only need to read one term's positions. E.g. search for 119 // "ripe mango" when the only occurrence of 'mango' in the current document 120 // is at position 0. 121 if (!start_position_list(0, did)) 122 goto done; 123 poslists[0]->skip_to(poslists[0]->index); 124 if (poslists[0]->at_end()) goto done; 125 126 // If we get here, we'll need to read the positionlists for at least two 127 // terms, so check the true positionlist length for the two terms with the 128 // lowest wdf and if necessary swap them so the true shorter one is first. 129 if (!start_position_list(1, did)) 130 goto done; 131 if (poslists[0]->get_size() < poslists[1]->get_size()) { 132 poslists[1]->skip_to(poslists[1]->index); 133 if (poslists[1]->at_end()) goto done; 134 swap(poslists[0], poslists[1]); 135 } 136 137 { 138 unsigned read_hwm = 1; 139 Xapian::termpos idx0 = poslists[0]->index; 140 do { 141 Xapian::termpos base = poslists[0]->get_position() - idx0; 142 unsigned i = 1; 143 while (true) { 144 if (i > read_hwm) { 145 read_hwm = i; 146 if (!start_position_list(i, did)) 147 goto done; 148 // FIXME: consider comparing with poslist[0] and swapping 149 // if less common. Should we allow for the number of positions 150 // we've read from poslist[0] already? 151 } 152 Xapian::termpos required = base + poslists[i]->index; 153 poslists[i]->skip_to(required); 154 if (poslists[i]->at_end()) goto done; 155 if (poslists[i]->get_position() != required) break; 156 if (++i == terms.size()) { 157 result = true; 158 goto done; 159 } 160 } 161 poslists[0]->next(); 162 } while (!poslists[0]->at_end()); 163 } 164 done: 165 for (size_t i = 0; i < terms.size(); ++i) { 166 delete poslists[i]; 167 poslists[i] = NULL; 168 } 169 RETURN(result); 170 } -
matcher/multimatch.cc
46 46 47 47 #include "weightinternal.h" 48 48 49 #include "exactphrasecheck.h" 50 49 51 #include <xapian/errorhandler.h> 50 52 #include <xapian/matchspy.h> 51 53 #include <xapian/version.h> // For XAPIAN_HAS_REMOTE_BACKEND … … 356 358 map<string, Xapian::MSet::Internal::TermFreqAndWeight> * termfreqandwts_ptr; 357 359 termfreqandwts_ptr = &termfreqandwts; 358 360 361 vector<string> pool_terms; 359 362 Xapian::termcount total_subqs = 0; 360 363 // Keep a count of matches which we know exist, but we won't see. This 361 364 // occurs when a submatch is remote, and returns a lower bound on the … … 365 368 for (size_t i = 0; i != leaves.size(); ++i) { 366 369 PostList *pl; 367 370 try { 371 if (!is_remote[i]) pool_terms.clear(); 368 372 pl = leaves[i]->get_postlist_and_term_info(this, 369 373 termfreqandwts_ptr, 370 &total_subqs); 374 &total_subqs, 375 pool_terms); 371 376 if (termfreqandwts_ptr && !termfreqandwts.empty()) 372 377 termfreqandwts_ptr = NULL; 373 378 if (is_remote[i]) { … … 522 527 // Is the mset a valid heap? 523 528 bool is_heap = false; 524 529 530 size_t SETTLING_POND_SIZE = 0; 531 if (!pool_terms.empty()) { 532 const char * sps = getenv("POND_SIZE"); 533 SETTLING_POND_SIZE = sps ? atoi(sps) : 100000; 534 } 535 ExactPhraseCheck phrase_check(db, pool_terms); 536 // FIXME: a min/max heap is probably a better choice here (notably more 537 // compact) but the STL doesn't provide one so we'd have to find an 538 // implementation or write one. 539 multimap<Xapian::weight, Xapian::Internal::MSetItem> settling_pond; 525 540 while (true) { 526 541 bool pushback; 527 542 … … 649 664 new_item.wt = wt; 650 665 } 651 666 667 if (SETTLING_POND_SIZE) { 668 if (items.size() >= max_msize) { 669 // Settling pond handling... 670 multimap<Xapian::weight, Xapian::Internal::MSetItem>::iterator it; 671 it = settling_pond.upper_bound(-min_weight); 672 settling_pond.erase(it, settling_pond.end()); 673 674 settling_pond.insert(make_pair(-new_item.wt, new_item)); 675 if (settling_pond.size() < SETTLING_POND_SIZE) { 676 continue; 677 } 678 679 // Take the last item off the heap, which will have a reasonably 680 // high weight in general. 681 it = settling_pond.begin(); 682 swap(new_item, it->second); 683 settling_pond.erase(it); 684 } 685 if (!phrase_check(new_item.did)) continue; 686 } 687 652 688 pushback = true; 653 689 654 690 // Perform collapsing on key if requested. … … 811 847 } 812 848 } 813 849 850 multimap<Xapian::weight, Xapian::Internal::MSetItem>::iterator it; 851 for (it = settling_pond.begin(); it != settling_pond.end(); ++it) { 852 const Xapian::Internal::MSetItem & new_item = it->second; 853 if (new_item.wt < min_weight) break; 854 if (!phrase_check(new_item.did)) continue; 855 856 { 857 ++docs_matched; 858 if (items.size() >= max_msize) { 859 items.push_back(new_item); 860 if (!is_heap) { 861 is_heap = true; 862 make_heap(items.begin(), items.end(), mcmp); 863 } else { 864 push_heap<vector<Xapian::Internal::MSetItem>::iterator, 865 MSetCmp>(items.begin(), items.end(), mcmp); 866 } 867 pop_heap<vector<Xapian::Internal::MSetItem>::iterator, 868 MSetCmp>(items.begin(), items.end(), mcmp); 869 items.pop_back(); 870 871 min_item = items.front(); 872 if (sort_by == REL || sort_by == REL_VAL) { 873 if (docs_matched >= check_at_least) { 874 if (sort_by == REL) { 875 // We're done if this is a forward boolean match 876 // with only one database (bodgetastic, FIXME 877 // better if we can!) 878 if (rare(max_possible == 0 && sort_forward)) { 879 // In the multi database case, MergePostList 880 // currently processes each database 881 // sequentially (which actually may well be 882 // more efficient) so the docids in general 883 // won't arrive in order. 884 // FIXME: is this still good here: 885 // if (leaves.size() == 1) break; 886 } 887 } 888 if (min_item.wt > min_weight) { 889 LOGLINE(MATCH, "Setting min_weight to " << 890 min_item.wt << " from " << min_weight); 891 min_weight = min_item.wt; 892 } 893 } 894 } 895 } else { 896 items.push_back(new_item); 897 is_heap = false; 898 if (sort_by == REL && items.size() == max_msize) { 899 if (docs_matched >= check_at_least) { 900 // We're done if this is a forward boolean match 901 // with only one database (bodgetastic, FIXME 902 // better if we can!) 903 if (rare(max_possible == 0 && sort_forward)) { 904 // In the multi database case, MergePostList 905 // currently processes each database 906 // sequentially (which actually may well be 907 // more efficient) so the docids in general 908 // won't arrive in order. 909 // FIXME: if (leaves.size() == 1) break; 910 } 911 } 912 } 913 } 914 } 915 916 // Keep a track of the greatest weight we've seen. 917 if (new_item.wt > greatest_wt) { 918 greatest_wt = new_item.wt; 919 #ifdef XAPIAN_HAS_REMOTE_BACKEND 920 const unsigned int multiplier = db.internal.size(); 921 unsigned int db_num = (new_item.did - 1) % multiplier; 922 if (is_remote[db_num]) { 923 // Note that the greatest weighted document came from a remote 924 // database, and which one. 925 greatest_wt_subqs_db_num = db_num; 926 } else 927 #endif 928 { 929 greatest_wt_subqs_matched = pl->count_matching_subqs(); 930 #ifdef XAPIAN_HAS_REMOTE_BACKEND 931 greatest_wt_subqs_db_num = UINT_MAX; 932 #endif 933 } 934 if (percent_cutoff) { 935 Xapian::weight w = new_item.wt * percent_cutoff_factor; 936 if (w > min_weight) { 937 min_weight = w; 938 if (!is_heap) { 939 is_heap = true; 940 make_heap<vector<Xapian::Internal::MSetItem>::iterator, 941 MSetCmp>(items.begin(), items.end(), mcmp); 942 } 943 while (!items.empty() && items.front().wt < min_weight) { 944 pop_heap<vector<Xapian::Internal::MSetItem>::iterator, 945 MSetCmp>(items.begin(), items.end(), mcmp); 946 Assert(items.back().wt < min_weight); 947 items.pop_back(); 948 } 949 #ifdef XAPIAN_ASSERTIONS_PARANOID 950 vector<Xapian::Internal::MSetItem>::const_iterator i; 951 for (i = items.begin(); i != items.end(); ++i) { 952 Assert(i->wt >= min_weight); 953 } 954 #endif 955 } 956 } 957 } 958 } 959 960 814 961 // done with posting list tree 815 962 delete pl; 816 963 -
matcher/localmatch.cc
89 89 PostList * 90 90 LocalSubMatch::get_postlist_and_term_info(MultiMatch * matcher, 91 91 map<string, Xapian::MSet::Internal::TermFreqAndWeight> * termfreqandwts, 92 Xapian::termcount * total_subqs_ptr) 92 Xapian::termcount * total_subqs_ptr, 93 std::vector<std::string> & pool_terms) 93 94 { 94 95 DEBUGCALL(MATCH, PostList *, "LocalSubMatch::get_postlist_and_term_info", 95 96 matcher << ", [termfreqandwts], [total_subqs_ptr]"); … … 98 99 // Build the postlist tree for the query. This calls 99 100 // LocalSubMatch::postlist_from_op_leaf_query() for each term in the query, 100 101 // which builds term_info as a side effect. 101 QueryOptimiser opt(*db, *this, matcher );102 QueryOptimiser opt(*db, *this, matcher, pool_terms); 102 103 PostList * pl = opt.optimise_query(&orig_query); 103 104 *total_subqs_ptr = opt.get_total_subqueries(); 104 105 -
matcher/exactphrasecheck.h
1 /** @file exactphrasecheck.cc 2 * @brief Check if terms form a particular exact phrase. 3 */ 4 /* Copyright (C) 2006 Olly Betts 5 * Copyright (C) 2009 Lemur Consulting Ltd 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22 #ifndef XAPIAN_INCLUDED_EXACTPHRASEPOSTLIST_H 23 #define XAPIAN_INCLUDED_EXACTPHRASEPOSTLIST_H 24 25 #include "xapian/database.h" 26 27 #include <string> 28 #include <vector> 29 30 typedef Xapian::PositionIterator::Internal PositionList; 31 32 /** Check for an exact phrase using positional information. 33 * 34 * Tests if the terms occur somewhere in the document in the order given 35 * and at adjacent term positions. 36 */ 37 class ExactPhraseCheck { 38 Xapian::Database db; 39 40 std::vector<std::string> terms; 41 42 PositionList ** poslists; 43 44 unsigned * order; 45 46 /// Start reading from the i-th position list. 47 bool start_position_list(unsigned i, Xapian::docid did); 48 49 public: 50 ExactPhraseCheck(const Xapian::Database & db_, 51 const std::vector<std::string> &terms_); 52 53 ~ExactPhraseCheck(); 54 55 /// Test if the specified document contains the terms as an exact phrase. 56 bool operator()(Xapian::docid did); 57 }; 58 59 #endif -
matcher/localmatch.h
81 81 /// Get PostList and term info. 82 82 PostList * get_postlist_and_term_info(MultiMatch *matcher, 83 83 std::map<string, Xapian::MSet::Internal::TermFreqAndWeight> *termfreqandwts, 84 Xapian::termcount * total_subqs_ptr); 84 Xapian::termcount * total_subqs_ptr, 85 std::vector<std::string> & pool_terms); 85 86 86 87 /** Convert a postlist into a synonym postlist. 87 88 */ -
matcher/remotesubmatch.cc
64 64 PostList * 65 65 RemoteSubMatch::get_postlist_and_term_info(MultiMatch *, 66 66 map<string, Xapian::MSet::Internal::TermFreqAndWeight> * termfreqandwts, 67 Xapian::termcount * total_subqs_ptr) 67 Xapian::termcount * total_subqs_ptr, 68 std::vector<std::string> &) 68 69 { 69 70 DEBUGCALL(MATCH, PostList *, "RemoteSubMatch::get_postlist_and_term_info", 70 71 "[matcher], " << (void*)termfreqandwts << ", " << (void*)total_subqs_ptr); -
matcher/queryoptimiser.cc
29 29 #include "emptypostlist.h" 30 30 #include "exactphrasepostlist.h" 31 31 #include "externalpostlist.h" 32 #include "leafpostlist.h" 32 33 #include "multiandpostlist.h" 33 34 #include "multimatch.h" 34 35 #include "omassert.h" … … 49 50 using namespace std; 50 51 51 52 PostList * 52 QueryOptimiser::do_subquery(const Xapian::Query::Internal * query, double factor) 53 QueryOptimiser::do_subquery(const Xapian::Query::Internal * query, double factor, 54 bool top_and) 53 55 { 54 56 DEBUGCALL(MATCH, PostList *, "QueryOptimiser::do_subquery", 55 57 query << ", " << factor); … … 79 81 case Xapian::Query::OP_FILTER: 80 82 case Xapian::Query::OP_NEAR: 81 83 case Xapian::Query::OP_PHRASE: 82 RETURN(do_and_like(query, factor ));84 RETURN(do_and_like(query, factor, top_and)); 83 85 84 86 case Xapian::Query::OP_OR: 85 87 case Xapian::Query::OP_XOR: … … 99 101 100 102 case Xapian::Query::OP_AND_NOT: { 101 103 AssertEq(query->subqs.size(), 2); 102 PostList * l = do_subquery(query->subqs[0], factor );103 PostList * r = do_subquery(query->subqs[1], 0.0 );104 PostList * l = do_subquery(query->subqs[0], factor, top_and); 105 PostList * r = do_subquery(query->subqs[1], 0.0, false); 104 106 RETURN(new AndNotPostList(l, r, matcher, db_size)); 105 107 } 106 108 107 109 case Xapian::Query::OP_AND_MAYBE: { 108 110 AssertEq(query->subqs.size(), 2); 109 PostList * l = do_subquery(query->subqs[0], factor );110 PostList * r = do_subquery(query->subqs[1], factor );111 PostList * l = do_subquery(query->subqs[0], factor, top_and); 112 PostList * r = do_subquery(query->subqs[1], factor, false); 111 113 RETURN(new AndMaybePostList(l, r, matcher, db_size)); 112 114 } 113 115 … … 140 142 AssertEq(query->subqs.size(), 1); 141 143 double sub_factor = factor; 142 144 if (sub_factor != 0.0) sub_factor *= query->get_dbl_parameter(); 143 RETURN(do_subquery(query->subqs[0], sub_factor ));145 RETURN(do_subquery(query->subqs[0], sub_factor, top_and)); 144 146 } 145 147 146 148 default: … … 163 165 }; 164 166 165 167 PostList * 166 QueryOptimiser::do_and_like(const Xapian::Query::Internal *query, double factor) 168 QueryOptimiser::do_and_like(const Xapian::Query::Internal *query, double factor, 169 bool top_and) 167 170 { 168 171 DEBUGCALL(MATCH, PostList *, "QueryOptimiser::do_and_like", 169 172 query << ", " << factor); … … 195 198 pl = new NearPostList(pl, window, terms); 196 199 } else if (window == filter.end - filter.begin) { 197 200 AssertEq(filter.op, Xapian::Query::OP_PHRASE); 198 pl = new ExactPhrasePostList(pl, terms); 201 if (top_and) { 202 vector<PostList *>::const_iterator j; 203 for (j = terms.begin(); j != terms.end(); ++j) { 204 // FIXME: avoid dynamic_cast<> here. 205 LeafPostList * lpl = dynamic_cast<LeafPostList*>(*j); 206 if (!lpl || lpl->term.empty()) goto cannot_pool; 207 pool_terms.push_back(lpl->term); 208 } 209 top_and = false; 210 } else { 211 cannot_pool: 212 pl = new ExactPhrasePostList(pl, terms); 213 } 199 214 } else { 200 215 AssertEq(filter.op, Xapian::Query::OP_PHRASE); 201 216 pl = new PhrasePostList(pl, window, terms); … … 244 259 if (is_and_like(subq->op)) { 245 260 do_and_like(subq, factor, and_plists, pos_filters); 246 261 } else { 247 PostList * pl = do_subquery(subq, factor );262 PostList * pl = do_subquery(subq, factor, false); 248 263 and_plists.push_back(pl); 249 264 } 250 265 } … … 255 270 size_t begin = end - queries.size(); 256 271 Xapian::termcount window = query->parameter; 257 272 273 if (window == queries.size()) { 274 } 258 275 pos_filters.push_back(PosFilter(op, begin, end, window)); 259 276 } 260 277 } … … 335 352 336 353 Xapian::Query::Internal::subquery_list::const_iterator q; 337 354 for (q = queries.begin(); q != queries.end(); ++q) { 338 postlists.push_back(do_subquery(*q, factor ));355 postlists.push_back(do_subquery(*q, factor, false)); 339 356 } 340 357 341 358 if (op == Xapian::Query::OP_ELITE_SET) { -
matcher/queryoptimiser.h
44 44 45 45 MultiMatch * matcher; 46 46 47 std::vector<std::string> & pool_terms; 48 47 49 /** How many leaf subqueries there are. 48 50 * 49 51 * Used for scaling percentages when the highest weighted document doesn't … … 59 61 * @return A PostList subtree. 60 62 */ 61 63 PostList * do_subquery(const Xapian::Query::Internal * query, 62 double factor );64 double factor, bool top_and); 63 65 64 66 /** Optimise an AND-like Xapian::Query::Internal subtree into a PostList 65 67 * subtree. … … 69 71 * 70 72 * @return A PostList subtree. 71 73 */ 72 PostList * do_and_like(const Xapian::Query::Internal *query, double factor); 74 PostList * do_and_like(const Xapian::Query::Internal *query, double factor, 75 bool top_and); 73 76 74 77 /** Optimise an AND-like Xapian::Query::Internal subtree into a PostList 75 78 * subtree. … … 107 110 public: 108 111 QueryOptimiser(const Xapian::Database::Internal & db_, 109 112 LocalSubMatch & localsubmatch_, 110 MultiMatch * matcher_) 113 MultiMatch * matcher_, 114 std::vector<std::string> & pool_terms_) 111 115 : db(db_), db_size(db.get_doccount()), localsubmatch(localsubmatch_), 112 matcher(matcher_), total_subqs(0) { }116 matcher(matcher_), pool_terms(pool_terms_), total_subqs(0) { } 113 117 114 118 PostList * optimise_query(Xapian::Query::Internal * query) { 115 return do_subquery(query, 1.0 );119 return do_subquery(query, 1.0, true); 116 120 } 117 121 118 122 Xapian::termcount get_total_subqueries() const { return total_subqs; } -
matcher/remotesubmatch.h
72 72 PostList * get_postlist_and_term_info(MultiMatch *matcher, 73 73 std::map<std::string, 74 74 Xapian::MSet::Internal::TermFreqAndWeight> *termfreqandwts, 75 Xapian::termcount * total_subqs_ptr); 75 Xapian::termcount * total_subqs_ptr, 76 std::vector<std::string> & pool_terms); 76 77 77 78 /// Get percentage factor - only valid after get_postlist_and_term_info(). 78 79 double get_percent_factor() const { return percent_factor; } -
common/leafpostlist.h
47 47 48 48 bool need_doclength; 49 49 50 public: // FIXME: avoid having to make term public. 50 51 /// The term name for this postlist ("" for an alldocs postlist). 51 52 std::string term; 52 53 54 protected: 53 55 /// Only constructable as a base class for derived classes. 54 56 LeafPostList(const std::string & term_) 55 57 : weight(0), need_doclength(false), term(term_) { } -
common/submatch.h
76 76 virtual PostList * get_postlist_and_term_info(MultiMatch *matcher, 77 77 std::map<std::string, 78 78 Xapian::MSet::Internal::TermFreqAndWeight> *termfreqandwts, 79 Xapian::termcount * total_subqs_ptr) 79 Xapian::termcount * total_subqs_ptr, 80 std::vector<std::string> & pool_terms) 80 81 = 0; 81 82 }; 82 83