Ticket #100: matchcmp.patch
File matchcmp.patch, 49.2 KB (added by , 18 years ago) |
---|
-
xapian-maintainer-tools/win32/win32_matcher.mak
42 42 $(INTDIR)\multimatch.obj \ 43 43 $(INTDIR)\expand.obj \ 44 44 $(INTDIR)\stats.obj \ 45 $(INTDIR)\matchcmp.obj \ 45 46 $(INTDIR)\mergepostlist.obj \ 46 47 $(INTDIR)\msetpostlist.obj \ 47 48 $(INTDIR)\msetcmp.obj 48 49 49 50 CLEAN : 50 51 -@erase "$(OUTDIR)\libmatcher.lib" … … 175 176 << 176 177 177 178 179 "$(INTDIR)\matchcmp.obj" : ".\matchcmp.cc" 180 $(CPP) @<< 181 $(CPP_PROJ) $** 182 << 183 178 184 "$(INTDIR)\mergepostlist.obj" : ".\mergepostlist.cc" 179 185 $(CPP) @<< 180 186 $(CPP_PROJ) $** -
xapian-core/matcher/matchcmp.cc
1 /* matchcmp.cc: C++ classes for comparing search results. 2 * 3 * Copyright 2006 Lemur Consulting Ltd 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 18 * USA 19 */ 20 21 #include <config.h> 22 #include <xapian/enquire.h> 23 #include "serialise.h" 24 #include "serialise-double.h" 25 #include "omdebug.h" 26 #include "omenquireinternal.h" 27 28 namespace Xapian { 29 30 weight 31 MatchItem::get_wt() const 32 { 33 return item.wt; 34 } 35 36 docid 37 MatchItem::get_docid() const 38 { 39 return item.did; 40 } 41 42 Document 43 MatchItem::get_document() const 44 { 45 return Document(item.get_document().get()); 46 } 47 48 49 50 std::string IntegerMatchCmp::serialise() const { 51 std::string result = encode_length(sort_key); 52 result += (direction == 1) ? 'A' : 'D'; 53 return result; 54 } 55 56 IntegerMatchCmp * IntegerMatchCmp::unserialise(const std::string & s) const { 57 const char *p = s.data(); 58 const char *p_end = p + s.size(); 59 size_t sort_key_ = decode_length(&p, p_end); 60 Assert(p + 1 == p_end); 61 return new IntegerMatchCmp(sort_key_, p[0] == 'A' ? 1 : -1); 62 } 63 64 int 65 IntegerMatchCmp::cmp(const MatchItem & a, 66 const MatchItem & b) const 67 { 68 DEBUGCALL(MATCH, bool, "IntegerMatchCmp::operator()", ""); 69 std::string s = a.get_document().get_value(sort_key); 70 const char *p = s.data(); 71 const char *p_end = p + s.size(); 72 size_t val_a = decode_length(&p, p_end); 73 74 s = b.get_document().get_value(sort_key); 75 p = s.data(); 76 p_end = p + s.size(); 77 size_t val_b = decode_length(&p, p_end); 78 79 if (val_a > val_b) 80 return direction; 81 else if (val_a < val_b) 82 return -direction; 83 return 0; 84 } 85 86 std::string 87 IntegerMatchCmp::int_to_value(int num) 88 { 89 return encode_length(num); 90 } 91 92 int 93 IntegerMatchCmp::value_to_int(const std::string &s) 94 { 95 const char *p = s.data(); 96 const char *p_end = p + s.size(); 97 size_t result = decode_length(&p, p_end); 98 return result; 99 } 100 101 102 103 std::string DoubleMatchCmp::serialise() const { 104 std::string result = encode_length(sort_key); 105 result += (direction == 1) ? 'A' : 'D'; 106 return result; 107 } 108 109 DoubleMatchCmp * DoubleMatchCmp::unserialise(const std::string & s) const { 110 const char *p = s.data(); 111 const char *p_end = p + s.size(); 112 size_t sort_key_ = decode_length(&p, p_end); 113 Assert(p + 1 == p_end); 114 return new DoubleMatchCmp(sort_key_, p[0] == 'A' ? 1 : -1); 115 } 116 117 int 118 DoubleMatchCmp::cmp(const MatchItem & a, 119 const MatchItem & b) const 120 { 121 DEBUGCALL(MATCH, bool, "DoubleMatchCmp::operator()", ""); 122 std::string s = a.get_document().get_value(sort_key); 123 const char *p = s.data(); 124 const char *p_end = p + s.size(); 125 double val_a = unserialise_double(&p, p_end); 126 127 s = b.get_document().get_value(sort_key); 128 p = s.data(); 129 p_end = p + s.size(); 130 double val_b = unserialise_double(&p, p_end); 131 132 if (val_a > val_b) 133 return direction; 134 else if (val_a < val_b) 135 return -direction; 136 return 0; 137 } 138 139 std::string 140 DoubleMatchCmp::double_to_value(double num) 141 { 142 return serialise_double(num); 143 } 144 145 double 146 DoubleMatchCmp::value_to_double(const std::string &s) 147 { 148 const char *p = s.data(); 149 const char *p_end = p + s.size(); 150 double result = unserialise_double(&p, p_end); 151 return result; 152 } 153 154 } -
xapian-core/matcher/multimatch.cc
78 78 Xapian::weight bias_weight_, 79 79 Xapian::ErrorHandler * errorhandler_, 80 80 StatsGatherer * gatherer_, 81 const Xapian::Weight * weight_) 81 const Xapian::Weight * weight_, 82 const Xapian::MatchCmp * match_cmp_) 82 83 : gatherer(gatherer_), db(db_), query(query_), 83 84 collapse_key(collapse_key_), percent_cutoff(percent_cutoff_), 84 85 weight_cutoff(weight_cutoff_), order(order_), 85 86 sort_key(sort_key_), sort_by(sort_by_), 86 87 sort_value_forward(sort_value_forward_), 87 88 bias_halflife(bias_halflife_), bias_weight(bias_weight_), 88 errorhandler(errorhandler_), weight(weight_) 89 errorhandler(errorhandler_), weight(weight_), match_cmp(match_cmp_) 89 90 { 90 91 DEBUGCALL(MATCH, void, "MultiMatch", db_ << ", " << query_ << ", " << 91 92 qlen << ", " << … … 138 139 } 139 140 rem_db->set_query(query, qlen, collapse_key, order, sort_key, 140 141 sort_by, sort_value_forward, percent_cutoff, 141 weight_cutoff, weight, *subrset);142 weight_cutoff, weight, match_cmp, *subrset); 142 143 smatch = new RemoteSubMatch(rem_db, gatherer.get(), 143 144 sort_key != Xapian::valueno(-1)); 144 145 } else { … … 192 193 } 193 194 194 195 string 195 MultiMatch::get_collapse_key(PostList *pl, Xapian::docid did, 196 Xapian::valueno keyno, Xapian::Internal::RefCntPtr<Xapian::Document::Internal> &doc) 196 MultiMatch::get_collapse_key(PostList *pl, 197 Xapian::valueno keyno, 198 const Xapian::Internal::MSetItem & item) 197 199 { 198 DEBUGCALL(MATCH, string, "MultiMatch::get_collapse_key", pl << ", " << did << ", " << keyno << ", [doc]"); 200 DEBUGCALL(MATCH, string, "MultiMatch::get_collapse_key", pl << ", " << item.did << ", " << keyno << ", [doc]"); 201 202 // FIXME - this gets the collapse key from the postlist. This only 203 // actually happens for Mset postlists (or mergepostlists containing an 204 // mset postlist), since this is the only case where the collapse key has 205 // been read already. Instead, we should use the document object stored in 206 // the mset item. 207 199 208 const string *key = pl->get_collapse_key(); 200 209 if (key) RETURN(*key); 201 if (doc.get() == 0) { 202 unsigned int multiplier = db.internal.size(); 203 Assert(multiplier != 0); 204 Xapian::doccount n = (did - 1) % multiplier; // which actual database 205 Xapian::docid m = (did - 1) / multiplier + 1; // real docid in that database 206 207 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(db.internal[n]->open_document(m, true)); 208 doc = temp; 209 } 210 RETURN(doc->get_value(keyno)); 210 RETURN(item.get_document()->get_value(keyno)); 211 211 } 212 212 213 213 Xapian::weight … … 230 230 void 231 231 MultiMatch::get_mset(Xapian::doccount first, Xapian::doccount maxitems, 232 232 Xapian::doccount check_at_least, 233 Xapian::MSet & mset, const Xapian::MatchDecider *mdecider) 233 Xapian::MSet & mset, 234 const Xapian::MatchDecider *mdecider) 234 235 { 235 236 DEBUGCALL(MATCH, void, "MultiMatch::get_mset", first << ", " << maxitems 236 237 << ", " << check_at_least << ", ..."); … … 368 369 369 370 /// Comparison functor for sorting MSet 370 371 bool sort_forward = (order != Xapian::Enquire::DESCENDING); 371 MSetCmp mcmp(get_msetcmp_function(sort_by, sort_forward, sort_value_forward)); 372 mset_cmp cmpfn = get_msetcmp_function(sort_by, sort_forward, sort_value_forward); 373 MSetCmp mcmp(cmpfn, sort_key, match_cmp); 372 374 375 /// Number of databases making up the database we're using. 376 const unsigned int db_internal_size = db.internal.size(); 377 Assert(db_internal_size != 0); 378 373 379 // Perform query 374 380 375 381 // We form the mset in two stages. In the first we fill up our working … … 416 422 if (min_item.wt > 0.0) wt = pl->get_weight(); 417 423 418 424 DEBUGLINE(MATCH, "Candidate document id " << did << " wt " << wt); 419 Xapian::Internal::MSetItem new_item(wt, did);420 if (sort_key != Xapian::valueno(-1)) {421 const unsigned int multiplier = db.internal.size();422 Assert(multiplier != 0);423 Xapian::doccount n = (new_item.did - 1) % multiplier; // which actual database424 Xapian::docid m = (new_item.did - 1) / multiplier + 1; // real docid in that database425 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc(db.internal[n]->open_document(m, true));426 new_item.sort_key = doc->get_value(sort_key);427 }428 425 426 Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db = db.internal[((did - 1) % db_internal_size)]; // database holding document 427 Xapian::docid internal_docid = (did - 1) / db_internal_size + 1; // docid in internal_db 428 Xapian::Internal::MSetItem new_item(wt, did, internal_db, internal_docid); 429 429 430 // Test if item has high enough weight (or sort key) to get into 430 431 // proto-mset. 431 432 if (sort_key != Xapian::valueno(-1) || min_item.wt > 0.0) 432 433 if (!mcmp(new_item, min_item)) continue; 433 434 434 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc;435 436 435 // Use the decision functor if any. 437 436 // FIXME: if results are from MSetPostList then we can omit this step 438 437 if (mdecider != NULL) { 439 if (doc.get() == 0) { 440 const unsigned int multiplier = db.internal.size(); 441 Assert(multiplier != 0); 442 Xapian::doccount n = (did - 1) % multiplier; // which actual database 443 Xapian::docid m = (did - 1) / multiplier + 1; // real docid in that database 444 445 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(db.internal[n]->open_document(m, true)); 446 doc = temp; 447 } 448 Xapian::Document mydoc(doc.get()); 438 Xapian::Document mydoc(new_item.get_document().get()); 449 439 if (!mdecider->operator()(mydoc)) continue; 450 440 } 451 441 … … 460 450 461 451 // Perform collapsing on key if requested. 462 452 if (collapse_key != Xapian::valueno(-1)) { 463 new_item.collapse_key = get_collapse_key(pl, did, collapse_key, 464 doc); 453 new_item.collapse_key = get_collapse_key(pl, collapse_key, new_item); 465 454 466 455 // Don't collapse on null key 467 456 if (!new_item.collapse_key.empty()) { -
xapian-core/matcher/msetcmp.h
20 20 21 21 #include "omenquireinternal.h" 22 22 23 class MSetCmp; 24 23 25 // typedef for MSetItem comparison function. 24 26 typedef bool (* mset_cmp)(const Xapian::Internal::MSetItem &, 25 const Xapian::Internal::MSetItem &); 27 const Xapian::Internal::MSetItem &, 28 const MSetCmp *); 26 29 27 30 /// Select the appropriate msetcmp function. 28 31 mset_cmp get_msetcmp_function(Xapian::Enquire::Internal::sort_setting sort_by, bool sort_forward, bool sort_value_forward); … … 31 34 class MSetCmp { 32 35 mset_cmp fn; 33 36 public: 34 MSetCmp(mset_cmp fn_) : fn(fn_) { } 37 Xapian::valueno sort_key; 38 const Xapian::MatchCmp * cmp; 39 40 /// Construct an instance of MSetCmp using a built-in comparison function. 41 MSetCmp(mset_cmp fn_, 42 Xapian::valueno sort_key_, 43 const Xapian::MatchCmp * cmp_) 44 : fn(fn_), sort_key(sort_key_), cmp(cmp_) { } 45 35 46 /// Return true if MSetItem a should be ranked above MSetItem b. 36 47 bool operator()(const Xapian::Internal::MSetItem &a, 37 38 return fn(a, b );48 const Xapian::Internal::MSetItem &b) const { 49 return fn(a, b, this); 39 50 } 40 51 }; 52 -
xapian-core/matcher/msetcmp.cc
20 20 21 21 #include <config.h> 22 22 #include "msetcmp.h" 23 #include <string> 23 24 24 25 /* We use templates to generate the 14 different comparison functions 25 26 * which we need. This avoids having to write them all out by hand. … … 46 47 // Order by relevance, then docid. 47 48 template<bool FORWARD_DID> bool 48 49 msetcmp_by_relevance(const Xapian::Internal::MSetItem &a, 49 const Xapian::Internal::MSetItem &b) 50 const Xapian::Internal::MSetItem &b, 51 const MSetCmp *) 50 52 { 51 53 if (a.wt > b.wt) return true; 52 54 if (a.wt < b.wt) return false; … … 56 58 // Order by value, then docid. 57 59 template<bool FORWARD_VALUE, bool FORWARD_DID> bool 58 60 msetcmp_by_value(const Xapian::Internal::MSetItem &a, 59 const Xapian::Internal::MSetItem &b) 61 const Xapian::Internal::MSetItem &b, 62 const MSetCmp * cmp) 60 63 { 61 64 if (!FORWARD_VALUE) { 62 65 // We want dummy did 0 to compare worse than any other. 63 66 if (a.did == 0) return false; 64 67 if (b.did == 0) return true; 65 68 } 66 if (a.sort_key > b.sort_key) return FORWARD_VALUE; 67 if (a.sort_key < b.sort_key) return !FORWARD_VALUE; 69 std::string sort_key_a = a.get_document()->get_value(cmp->sort_key); 70 std::string sort_key_b = b.get_document()->get_value(cmp->sort_key); 71 if (sort_key_a > sort_key_b) return FORWARD_VALUE; 72 if (sort_key_a < sort_key_b) return !FORWARD_VALUE; 68 73 return msetcmp_by_did<FORWARD_DID, FORWARD_VALUE>(a, b); 69 74 } 70 75 71 76 // Order by value, then relevance, then docid. 72 77 template<bool FORWARD_VALUE, bool FORWARD_DID> bool 73 78 msetcmp_by_value_then_relevance(const Xapian::Internal::MSetItem &a, 74 const Xapian::Internal::MSetItem &b) 79 const Xapian::Internal::MSetItem &b, 80 const MSetCmp * cmp) 75 81 { 76 82 if (!FORWARD_VALUE) { 77 83 // two special cases to make min_item compares work when did == 0 78 84 if (a.did == 0) return false; 79 85 if (b.did == 0) return true; 80 86 } 81 if (a.sort_key > b.sort_key) return FORWARD_VALUE; 82 if (a.sort_key < b.sort_key) return !FORWARD_VALUE; 87 std::string sort_key_a = a.get_document()->get_value(cmp->sort_key); 88 std::string sort_key_b = b.get_document()->get_value(cmp->sort_key); 89 if (sort_key_a > sort_key_b) return FORWARD_VALUE; 90 if (sort_key_a < sort_key_b) return !FORWARD_VALUE; 83 91 if (a.wt > b.wt) return true; 84 92 if (a.wt < b.wt) return false; 85 93 return msetcmp_by_did<FORWARD_DID, FORWARD_VALUE>(a, b); … … 88 96 // Order by relevance, then value, then docid. 89 97 template<bool FORWARD_VALUE, bool FORWARD_DID> bool 90 98 msetcmp_by_relevance_then_value(const Xapian::Internal::MSetItem &a, 91 const Xapian::Internal::MSetItem &b) 99 const Xapian::Internal::MSetItem &b, 100 const MSetCmp * cmp) 92 101 { 93 102 if (!FORWARD_VALUE) { 94 103 // two special cases to make min_item compares work when did == 0 … … 97 106 } 98 107 if (a.wt > b.wt) return true; 99 108 if (a.wt < b.wt) return false; 100 if (a.sort_key > b.sort_key) return FORWARD_VALUE; 101 if (a.sort_key < b.sort_key) return !FORWARD_VALUE; 109 std::string sort_key_a = a.get_document()->get_value(cmp->sort_key); 110 std::string sort_key_b = b.get_document()->get_value(cmp->sort_key); 111 if (sort_key_a > sort_key_b) return FORWARD_VALUE; 112 if (sort_key_a < sort_key_b) return !FORWARD_VALUE; 102 113 return msetcmp_by_did<FORWARD_DID, FORWARD_VALUE>(a, b); 103 114 } 104 115 116 template<bool FORWARD_DID> bool 117 msetcmp_by_user_cmpfn(const Xapian::Internal::MSetItem &a, 118 const Xapian::Internal::MSetItem &b, 119 const MSetCmp * cmp) 120 { 121 // We want dummy did 0 to compare worse than any other. 122 if (a.did == 0) return false; 123 if (b.did == 0) return true; 124 125 if (a.did == b.did) return false; // FIXME - can this ever happen? If not, convert this to Assert(a.did != b.did). 126 Xapian::MatchItem item_a(a); 127 Xapian::MatchItem item_b(b); 128 int c = (cmp->cmp->cmp)(item_a, item_b); 129 if (c < 0) 130 return true; 131 else if (c > 0) 132 return false; 133 if (FORWARD_DID) { 134 return (a.did < b.did); 135 } else { 136 return (a.did > b.did); 137 } 138 } 139 105 140 static mset_cmp mset_cmp_table[] = { 106 141 // Xapian::Enquire::Internal::REL 107 142 msetcmp_by_relevance<false>, … … 122 157 msetcmp_by_relevance_then_value<true, true>, 123 158 msetcmp_by_relevance_then_value<false, true>, 124 159 msetcmp_by_relevance_then_value<true, false>, 125 msetcmp_by_relevance_then_value<false, false> 160 msetcmp_by_relevance_then_value<false, false>, 161 // Xapian::Enquire::Internal::USER 162 msetcmp_by_user_cmpfn<false>, 163 msetcmp_by_user_cmpfn<false>, 164 msetcmp_by_user_cmpfn<true>, 165 msetcmp_by_user_cmpfn<true> 126 166 }; 127 167 128 168 mset_cmp get_msetcmp_function(Xapian::Enquire::Internal::sort_setting sort_by, bool sort_forward, bool sort_value_forward) { -
xapian-core/matcher/Makefile.am
20 20 andmaybepostlist.cc xorpostlist.cc phrasepostlist.cc selectpostlist.cc \ 21 21 filterpostlist.cc ortermlist.cc expandweight.cc rset.cc \ 22 22 bm25weight.cc tradweight.cc \ 23 localmatch.cc m ultimatch.cc expand.cc stats.cc \23 localmatch.cc matchcmp.cc multimatch.cc expand.cc stats.cc \ 24 24 mergepostlist.cc msetpostlist.cc msetcmp.cc emptysubmatch.cc \ 25 25 $(SOURCEFORREMOTE) -
xapian-core/tests/internaltest.cc
239 239 255.5, 240 240 256.125, 241 241 257.03125, 242 0.12268031290495594321l, 243 0.12268031290495592933l, 242 244 }; 243 245 244 246 check_double_serialisation(0.0); -
xapian-core/tests/api_db.cc
1147 1147 // set_sort_by_value 1148 1148 // set_sort_by_value_then_relevance 1149 1149 // set_sort_by_relevance_then_value 1150 // User comparison functions 1150 1151 static bool test_sortrel1() 1151 1152 { 1152 1153 Xapian::Enquire enquire(get_database("apitest_sortrel")); … … 1162 1163 const Xapian::docid order7[] = { 7,9,8,6,5,4,2,1,3 }; 1163 1164 const Xapian::docid order8[] = { 7,6,2,9,5,1,8,4,3 }; 1164 1165 const Xapian::docid order9[] = { 2,6,7,1,5,9,3,4,8 }; 1166 const Xapian::docid order10[] = { 7,9,4,5,6,1,2,3,8 }; 1167 const Xapian::docid order11[] = { 8,1,2,3,4,5,6,7,9 }; 1168 const Xapian::docid order12[] = { 9,7,6,5,4,3,2,1,8 }; 1169 const Xapian::docid order13[] = { 8,3,2,1,6,5,4,9,7 }; 1165 1170 1166 1171 Xapian::MSet mset; 1167 1172 size_t i; … … 1172 1177 TEST_EQUAL(*mset[i], order1[i]); 1173 1178 } 1174 1179 1180 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100)); 1181 1182 mset = enquire.get_mset(0, 10); 1183 TEST_EQUAL(mset.size(), sizeof(order10) / sizeof(Xapian::docid)); 1184 for (i = 0; i < sizeof(order10) / sizeof(Xapian::docid); ++i) { 1185 TEST_EQUAL(*mset[i], order10[i]); 1186 } 1187 1188 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, true)); 1189 1190 mset = enquire.get_mset(0, 10); 1191 TEST_EQUAL(mset.size(), sizeof(order10) / sizeof(Xapian::docid)); 1192 for (i = 0; i < sizeof(order10) / sizeof(Xapian::docid); ++i) { 1193 TEST_EQUAL(*mset[i], order10[i]); 1194 } 1195 1196 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, false)); 1197 1198 mset = enquire.get_mset(0, 10); 1199 TEST_EQUAL(mset.size(), sizeof(order11) / sizeof(Xapian::docid)); 1200 for (i = 0; i < sizeof(order11) / sizeof(Xapian::docid); ++i) { 1201 TEST_EQUAL(*mset[i], order11[i]); 1202 } 1203 1175 1204 enquire.set_sort_by_value_then_relevance(1); 1176 1205 1177 1206 mset = enquire.get_mset(0, 10); … … 1188 1217 TEST_EQUAL(*mset[i], order1[i]); 1189 1218 } 1190 1219 1220 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100)); 1221 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1222 1223 mset = enquire.get_mset(0, 10); 1224 TEST_EQUAL(mset.size(), sizeof(order12) / sizeof(Xapian::docid)); 1225 for (i = 0; i < sizeof(order12) / sizeof(Xapian::docid); ++i) { 1226 TEST_EQUAL(*mset[i], order12[i]); 1227 } 1228 1229 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, true)); 1230 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1231 1232 mset = enquire.get_mset(0, 10); 1233 TEST_EQUAL(mset.size(), sizeof(order12) / sizeof(Xapian::docid)); 1234 for (i = 0; i < sizeof(order12) / sizeof(Xapian::docid); ++i) { 1235 TEST_EQUAL(*mset[i], order12[i]); 1236 } 1237 1238 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, false)); 1239 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1240 1241 mset = enquire.get_mset(0, 10); 1242 TEST_EQUAL(mset.size(), sizeof(order13) / sizeof(Xapian::docid)); 1243 for (i = 0; i < sizeof(order13) / sizeof(Xapian::docid); ++i) { 1244 TEST_EQUAL(*mset[i], order13[i]); 1245 } 1246 1191 1247 enquire.set_sort_by_value_then_relevance(1); 1192 1248 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1193 1249 -
xapian-core/tests/testdata/apitest_sortrel.txt
12 12 13 13 V1 woman 14 14 15 V1 man woman fish15 V10 man woman fish 16 16 17 17 V1 man woman -
xapian-core/include/xapian/enquire.h
31 31 #include <xapian/error.h> 32 32 #include <xapian/types.h> 33 33 #include <xapian/termiterator.h> 34 #include <xapian/document.h> 34 35 35 36 namespace Xapian { 36 37 … … 40 41 class MSetIterator; 41 42 class Query; 42 43 class Weight; 44 class MatchCmp; 43 45 46 namespace Internal { 47 class MSetItem; 48 } 49 44 50 /** A match set (MSet). 45 51 * This class represents (a portion of) the results of a query. 46 52 */ … … 839 845 void set_sort_by_relevance_then_value(Xapian::valueno sort_key, 840 846 bool ascending = true); 841 847 848 /** Set a comparison functor to be used when comparing matches. 849 * 850 * This overrides the sort options set by set_sort_by_relevance(), 851 * set_sort_by_value(), set_sort_by_relevance_then_value() and 852 * set_sort_by_value_then_relevance(). For matches which the 853 * comparison functor considers equal (ie, for which the functor 854 * returns 0 when comparing them), the matches will be compared in 855 * document ID order, as set by set_docid_order(); 856 * 857 * The comparison function will be called many times in the process of 858 * performing the search. Therefore, it is important that it is 859 * implemented as efficiently as possible. 860 * 861 * @param cmpfn_ The comparion function to use to compare matches. 862 */ 863 void set_sort_by_cmpfn(const MatchCmp &cmpfn_); 864 842 865 /** Set the bias functor parameters. 843 866 * 844 867 * NB this is a temporary API for this feature. … … 1267 1290 bool get_sumpart_needs_doclength() const; 1268 1291 }; 1269 1292 1293 /// An item matching a search. 1294 class MatchItem { 1295 private: 1296 const Xapian::Internal::MSetItem & item; 1297 1298 public: 1299 MatchItem(const Xapian::Internal::MSetItem & item_) 1300 : item(item_) {} 1301 1302 /** Get the weight calculated. */ 1303 Xapian::weight get_wt() const; 1304 1305 /** Get the document id. */ 1306 Xapian::docid get_docid() const; 1307 1308 /** Get the document object, for access to document data, values, 1309 * and terms. */ 1310 Xapian::Document get_document() const; 1311 }; 1312 1313 /// Abstract base class for match comparison functors. 1314 class MatchCmp { 1315 friend class Enquire; // So Enquire can clone us 1316 friend class ::RemoteServer; // So RemoteServer can clone us - FIXME 1317 protected: 1318 MatchCmp(const MatchCmp &); 1319 private: 1320 void operator=(MatchCmp &); 1321 1322 /** Return a new MatchCmp object of this type. 1323 * 1324 * A subclass called FooMatchCmp taking parameters param1 and param2 1325 * should implement this as: 1326 * 1327 * virtual FooMatchCmp * clone() const { 1328 * return new FooMatchCmp(param1, param2); 1329 * } 1330 */ 1331 virtual MatchCmp * clone() const = 0; 1332 1333 public: 1334 MatchCmp() { } 1335 virtual ~MatchCmp() { } 1336 1337 /** Name of the comparison functor. 1338 * 1339 * If the subclass is called FooMatchCmp, this should return "Foo". 1340 */ 1341 virtual std::string name() const = 0; 1342 1343 /// Serialise object parameters into a string. 1344 virtual std::string serialise() const = 0; 1345 1346 /** Create object given string serialisation returned by serialise(). 1347 * 1348 * If the string is not a valid serialised form, this should raise a 1349 * Xapian::NetworkError; 1350 */ 1351 virtual MatchCmp * unserialise(const std::string &s) const = 0; 1352 1353 /** Compare a potential Mset entry a to an entry b. 1354 * 1355 * This function should return an integer less than 0 if MatchItem a 1356 * should be ranked below MatchItem b, and greater than 0 if MatchItem 1357 * a should be ranked above MatchItem b. The function may return 0 if 1358 * it considers the two match items to be equal. 1359 * 1360 * The function will never be called with items which have identical 1361 * document IDs. 1362 * 1363 * The comparison function must be well behaved, such that: 1364 * 1365 * - it must produce the same result if called a second time on a 1366 * particular pair of documents 1367 * - if cmp(x,y) is less than 0 and cmp(y,z) is less than 0, cmp(x,z) 1368 * must be less than 0. 1369 * - if cmp(x,y) is less than 0, cmp(y,x) must be greater than 0. 1370 * 1371 * Bear in mind that the comparison will be performed very frequently 1372 * when performing a search, so must be as fast as possible. In 1373 * particular, although the MatchItem provides access to the document 1374 * object, it is recommended that only the value items stored in the 1375 * document object are accessed. 1376 */ 1377 virtual int cmp(const MatchItem & a, 1378 const MatchItem & b) const = 0; 1379 }; 1380 1381 /** Comparison function for comparing by value as integer. 1382 */ 1383 class IntegerMatchCmp : public MatchCmp { 1384 Xapian::valueno sort_key; 1385 int direction; 1386 public: 1387 /** Return a new IntegerMatchCmp with the same parameters as this one. 1388 */ 1389 IntegerMatchCmp * clone() const { 1390 return new IntegerMatchCmp(sort_key, direction == 1); 1391 } 1392 IntegerMatchCmp(Xapian::valueno sort_key_, 1393 bool ascending = true) 1394 : sort_key(sort_key_), 1395 direction(ascending ? 1 : -1) { } 1396 IntegerMatchCmp() 1397 : sort_key(0), 1398 direction(1) { } 1399 ~IntegerMatchCmp() { } 1400 std::string name() const { return "Integer"; } 1401 1402 std::string serialise() const; 1403 IntegerMatchCmp * unserialise(const std::string &s) const; 1404 1405 int cmp(const MatchItem & a, 1406 const MatchItem & b) const; 1407 1408 /** Convert an integer to a string, suitable for comparing with this 1409 * comparison functor. 1410 */ 1411 static std::string int_to_value(int num); 1412 1413 /** Convert a string suitable for comparison with this comparison 1414 * functor to an integer. 1415 */ 1416 static int value_to_int(const std::string &s); 1417 }; 1418 1419 /** Comparison function for comparing by value as a double. 1420 */ 1421 class DoubleMatchCmp : public MatchCmp { 1422 Xapian::valueno sort_key; 1423 int direction; 1424 public: 1425 /** Return a new DoubleMatchCmp with the same parameters as this one. 1426 */ 1427 DoubleMatchCmp * clone() const { 1428 return new DoubleMatchCmp(sort_key, direction == 1); 1429 } 1430 DoubleMatchCmp(Xapian::valueno sort_key_, 1431 bool ascending = true) 1432 : sort_key(sort_key_), 1433 direction(ascending ? 1 : -1) { } 1434 DoubleMatchCmp() 1435 : sort_key(0), 1436 direction(1) { } 1437 ~DoubleMatchCmp() { } 1438 std::string name() const { return "Double"; } 1439 1440 std::string serialise() const; 1441 DoubleMatchCmp * unserialise(const std::string &s) const; 1442 1443 int cmp(const MatchItem & a, 1444 const MatchItem & b) const; 1445 1446 /** Convert a double to a string, suitable for comparing with this 1447 * comparison functor. 1448 */ 1449 static std::string double_to_value(double num); 1450 1451 /** Convert a string suitable for comparison with this comparison 1452 * functor to a double. 1453 */ 1454 static double value_to_double(const std::string &s); 1455 }; 1456 1270 1457 } 1271 1458 1272 1459 #endif /* XAPIAN_INCLUDED_ENQUIRE_H */ -
xapian-core/net/serialise.cc
220 220 } 221 221 222 222 Xapian::MSet 223 unserialise_mset(const string &s) 223 unserialise_mset(const string &s, 224 Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db) 224 225 { 225 226 const char * p = s.data(); 226 227 const char * p_end = p + s.size(); … … 239 240 size_t len = decode_length(&p, p_end); 240 241 string key(p, len); 241 242 p += len; 242 items.push_back(Xapian::Internal::MSetItem(wt, did, key, 243 items.push_back(Xapian::Internal::MSetItem(wt, did, 244 internal_db, 245 did, 246 key, 243 247 decode_length(&p, p_end))); 244 248 } 245 249 -
xapian-core/net/remoteserver.cc
87 87 wtschemes[weight->name()] = weight; 88 88 weight = new Xapian::TradWeight(); 89 89 wtschemes[weight->name()] = weight; 90 91 // Register match comparison functions. 92 Xapian::MatchCmp * match_cmp; 93 match_cmp = new Xapian::IntegerMatchCmp(); 94 match_cmps[match_cmp->name()] = match_cmp; 95 match_cmp = new Xapian::DoubleMatchCmp(); 96 match_cmps[match_cmp->name()] = match_cmp; 90 97 } 91 98 92 99 RemoteServer::~RemoteServer() … … 95 102 for (i = wtschemes.begin(); i != wtschemes.end(); ++i) { 96 103 delete i->second; 97 104 } 105 map<string, Xapian::MatchCmp*>::const_iterator j; 106 for (j = match_cmps.begin(); j != match_cmps.end(); ++j) { 107 delete j->second; 108 } 98 109 } 99 110 100 111 message_type … … 274 285 275 286 Xapian::valueno sort_key = decode_length(&p, p_end); 276 287 277 if (*p < '0' || *p > ' 3') {288 if (*p < '0' || *p > '4') { 278 289 throw Xapian::NetworkError("bad message (sort_by)"); 279 290 } 280 291 Xapian::Enquire::Internal::sort_setting sort_by; … … 308 319 AutoPtr<Xapian::Weight> wt(i->second->unserialise(string(p, len))); 309 320 p += len; 310 321 322 // Unserialise the MatchCmp object 323 len = decode_length(&p, p_end); 324 AutoPtr<Xapian::MatchCmp> mcmp; 325 if (len > 0) { 326 map<string, Xapian::MatchCmp *>::const_iterator j; 327 j = match_cmps.find(string(p, len)); 328 if (j == match_cmps.end()) { 329 throw Xapian::InvalidArgumentError("MatchCmp type " + string(p, len) + " not registered"); 330 } 331 p += len; 332 333 len = decode_length(&p, p_end); 334 mcmp = j->second->unserialise(string(p, len)); 335 p += len; 336 } 337 311 338 // Unserialise the RSet object. 312 339 Xapian::RSet rset = unserialise_rset(string(p, p_end - p)); 313 340 … … 316 343 MultiMatch match(*db, query.get(), qlen, rset, collapse_key, 317 344 percent_cutoff, weight_cutoff, order, 318 345 sort_key, sort_by, sort_value_forward, 319 0, 0, NULL, gatherer, wt.get() );346 0, 0, NULL, gatherer, wt.get(), mcmp.get()); 320 347 321 348 send_message(REPLY_STATS, serialise_stats(gatherer->get_local_stats())); 322 349 -
xapian-core/common/remote-database.h
124 124 * @param percent_cutoff Percentage cutoff. 125 125 * @param weight_cutoff Weight cutoff. 126 126 * @param wtscheme Weighting scheme. 127 * @param sort_cmpfn Comparison functor for sorting. 127 128 * @param omrset The rset. 128 129 */ 129 130 void set_query(const Xapian::Query::Internal *query, … … 135 136 bool sort_value_forward, 136 137 int percent_cutoff, Xapian::weight weight_cutoff, 137 138 const Xapian::Weight *wtscheme, 139 const Xapian::MatchCmp *sort_cmpfn, 138 140 const Xapian::RSet &omrset); 139 141 140 142 /** Get the Stats from the remote server. -
xapian-core/common/omenquireinternal.h
31 31 #include <math.h> 32 32 #include <map> 33 33 #include <set> 34 #include "document.h" 34 35 35 36 using namespace std; 36 37 … … 64 65 }; 65 66 66 67 /** An item resulting from a query. 68 * 67 69 * This item contains the document id, and the weight calculated for 68 70 * the document. 71 * 72 * It also provides access to the underlying document, 73 * and stores information needed to support collapse operations. 69 74 */ 70 75 class MSetItem { 71 76 public: 72 77 MSetItem(Xapian::weight wt_, Xapian::docid did_) 73 : wt(wt_), did(did_), collapse_count(0) {} 78 : wt(wt_), 79 did(did_), 80 collapse_count(0), 81 internal_docid(0) {} 74 82 75 MSetItem(Xapian::weight wt_, Xapian::docid did_, const string &key_) 76 : wt(wt_), did(did_), collapse_key(key_), collapse_count(0) {} 83 MSetItem(Xapian::weight wt_, 84 Xapian::docid did_, 85 const Xapian::Internal::RefCntPtr<Xapian::Database::Internal> & internal_db_, 86 Xapian::docid internal_docid_) 87 : wt(wt_), 88 did(did_), 89 collapse_count(0), 90 internal_db(internal_db_), 91 internal_docid(internal_docid_) {} 77 92 78 MSetItem(Xapian::weight wt_, Xapian::docid did_, const string &key_, 93 MSetItem(Xapian::weight wt_, 94 Xapian::docid did_, 95 const Xapian::Internal::RefCntPtr<Xapian::Database::Internal> & internal_db_, 96 Xapian::docid internal_docid_, 97 const string &collapse_key_, 79 98 Xapian::doccount collapse_count_) 80 : wt(wt_), did(did_), collapse_key(key_), 81 collapse_count(collapse_count_) {} 99 : wt(wt_), 100 did(did_), 101 collapse_key(collapse_key_), 102 collapse_count(collapse_count_), 103 internal_db(internal_db_), 104 internal_docid(internal_docid_) {} 82 105 83 106 /** Weight calculated. */ 84 107 Xapian::weight wt; 85 108 86 /** Document id . */109 /** Document id (as publically displayed). */ 87 110 Xapian::docid did; 88 111 89 112 /** Value which was used to collapse upon. … … 96 119 * for this item, the value will be a null string. Only one instance 97 120 * of each key value (apart from the null string) will be present in 98 121 * the items in the returned Xapian::MSet. 122 * 123 * FIXME - just use doc. 99 124 */ 100 125 string collapse_key; 101 126 102 /** Count of collapses done on collapse_key so far 127 /** Count of collapses done on collapse_key so far. 103 128 * 104 * This is normally 0, and goes up for each collapse done105 * It is not neccessarily an indication of how many collapses106 * might be done if an exhaustive match was done129 * This is normally 0, and goes up for each collapse done 130 * It is not neccessarily an indication of how many collapses 131 * might be done if an exhaustive match was done 107 132 */ 108 133 Xapian::doccount collapse_count; 109 134 110 /** Used when sorting by value. */ 111 /* FIXME: why not just cache the Xapian::Document here!?! */ 112 string sort_key; 135 /** Get the document. 136 * 137 * This will cache the document from previous requests, and will 138 * return a pointer to NULL if the MSetItem was not initialised with 139 * and internal_db and internal_docid. 140 */ 141 const Xapian::Internal::RefCntPtr<Xapian::Document::Internal> & 142 get_document() const 143 { 144 if (doc.get() == NULL) 145 { 146 if (internal_db.get() == NULL) 147 { 148 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(new Xapian::Document::Internal()); 149 doc = temp; 150 } else { 151 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(internal_db->open_document(internal_docid, true)); 152 doc = temp; 153 } 154 } 155 return doc; 156 } 113 157 114 158 /** Returns a string representing the mset item. 115 159 * Introspection method. 116 160 */ 117 161 string get_description() const; 162 163 private: 164 /** Database containing the document. */ 165 Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db; 166 167 /** Document id in database containing the document. */ 168 Xapian::docid internal_docid; 169 170 /** Document object. Points to NULL before the document has 171 * been requested (with get_document()). */ 172 mutable Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc; 118 173 }; 119 174 120 175 } … … 140 195 void operator=(const Internal &); 141 196 142 197 public: 143 typedef enum { REL, VAL, VAL_REL, REL_VAL } sort_setting;198 typedef enum { REL, VAL, VAL_REL, REL_VAL, USER } sort_setting; 144 199 145 200 Xapian::valueno collapse_key; 146 201 … … 153 208 Xapian::valueno sort_key; 154 209 sort_setting sort_by; 155 210 bool sort_value_forward; 211 MatchCmp * sort_cmpfn; 156 212 157 213 time_t bias_halflife; 158 214 Xapian::weight bias_weight; -
xapian-core/common/multimatch.h
68 68 /// Weighting scheme 69 69 const Xapian::Weight * weight; 70 70 71 /// User supplied match comparison function 72 const Xapian::MatchCmp * match_cmp; 73 71 74 /** Internal flag to note that w_max needs to be recalculated 72 75 * while query is running. 73 76 */ … … 75 78 76 79 /// get the collapse key 77 80 string get_collapse_key(PostList *pl, 78 Xapian:: docid did, Xapian::valueno keyno,79 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> &doc);81 Xapian::valueno keyno, 82 const Xapian::Internal::MSetItem & item); 80 83 81 84 /** get the maxweight that the postlist pl may return, calling 82 85 * recalc_maxweight if recalculate_w_max is set, and unsetting it. … … 118 121 Xapian::weight bias_weight_, 119 122 Xapian::ErrorHandler * errorhandler, 120 123 StatsGatherer * gatherer_, 121 const Xapian::Weight *wtscheme); 124 const Xapian::Weight *wtscheme, 125 const Xapian::MatchCmp * match_cmp_); 122 126 123 127 void get_mset(Xapian::doccount first, 124 128 Xapian::doccount maxitems, -
xapian-core/common/remoteprotocol.h
24 24 // Versions: 25 25 // 21: Overhauled remote backend supporting WritableDatabase 26 26 // 22: Lossless double serialisation 27 #define XAPIAN_REMOTE_PROTOCOL_VERSION 22 27 // 23: MatchCmp serialisation 28 #define XAPIAN_REMOTE_PROTOCOL_VERSION 23 28 29 29 30 /// Message types (client -> server). 30 31 enum message_type { -
xapian-core/common/remoteserver.h
67 67 /// Registered weighting schemes. 68 68 map<string, Xapian::Weight *> wtschemes; 69 69 70 /// Registered match cmpfns. 71 map<string, Xapian::MatchCmp *> match_cmps; 72 70 73 /// Initialisation code needed by both ctors. 71 74 void initialise(); 72 75 … … 176 179 void register_weighting_scheme(const Xapian::Weight &wt) { 177 180 wtschemes[wt.name()] = wt.clone(); 178 181 } 182 183 /// Register a user-defined match comparision class. 184 void register_match_cmp(const Xapian::MatchCmp &match_cmp) { 185 match_cmps[match_cmp.name()] = match_cmp.clone(); 186 } 179 187 }; 180 188 181 189 #endif // XAPIAN_INCLUDED_REMOTESERVER_H -
xapian-core/common/serialise.h
22 22 #define XAPIAN_INCLUDED_SERIALISE_H 23 23 24 24 #include <string> 25 #include <xapian/database.h> 25 26 26 27 // Forward class declarations: 27 28 … … 108 109 * 109 110 * @return The unserialised Xapian::MSet object. 110 111 */ 111 Xapian::MSet unserialise_mset(const std::string &s); 112 Xapian::MSet unserialise_mset(const std::string &s, 113 Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db); 112 114 113 115 /** Serialise a Xapian::RSet object. 114 116 * -
xapian-core/testsuite/index_utils.cc
80 80 for (Xapian::valueno i = min(para.length(), size_t(10)); i >= 1; --i) { 81 81 doc.add_value(i, para.substr(i, 1)); 82 82 } 83 if (para.length() > 1 && para[0] == 'V') { 84 doc.add_value(100, Xapian::IntegerMatchCmp::int_to_value(atoi(para.c_str() + 1))); 85 } 83 86 84 87 Xapian::termcount pos = 0; 85 88 string::const_iterator end = para.begin(); -
xapian-core/api/omenquire.cc
640 640 : db(db_), query(), collapse_key(Xapian::valueno(-1)), 641 641 order(Enquire::ASCENDING), percent_cutoff(0), weight_cutoff(0), 642 642 sort_key(Xapian::valueno(-1)), sort_by(REL), sort_value_forward(true), 643 sort_cmpfn(0), 643 644 bias_halflife(0), bias_weight(0), errorhandler(errorhandler_), weight(0) 644 645 { 645 646 } … … 647 648 Enquire::Internal::~Internal() 648 649 { 649 650 delete weight; 651 delete sort_cmpfn; 650 652 weight = 0; 651 653 } 652 654 … … 682 684 percent_cutoff, weight_cutoff, 683 685 order, sort_key, sort_by, sort_value_forward, 684 686 bias_halflife, bias_weight, errorhandler, 685 new LocalStatsGatherer(), weight );687 new LocalStatsGatherer(), weight, sort_cmpfn); 686 688 // Run query and put results into supplied Xapian::MSet object. 687 689 match.get_mset(first, maxitems, check_at_least, retval, mdecider); 688 690 } else { … … 690 692 percent_cutoff, weight_cutoff, 691 693 order, sort_key, sort_by, sort_value_forward, 692 694 bias_halflife, bias_weight, errorhandler, 693 new LocalStatsGatherer(), weight );695 new LocalStatsGatherer(), weight, sort_cmpfn); 694 696 // Run query and put results into supplied Xapian::MSet object. 695 697 match.get_mset(first, maxitems, check_at_least, retval, mdecider); 696 698 } … … 907 909 { 908 910 DEBUGAPICALL(void, "Xapian::Enquire::set_weighting_scheme", "[Weight]"); 909 911 delete internal->weight; 912 internal->weight = NULL; // Set to NULL before cloning, to avoid double free if clone() throws an exception. 910 913 internal->weight = weight_.clone(); 911 914 } 912 915 … … 939 942 Enquire::set_sort_by_relevance() 940 943 { 941 944 internal->sort_by = Internal::REL; 945 delete internal->sort_cmpfn; 946 internal->sort_cmpfn = NULL; 942 947 } 943 948 944 949 void … … 947 952 internal->sort_key = sort_key; 948 953 internal->sort_by = Internal::VAL; 949 954 internal->sort_value_forward = ascending; 955 delete internal->sort_cmpfn; 956 internal->sort_cmpfn = NULL; 950 957 } 951 958 952 959 void … … 956 963 internal->sort_key = sort_key; 957 964 internal->sort_by = Internal::VAL_REL; 958 965 internal->sort_value_forward = ascending; 966 delete internal->sort_cmpfn; 967 internal->sort_cmpfn = NULL; 959 968 } 960 969 961 970 void … … 965 974 internal->sort_key = sort_key; 966 975 internal->sort_by = Internal::REL_VAL; 967 976 internal->sort_value_forward = ascending; 977 delete internal->sort_cmpfn; 978 internal->sort_cmpfn = NULL; 968 979 } 969 980 970 981 void 982 Enquire::set_sort_by_cmpfn(const MatchCmp &cmpfn_) 983 { 984 DEBUGAPICALL(void, "Xapian::Enquire::set_sort_by_cmpfn", "[cmpfn:" << cmpfn_.name() << "(" << cmpfn_.serialise() << ")]"); 985 delete internal->sort_cmpfn; 986 internal->sort_by = Internal::USER; 987 internal->sort_cmpfn = NULL; // Set to NULL before cloning, to avoid double free if clone() throws an exception. 988 internal->sort_cmpfn = cmpfn_.clone(); 989 } 990 991 void 971 992 Enquire::set_sorting(Xapian::valueno sort_key, int sort_bands, 972 993 bool sort_by_relevance) 973 994 { -
xapian-core/backends/remote/remote-database.cc
367 367 bool sort_value_forward, 368 368 int percent_cutoff, Xapian::weight weight_cutoff, 369 369 const Xapian::Weight *wtscheme, 370 const Xapian::MatchCmp *sort_cmpfn, 370 371 const Xapian::RSet &omrset) 371 372 { 372 373 string tmp = query->serialise(); … … 383 384 message += char(percent_cutoff); 384 385 message += serialise_double(weight_cutoff); 385 386 387 // Serialise the weight scheme 386 388 tmp = wtscheme->name(); 387 389 message += encode_length(tmp.size()); 388 390 message += tmp; 389 390 391 tmp = wtscheme->serialise(); 391 392 message += encode_length(tmp.size()); 392 393 message += tmp; 393 394 395 // Serialise the match cmp object 396 if (sort_cmpfn == NULL) { 397 message += encode_length(0); 398 } else { 399 tmp = sort_cmpfn->name(); 400 message += encode_length(tmp.size()); 401 message += tmp; 402 tmp = sort_cmpfn->serialise(); 403 message += encode_length(tmp.size()); 404 message += tmp; 405 } 406 394 407 message += serialise_rset(omrset); 395 408 396 409 send_message(MSG_QUERY, message); … … 424 437 { 425 438 string message; 426 439 get_message(message, REPLY_RESULTS); 427 mset = unserialise_mset(message );440 mset = unserialise_mset(message, this); 428 441 } 429 442 430 443 void -
xapian-bindings/xapian.i
251 251 class ExpandDecider; 252 252 class MatchDecider; 253 253 class Weight; 254 class MatchCmp; 254 255 class Stopper; 255 256 256 257 // from xapian/positioniterator.h … … 582 583 bool ascending = true); 583 584 void set_sort_by_relevance_then_value(Xapian::valueno sort_key, 584 585 bool ascending = true); 586 void set_sort_by_cmpfn(const MatchCmp& cmpfn); 585 587 586 588 void set_bias(weight bias_weight, time_t bias_halflife); 587 589 … … 720 722 bool get_sumpart_needs_doclength() const; 721 723 }; 722 724 725 class MatchItem { 726 public: 727 MatchItem(const Xapian::Internal::MSetItem & item_); 728 Xapian::weight get_wt() const; 729 Xapian::docid get_docid() const; 730 Xapian::Document get_document() const; 731 }; 732 733 class MatchCmp { 734 /* SWIG doesn't handle this: 735 private: 736 virtual MatchCmp * clone() const = 0; */ 737 public: 738 virtual ~MatchCmp(); 739 740 virtual std::string name() const = 0; 741 virtual std::string serialise() const = 0; 742 virtual MatchCmp * unserialise(const std::string &s) const = 0; 743 744 virtual int cmp(const MatchItem & a, 745 const MatchItem & b) const = 0; 746 }; 747 748 %warnfilter(842) IntegerMatchCmp::unserialise; 749 class IntegerMatchCmp : public MatchCmp { 750 public: 751 IntegerMatchCmp * clone() const; 752 IntegerMatchCmp(Xapian::valueno sort_key_, 753 bool ascending = true); 754 IntegerMatchCmp(); 755 ~IntegerMatchCmp(); 756 757 std::string name() const; 758 std::string serialise() const; 759 IntegerMatchCmp * unserialise(const std::string &s) const; 760 761 int cmp(const MatchItem & a, 762 const MatchItem & b) const; 763 764 static std::string int_to_value(int num); 765 static int value_to_int(const std::string &s); 766 }; 767 768 %warnfilter(842) DoubleMatchCmp::unserialise; 769 class DoubleMatchCmp : public MatchCmp { 770 public: 771 DoubleMatchCmp * clone() const; 772 DoubleMatchCmp(Xapian::valueno sort_key_, 773 bool ascending = true); 774 DoubleMatchCmp(); 775 ~DoubleMatchCmp(); 776 777 std::string name() const; 778 std::string serialise() const; 779 DoubleMatchCmp * unserialise(const std::string &s) const; 780 781 int cmp(const MatchItem & a, 782 const MatchItem & b) const; 783 784 static std::string double_to_value(double num); 785 static double value_to_double(const std::string &s); 786 }; 787 788 723 789 // xapian/database.h 724 790 725 791 class Database {