Ticket #100: customsortorders2.patch
File customsortorders2.patch, 49.0 KB (added by , 18 years ago) |
---|
-
xapian-maintainer-tools/win32msvc/win32_matcher.mak
32 32 $(INTDIR)\multimatch.obj \ 33 33 $(INTDIR)\expand.obj \ 34 34 $(INTDIR)\stats.obj \ 35 $(INTDIR)\matchcmp.obj \ 35 36 $(INTDIR)\mergepostlist.obj \ 36 37 $(INTDIR)\msetpostlist.obj \ 37 38 $(INTDIR)\msetcmp.obj \ … … 166 167 $(CPP_PROJ) $** 167 168 << 168 169 170 "$(INTDIR)\matchcmp.obj" : ".\matchcmp.cc" 171 $(CPP) @<< 172 $(CPP_PROJ) $** 173 << 169 174 170 175 "$(INTDIR)\mergepostlist.obj" : ".\mergepostlist.cc" 171 176 $(CPP) @<< -
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/Makefile.mk
Property changes on: xapian-core/matcher/matchcmp.cc ___________________________________________________________________ Name: svn:eol-style + native
44 44 matcher/expandweight.cc\ 45 45 matcher/filterpostlist.cc\ 46 46 matcher/localmatch.cc\ 47 matcher/matchcmp.cc\ 47 48 matcher/mergepostlist.cc\ 48 49 matcher/msetcmp.cc\ 49 50 matcher/msetpostlist.cc\ -
xapian-core/matcher/multimatch.cc
89 89 Xapian::weight bias_weight_, 90 90 Xapian::ErrorHandler * errorhandler_, 91 91 StatsGatherer * gatherer_, 92 const Xapian::Weight * weight_) 92 const Xapian::Weight * weight_, 93 const Xapian::MatchCmp * match_cmp_) 93 94 : gatherer(gatherer_), db(db_), query(query_), 94 95 collapse_key(collapse_key_), percent_cutoff(percent_cutoff_), 95 96 weight_cutoff(weight_cutoff_), order(order_), … … 97 98 sort_value_forward(sort_value_forward_), 98 99 bias_halflife(bias_halflife_), bias_weight(bias_weight_), 99 100 errorhandler(errorhandler_), weight(weight_), 101 match_cmp(match_cmp_), 100 102 is_remote(db.internal.size()) 101 103 { 102 104 DEBUGCALL(MATCH, void, "MultiMatch", db_ << ", " << query_ << ", " << … … 148 150 } 149 151 rem_db->set_query(query, qlen, collapse_key, order, sort_key, 150 152 sort_by, sort_value_forward, percent_cutoff, 151 weight_cutoff, weight, subrsets[i]); 153 weight_cutoff, weight, match_cmp, 154 subrsets[i]); 152 155 bool decreasing_relevance = 153 156 (sort_by == REL || sort_by == REL_VAL); 154 157 smatch = new RemoteSubMatch(rem_db, gatherer.get(), … … 202 205 } 203 206 204 207 string 205 MultiMatch::get_collapse_key(PostList *pl, Xapian::docid did, 206 Xapian::valueno keyno, Xapian::Internal::RefCntPtr<Xapian::Document::Internal> &doc) 208 MultiMatch::get_collapse_key(PostList *pl, 209 Xapian::valueno keyno, 210 const Xapian::Internal::MSetItem & item) 207 211 { 208 DEBUGCALL(MATCH, string, "MultiMatch::get_collapse_key", pl << ", " << did << ", " << keyno << ", [doc]"); 212 DEBUGCALL(MATCH, string, "MultiMatch::get_collapse_key", pl << ", " << item.did << ", " << keyno << ", [doc]"); 213 214 // FIXME - this gets the collapse key from the postlist. This only 215 // actually happens for Mset postlists (or mergepostlists containing an 216 // mset postlist), since this is the only case where the collapse key has 217 // been read already. Instead, we should use the document object stored in 218 // the mset item. 219 209 220 const string *key = pl->get_collapse_key(); 210 221 if (key) RETURN(*key); 211 if (doc.get() == 0) { 212 unsigned int multiplier = db.internal.size(); 213 Assert(multiplier != 0); 214 Xapian::doccount n = (did - 1) % multiplier; // which actual database 215 Xapian::docid m = (did - 1) / multiplier + 1; // real docid in that database 216 217 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(db.internal[n]->open_document(m, true)); 218 doc = temp; 219 } 220 RETURN(doc->get_value(keyno)); 222 RETURN(item.get_document()->get_value(keyno)); 221 223 } 222 224 223 225 Xapian::weight … … 240 242 void 241 243 MultiMatch::get_mset(Xapian::doccount first, Xapian::doccount maxitems, 242 244 Xapian::doccount check_at_least, 243 Xapian::MSet & mset, const Xapian::MatchDecider *mdecider) 245 Xapian::MSet & mset, 246 const Xapian::MatchDecider *mdecider) 244 247 { 245 248 DEBUGCALL(MATCH, void, "MultiMatch::get_mset", first << ", " << maxitems 246 249 << ", " << check_at_least << ", ..."); … … 378 381 379 382 /// Comparison functor for sorting MSet 380 383 bool sort_forward = (order != Xapian::Enquire::DESCENDING); 381 MSetCmp mcmp(get_msetcmp_function(sort_by, sort_forward, sort_value_forward)); 384 mset_cmp cmpfn = get_msetcmp_function(sort_by, sort_forward, sort_value_forward); 385 MSetCmp mcmp(cmpfn, sort_key, match_cmp); 382 386 387 /// Number of databases making up the database we're using. 388 const unsigned int db_internal_size = db.internal.size(); 389 Assert(db_internal_size != 0); 390 383 391 // Perform query 384 392 385 393 // We form the mset in two stages. In the first we fill up our working … … 426 434 if (min_item.wt > 0.0) wt = pl->get_weight(); 427 435 428 436 DEBUGLINE(MATCH, "Candidate document id " << did << " wt " << wt); 429 Xapian::Internal::MSetItem new_item(wt, did); 430 if (sort_by != REL) { 431 const unsigned int multiplier = db.internal.size(); 432 Assert(multiplier != 0); 433 Xapian::doccount n = (new_item.did - 1) % multiplier; // which actual database 434 Xapian::docid m = (new_item.did - 1) / multiplier + 1; // real docid in that database 435 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc(db.internal[n]->open_document(m, true)); 436 new_item.sort_key = doc->get_value(sort_key); 437 } 437 Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db = db.internal[((did - 1) % db_internal_size)]; // database holding document 438 Xapian::docid internal_docid = (did - 1) / db_internal_size + 1; // docid in internal_db 439 Xapian::Internal::MSetItem new_item(wt, did, internal_db, internal_docid); 438 440 439 441 // Test if item has high enough weight (or sort key) to get into 440 442 // proto-mset. 441 443 if (sort_by != REL || min_item.wt > 0.0) 442 444 if (!mcmp(new_item, min_item)) continue; 443 445 444 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc;445 446 446 // Use the decision functor if any. 447 447 if (mdecider != NULL) { 448 448 const unsigned int multiplier = db.internal.size(); … … 451 451 // If the results are from a remote database, then the functor will 452 452 // already have been applied there so we can skip this step. 453 453 if (!is_remote[n]) { 454 if (doc.get() == 0) { 455 Xapian::docid m = (did - 1) / multiplier + 1; // real docid in that database 456 457 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(db.internal[n]->open_document(m, true)); 458 doc = temp; 459 } 460 Xapian::Document mydoc(doc.get()); 454 Xapian::Document mydoc(new_item.get_document().get()); 461 455 if (!mdecider->operator()(mydoc)) continue; 462 456 } 463 457 } … … 473 467 474 468 // Perform collapsing on key if requested. 475 469 if (collapse_key != Xapian::BAD_VALUENO) { 476 new_item.collapse_key = get_collapse_key(pl, did, collapse_key, 477 doc); 470 new_item.collapse_key = get_collapse_key(pl, collapse_key, new_item); 478 471 479 472 // Don't collapse on null key 480 473 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/tests/internaltest.cc
308 308 255.5, 309 309 256.125, 310 310 257.03125, 311 0.12268031290495594321l, 312 0.12268031290495592933l, 311 313 }; 312 314 313 315 check_double_serialisation(0.0); -
xapian-core/tests/api_db.cc
1149 1149 // set_sort_by_value 1150 1150 // set_sort_by_value_then_relevance 1151 1151 // set_sort_by_relevance_then_value 1152 // User comparison functions 1152 1153 static bool test_sortrel1() 1153 1154 { 1154 1155 Xapian::Enquire enquire(get_database("apitest_sortrel")); … … 1164 1165 const Xapian::docid order7[] = { 7,9,8,6,5,4,2,1,3 }; 1165 1166 const Xapian::docid order8[] = { 7,6,2,9,5,1,8,4,3 }; 1166 1167 const Xapian::docid order9[] = { 2,6,7,1,5,9,3,4,8 }; 1168 const Xapian::docid order10[] = { 7,9,4,5,6,1,2,3,8 }; 1169 const Xapian::docid order11[] = { 8,1,2,3,4,5,6,7,9 }; 1170 const Xapian::docid order12[] = { 9,7,6,5,4,3,2,1,8 }; 1171 const Xapian::docid order13[] = { 8,3,2,1,6,5,4,9,7 }; 1167 1172 1168 1173 Xapian::MSet mset; 1169 1174 size_t i; … … 1174 1179 TEST_EQUAL(*mset[i], order1[i]); 1175 1180 } 1176 1181 1182 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100)); 1183 1184 mset = enquire.get_mset(0, 10); 1185 TEST_EQUAL(mset.size(), sizeof(order10) / sizeof(Xapian::docid)); 1186 for (i = 0; i < sizeof(order10) / sizeof(Xapian::docid); ++i) { 1187 TEST_EQUAL(*mset[i], order10[i]); 1188 } 1189 1190 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, true)); 1191 1192 mset = enquire.get_mset(0, 10); 1193 TEST_EQUAL(mset.size(), sizeof(order10) / sizeof(Xapian::docid)); 1194 for (i = 0; i < sizeof(order10) / sizeof(Xapian::docid); ++i) { 1195 TEST_EQUAL(*mset[i], order10[i]); 1196 } 1197 1198 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, false)); 1199 1200 mset = enquire.get_mset(0, 10); 1201 TEST_EQUAL(mset.size(), sizeof(order11) / sizeof(Xapian::docid)); 1202 for (i = 0; i < sizeof(order11) / sizeof(Xapian::docid); ++i) { 1203 TEST_EQUAL(*mset[i], order11[i]); 1204 } 1205 1177 1206 enquire.set_sort_by_value_then_relevance(1); 1178 1207 1179 1208 mset = enquire.get_mset(0, 10); … … 1190 1219 TEST_EQUAL(*mset[i], order1[i]); 1191 1220 } 1192 1221 1222 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100)); 1223 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1224 1225 mset = enquire.get_mset(0, 10); 1226 TEST_EQUAL(mset.size(), sizeof(order12) / sizeof(Xapian::docid)); 1227 for (i = 0; i < sizeof(order12) / sizeof(Xapian::docid); ++i) { 1228 TEST_EQUAL(*mset[i], order12[i]); 1229 } 1230 1231 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, true)); 1232 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1233 1234 mset = enquire.get_mset(0, 10); 1235 TEST_EQUAL(mset.size(), sizeof(order12) / sizeof(Xapian::docid)); 1236 for (i = 0; i < sizeof(order12) / sizeof(Xapian::docid); ++i) { 1237 TEST_EQUAL(*mset[i], order12[i]); 1238 } 1239 1240 enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, false)); 1241 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1242 1243 mset = enquire.get_mset(0, 10); 1244 TEST_EQUAL(mset.size(), sizeof(order13) / sizeof(Xapian::docid)); 1245 for (i = 0; i < sizeof(order13) / sizeof(Xapian::docid); ++i) { 1246 TEST_EQUAL(*mset[i], order13[i]); 1247 } 1248 1193 1249 enquire.set_sort_by_value_then_relevance(1); 1194 1250 enquire.set_docid_order(Xapian::Enquire::DESCENDING); 1195 1251 -
xapian-core/tests/harness/index_utils.cc
78 78 for (Xapian::valueno i = min(para.length(), size_t(10)); i >= 1; --i) { 79 79 doc.add_value(i, para.substr(i, 1)); 80 80 } 81 if (para.length() > 1 && para[0] == 'V') { 82 doc.add_value(100, Xapian::IntegerMatchCmp::int_to_value(atoi(para.c_str() + 1))); 83 } 81 84 82 85 Xapian::termcount pos = 0; 83 86 string::const_iterator end = para.begin(); -
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. … … 1260 1283 bool get_sumpart_needs_doclength() const; 1261 1284 }; 1262 1285 1286 /// An item matching a search. 1287 class MatchItem { 1288 private: 1289 const Xapian::Internal::MSetItem & item; 1290 1291 public: 1292 MatchItem(const Xapian::Internal::MSetItem & item_) 1293 : item(item_) {} 1294 1295 /** Get the weight calculated. */ 1296 Xapian::weight get_wt() const; 1297 1298 /** Get the document id. */ 1299 Xapian::docid get_docid() const; 1300 1301 /** Get the document object, for access to document data, values, 1302 * and terms. */ 1303 Xapian::Document get_document() const; 1304 }; 1305 1306 /// Abstract base class for match comparison functors. 1307 class MatchCmp { 1308 friend class Enquire; // So Enquire can clone us 1309 friend class ::RemoteServer; // So RemoteServer can clone us - FIXME 1310 protected: 1311 MatchCmp(const MatchCmp &); 1312 private: 1313 void operator=(MatchCmp &); 1314 1315 /** Return a new MatchCmp object of this type. 1316 * 1317 * A subclass called FooMatchCmp taking parameters param1 and param2 1318 * should implement this as: 1319 * 1320 * virtual FooMatchCmp * clone() const { 1321 * return new FooMatchCmp(param1, param2); 1322 * } 1323 */ 1324 virtual MatchCmp * clone() const = 0; 1325 1326 public: 1327 MatchCmp() { } 1328 virtual ~MatchCmp() { } 1329 1330 /** Name of the comparison functor. 1331 * 1332 * If the subclass is called FooMatchCmp, this should return "Foo". 1333 */ 1334 virtual std::string name() const = 0; 1335 1336 /// Serialise object parameters into a string. 1337 virtual std::string serialise() const = 0; 1338 1339 /** Create object given string serialisation returned by serialise(). 1340 * 1341 * If the string is not a valid serialised form, this should raise a 1342 * Xapian::NetworkError; 1343 */ 1344 virtual MatchCmp * unserialise(const std::string &s) const = 0; 1345 1346 /** Compare a potential Mset entry a to an entry b. 1347 * 1348 * This function should return an integer less than 0 if MatchItem a 1349 * should be ranked below MatchItem b, and greater than 0 if MatchItem 1350 * a should be ranked above MatchItem b. The function may return 0 if 1351 * it considers the two match items to be equal. 1352 * 1353 * The function will never be called with items which have identical 1354 * document IDs. 1355 * 1356 * The comparison function must be well behaved, such that: 1357 * 1358 * - it must produce the same result if called a second time on a 1359 * particular pair of documents 1360 * - if cmp(x,y) is less than 0 and cmp(y,z) is less than 0, cmp(x,z) 1361 * must be less than 0. 1362 * - if cmp(x,y) is less than 0, cmp(y,x) must be greater than 0. 1363 * 1364 * Bear in mind that the comparison will be performed very frequently 1365 * when performing a search, so must be as fast as possible. In 1366 * particular, although the MatchItem provides access to the document 1367 * object, it is recommended that only the value items stored in the 1368 * document object are accessed. 1369 */ 1370 virtual int cmp(const MatchItem & a, 1371 const MatchItem & b) const = 0; 1372 }; 1373 1374 /** Comparison function for comparing by value as integer. 1375 */ 1376 class IntegerMatchCmp : public MatchCmp { 1377 Xapian::valueno sort_key; 1378 int direction; 1379 public: 1380 /** Return a new IntegerMatchCmp with the same parameters as this one. 1381 */ 1382 IntegerMatchCmp * clone() const { 1383 return new IntegerMatchCmp(sort_key, direction == 1); 1384 } 1385 IntegerMatchCmp(Xapian::valueno sort_key_, 1386 bool ascending = true) 1387 : sort_key(sort_key_), 1388 direction(ascending ? 1 : -1) { } 1389 IntegerMatchCmp() 1390 : sort_key(0), 1391 direction(1) { } 1392 ~IntegerMatchCmp() { } 1393 std::string name() const { return "Integer"; } 1394 1395 std::string serialise() const; 1396 IntegerMatchCmp * unserialise(const std::string &s) const; 1397 1398 int cmp(const MatchItem & a, 1399 const MatchItem & b) const; 1400 1401 /** Convert an integer to a string, suitable for comparing with this 1402 * comparison functor. 1403 */ 1404 static std::string int_to_value(int num); 1405 1406 /** Convert a string suitable for comparison with this comparison 1407 * functor to an integer. 1408 */ 1409 static int value_to_int(const std::string &s); 1410 }; 1411 1412 /** Comparison function for comparing by value as a double. 1413 */ 1414 class DoubleMatchCmp : public MatchCmp { 1415 Xapian::valueno sort_key; 1416 int direction; 1417 public: 1418 /** Return a new DoubleMatchCmp with the same parameters as this one. 1419 */ 1420 DoubleMatchCmp * clone() const { 1421 return new DoubleMatchCmp(sort_key, direction == 1); 1422 } 1423 DoubleMatchCmp(Xapian::valueno sort_key_, 1424 bool ascending = true) 1425 : sort_key(sort_key_), 1426 direction(ascending ? 1 : -1) { } 1427 DoubleMatchCmp() 1428 : sort_key(0), 1429 direction(1) { } 1430 ~DoubleMatchCmp() { } 1431 std::string name() const { return "Double"; } 1432 1433 std::string serialise() const; 1434 DoubleMatchCmp * unserialise(const std::string &s) const; 1435 1436 int cmp(const MatchItem & a, 1437 const MatchItem & b) const; 1438 1439 /** Convert a double to a string, suitable for comparing with this 1440 * comparison functor. 1441 */ 1442 static std::string double_to_value(double num); 1443 1444 /** Convert a string suitable for comparison with this comparison 1445 * functor to a double. 1446 */ 1447 static double value_to_double(const std::string &s); 1448 }; 1449 1263 1450 } 1264 1451 1265 1452 #endif /* XAPIAN_INCLUDED_ENQUIRE_H */ -
xapian-core/net/serialise.cc
217 217 } 218 218 219 219 Xapian::MSet 220 unserialise_mset(const string &s) 220 unserialise_mset(const string &s, 221 Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db) 221 222 { 222 223 const char * p = s.data(); 223 224 const char * p_end = p + s.size(); … … 236 237 size_t len = decode_length(&p, p_end); 237 238 string key(p, len); 238 239 p += len; 239 items.push_back(Xapian::Internal::MSetItem(wt, did, key, 240 items.push_back(Xapian::Internal::MSetItem(wt, did, 241 internal_db, 242 did, 243 key, 240 244 decode_length(&p, p_end))); 241 245 } 242 246 -
xapian-core/net/remoteserver.cc
90 90 wtschemes[weight->name()] = weight; 91 91 weight = new Xapian::TradWeight(); 92 92 wtschemes[weight->name()] = weight; 93 94 // Register match comparison functions. 95 Xapian::MatchCmp * match_cmp; 96 match_cmp = new Xapian::IntegerMatchCmp(); 97 match_cmps[match_cmp->name()] = match_cmp; 98 match_cmp = new Xapian::DoubleMatchCmp(); 99 match_cmps[match_cmp->name()] = match_cmp; 93 100 } 94 101 95 102 RemoteServer::~RemoteServer() … … 98 105 for (i = wtschemes.begin(); i != wtschemes.end(); ++i) { 99 106 delete i->second; 100 107 } 108 map<string, Xapian::MatchCmp*>::const_iterator j; 109 for (j = match_cmps.begin(); j != match_cmps.end(); ++j) { 110 delete j->second; 111 } 101 112 } 102 113 103 114 message_type … … 278 289 279 290 Xapian::valueno sort_key = decode_length(&p, p_end); 280 291 281 if (*p < '0' || *p > ' 3') {292 if (*p < '0' || *p > '4') { 282 293 throw Xapian::NetworkError("bad message (sort_by)"); 283 294 } 284 295 Xapian::Enquire::Internal::sort_setting sort_by; … … 312 323 AutoPtr<Xapian::Weight> wt(i->second->unserialise(string(p, len))); 313 324 p += len; 314 325 326 // Unserialise the MatchCmp object 327 len = decode_length(&p, p_end); 328 AutoPtr<Xapian::MatchCmp> mcmp; 329 if (len > 0) { 330 map<string, Xapian::MatchCmp *>::const_iterator j; 331 j = match_cmps.find(string(p, len)); 332 if (j == match_cmps.end()) { 333 throw Xapian::InvalidArgumentError("MatchCmp type " + string(p, len) + " not registered"); 334 } 335 p += len; 336 337 len = decode_length(&p, p_end); 338 mcmp = j->second->unserialise(string(p, len)); 339 p += len; 340 } 341 315 342 // Unserialise the RSet object. 316 343 Xapian::RSet rset = unserialise_rset(string(p, p_end - p)); 317 344 … … 320 347 MultiMatch match(*db, query.get(), qlen, rset, collapse_key, 321 348 percent_cutoff, weight_cutoff, order, 322 349 sort_key, sort_by, sort_value_forward, 323 0, 0, NULL, gatherer, wt.get() );350 0, 0, NULL, gatherer, wt.get(), mcmp.get()); 324 351 325 352 send_message(REPLY_STATS, serialise_stats(gatherer->get_local_stats())); 326 353 -
xapian-core/common/remote-database.h
122 122 * @param percent_cutoff Percentage cutoff. 123 123 * @param weight_cutoff Weight cutoff. 124 124 * @param wtscheme Weighting scheme. 125 * @param sort_cmpfn Comparison functor for sorting. 125 126 * @param omrset The rset. 126 127 */ 127 128 void set_query(const Xapian::Query::Internal *query, … … 133 134 bool sort_value_forward, 134 135 int percent_cutoff, Xapian::weight weight_cutoff, 135 136 const Xapian::Weight *wtscheme, 137 const Xapian::MatchCmp *sort_cmpfn, 136 138 const Xapian::RSet &omrset); 137 139 138 140 /** 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 */ … … 78 81 79 82 /// get the collapse key 80 83 string get_collapse_key(PostList *pl, 81 Xapian:: docid did, Xapian::valueno keyno,82 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> &doc);84 Xapian::valueno keyno, 85 const Xapian::Internal::MSetItem & item); 83 86 84 87 /** get the maxweight that the postlist pl may return, calling 85 88 * recalc_maxweight if recalculate_w_max is set, and unsetting it. … … 121 124 Xapian::weight bias_weight_, 122 125 Xapian::ErrorHandler * errorhandler, 123 126 StatsGatherer * gatherer_, 124 const Xapian::Weight *wtscheme); 127 const Xapian::Weight *wtscheme, 128 const Xapian::MatchCmp * match_cmp_); 125 129 126 130 void get_mset(Xapian::doccount first, 127 131 Xapian::doccount maxitems, -
xapian-core/common/remoteprotocol.h
26 26 // 22: Lossless double serialisation 27 27 // 23: Support get_lastdocid() on remote databases 28 28 // 24: Support for OP_VALUE_RANGE in query serialisation 29 #define XAPIAN_REMOTE_PROTOCOL_VERSION 24 29 // 25: MatchCmp serialisation 30 #define XAPIAN_REMOTE_PROTOCOL_VERSION 25 30 31 31 32 /// Message types (client -> server). 32 33 enum message_type { -
xapian-core/common/remoteserver.h
66 66 /// Registered weighting schemes. 67 67 map<string, Xapian::Weight *> wtschemes; 68 68 69 /// Registered match cmpfns. 70 map<string, Xapian::MatchCmp *> match_cmps; 71 69 72 /// Initialisation code needed by both ctors. 70 73 void initialise(); 71 74 … … 175 178 void register_weighting_scheme(const Xapian::Weight &wt) { 176 179 wtschemes[wt.name()] = wt.clone(); 177 180 } 181 182 /// Register a user-defined match comparision class. 183 void register_match_cmp(const Xapian::MatchCmp &match_cmp) { 184 match_cmps[match_cmp.name()] = match_cmp.clone(); 185 } 178 186 }; 179 187 180 188 #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/api/omenquire.cc
644 644 : db(db_), query(), collapse_key(Xapian::BAD_VALUENO), 645 645 order(Enquire::ASCENDING), percent_cutoff(0), weight_cutoff(0), 646 646 sort_key(Xapian::BAD_VALUENO), sort_by(REL), sort_value_forward(true), 647 sort_cmpfn(0), 647 648 bias_halflife(0), bias_weight(0), errorhandler(errorhandler_), weight(0) 648 649 { 649 650 } … … 651 652 Enquire::Internal::~Internal() 652 653 { 653 654 delete weight; 655 delete sort_cmpfn; 654 656 weight = 0; 655 657 } 656 658 … … 686 688 percent_cutoff, weight_cutoff, 687 689 order, sort_key, sort_by, sort_value_forward, 688 690 bias_halflife, bias_weight, errorhandler, 689 new LocalStatsGatherer(), weight );691 new LocalStatsGatherer(), weight, sort_cmpfn); 690 692 // Run query and put results into supplied Xapian::MSet object. 691 693 match.get_mset(first, maxitems, check_at_least, retval, mdecider); 692 694 } else { … … 694 696 percent_cutoff, weight_cutoff, 695 697 order, sort_key, sort_by, sort_value_forward, 696 698 bias_halflife, bias_weight, errorhandler, 697 new LocalStatsGatherer(), weight );699 new LocalStatsGatherer(), weight, sort_cmpfn); 698 700 // Run query and put results into supplied Xapian::MSet object. 699 701 match.get_mset(first, maxitems, check_at_least, retval, mdecider); 700 702 } … … 911 913 { 912 914 DEBUGAPICALL(void, "Xapian::Enquire::set_weighting_scheme", "[Weight]"); 913 915 delete internal->weight; 916 internal->weight = NULL; // Set to NULL before cloning, to avoid double free if clone() throws an exception. 914 917 internal->weight = weight_.clone(); 915 918 } 916 919 … … 943 946 Enquire::set_sort_by_relevance() 944 947 { 945 948 internal->sort_by = Internal::REL; 949 delete internal->sort_cmpfn; 950 internal->sort_cmpfn = NULL; 946 951 } 947 952 948 953 void … … 951 956 internal->sort_key = sort_key; 952 957 internal->sort_by = Internal::VAL; 953 958 internal->sort_value_forward = ascending; 959 delete internal->sort_cmpfn; 960 internal->sort_cmpfn = NULL; 954 961 } 955 962 956 963 void … … 960 967 internal->sort_key = sort_key; 961 968 internal->sort_by = Internal::VAL_REL; 962 969 internal->sort_value_forward = ascending; 970 delete internal->sort_cmpfn; 971 internal->sort_cmpfn = NULL; 963 972 } 964 973 965 974 void … … 969 978 internal->sort_key = sort_key; 970 979 internal->sort_by = Internal::REL_VAL; 971 980 internal->sort_value_forward = ascending; 981 delete internal->sort_cmpfn; 982 internal->sort_cmpfn = NULL; 972 983 } 973 984 974 985 void 986 Enquire::set_sort_by_cmpfn(const MatchCmp &cmpfn_) 987 { 988 DEBUGAPICALL(void, "Xapian::Enquire::set_sort_by_cmpfn", "[cmpfn:" << cmpfn_.name() << "(" << cmpfn_.serialise() << ")]"); 989 delete internal->sort_cmpfn; 990 internal->sort_by = Internal::USER; 991 internal->sort_cmpfn = NULL; // Set to NULL before cloning, to avoid double free if clone() throws an exception. 992 internal->sort_cmpfn = cmpfn_.clone(); 993 } 994 995 void 975 996 Enquire::set_sorting(Xapian::valueno sort_key, int sort_bands, 976 997 bool sort_by_relevance) 977 998 { -
xapian-core/backends/remote/remote-database.cc
379 379 bool sort_value_forward, 380 380 int percent_cutoff, Xapian::weight weight_cutoff, 381 381 const Xapian::Weight *wtscheme, 382 const Xapian::MatchCmp *sort_cmpfn, 382 383 const Xapian::RSet &omrset) 383 384 { 384 385 string tmp = query->serialise(); … … 395 396 message += char(percent_cutoff); 396 397 message += serialise_double(weight_cutoff); 397 398 399 // Serialise the weight scheme 398 400 tmp = wtscheme->name(); 399 401 message += encode_length(tmp.size()); 400 402 message += tmp; 401 402 403 tmp = wtscheme->serialise(); 403 404 message += encode_length(tmp.size()); 404 405 message += tmp; 405 406 407 // Serialise the match cmp object 408 if (sort_cmpfn == NULL) { 409 message += encode_length(0); 410 } else { 411 tmp = sort_cmpfn->name(); 412 message += encode_length(tmp.size()); 413 message += tmp; 414 tmp = sort_cmpfn->serialise(); 415 message += encode_length(tmp.size()); 416 message += tmp; 417 } 418 406 419 message += serialise_rset(omrset); 407 420 408 421 send_message(MSG_QUERY, message); … … 436 449 { 437 450 string message; 438 451 get_message(message, REPLY_RESULTS); 439 mset = unserialise_mset(message );452 mset = unserialise_mset(message, this); 440 453 } 441 454 442 455 void -
xapian-bindings/xapian.i
149 149 int xapian_revision(); 150 150 151 151 class Weight; 152 class MatchCmp; 152 153 class Stopper; 153 154 154 155 // from xapian/positioniterator.h … … 488 489 bool ascending = true); 489 490 void set_sort_by_relevance_then_value(Xapian::valueno sort_key, 490 491 bool ascending = true); 492 void set_sort_by_cmpfn(const MatchCmp& cmpfn); 491 493 492 494 void set_bias(weight bias_weight, time_t bias_halflife); 493 495 … … 643 645 bool get_sumpart_needs_doclength() const; 644 646 }; 645 647 648 class MatchItem { 649 public: 650 MatchItem(const Xapian::Internal::MSetItem & item_); 651 Xapian::weight get_wt() const; 652 Xapian::docid get_docid() const; 653 Xapian::Document get_document() const; 654 }; 655 656 class MatchCmp { 657 /* SWIG doesn't handle this: 658 private: 659 virtual MatchCmp * clone() const = 0; */ 660 public: 661 virtual ~MatchCmp(); 662 663 virtual std::string name() const = 0; 664 virtual std::string serialise() const = 0; 665 virtual MatchCmp * unserialise(const std::string &s) const = 0; 666 667 virtual int cmp(const MatchItem & a, 668 const MatchItem & b) const = 0; 669 }; 670 671 %warnfilter(842) IntegerMatchCmp::unserialise; 672 class IntegerMatchCmp : public MatchCmp { 673 public: 674 IntegerMatchCmp * clone() const; 675 IntegerMatchCmp(Xapian::valueno sort_key_, 676 bool ascending = true); 677 IntegerMatchCmp(); 678 ~IntegerMatchCmp(); 679 680 std::string name() const; 681 std::string serialise() const; 682 IntegerMatchCmp * unserialise(const std::string &s) const; 683 684 int cmp(const MatchItem & a, 685 const MatchItem & b) const; 686 687 static std::string int_to_value(int num); 688 static int value_to_int(const std::string &s); 689 }; 690 691 %warnfilter(842) DoubleMatchCmp::unserialise; 692 class DoubleMatchCmp : public MatchCmp { 693 public: 694 DoubleMatchCmp * clone() const; 695 DoubleMatchCmp(Xapian::valueno sort_key_, 696 bool ascending = true); 697 DoubleMatchCmp(); 698 ~DoubleMatchCmp(); 699 700 std::string name() const; 701 std::string serialise() const; 702 DoubleMatchCmp * unserialise(const std::string &s) const; 703 704 int cmp(const MatchItem & a, 705 const MatchItem & b) const; 706 707 static std::string double_to_value(double num); 708 static double value_to_double(const std::string &s); 709 }; 710 711 646 712 // xapian/database.h 647 713 648 714 class Database {