Branch data Line data Source code
1 : : /** @file postingsource.cc
2 : : * @brief External sources of posting information
3 : : */
4 : : /* Copyright (C) 2008,2009,2010 Olly Betts
5 : : * Copyright (C) 2008,2009 Lemur Consulting Ltd
6 : : * Copyright (C) 2010 Richard Boulton
7 : : *
8 : : * This program is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU General Public License as
10 : : * published by the Free Software Foundation; either version 2 of the
11 : : * License, or (at your option) any later version.
12 : : *
13 : : * This program is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : * GNU General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU General Public License
19 : : * along with this program; if not, write to the Free Software
20 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 : : */
22 : :
23 : : #include <config.h>
24 : :
25 : : #include "xapian/postingsource.h"
26 : :
27 : : #include "autoptr.h"
28 : :
29 : : #include "database.h"
30 : : #include "document.h"
31 : : #include "multimatch.h"
32 : :
33 : : #include "xapian/document.h"
34 : : #include "xapian/error.h"
35 : : #include "xapian/queryparser.h" // For sortable_unserialise().
36 : :
37 : : #include "omassert.h"
38 : : #include "serialise.h"
39 : : #include "serialise-double.h"
40 : : #include "str.h"
41 : :
42 : : #include <cfloat>
43 : :
44 : : using namespace std;
45 : :
46 : : namespace Xapian {
47 : :
48 [ # # ][ # # ]: 8707 : PostingSource::~PostingSource() { }
[ - + ]
49 : :
50 : : void
51 : 4030 : PostingSource::set_maxweight(Xapian::weight max_weight)
52 : : {
53 [ + + ]: 4030 : if (usual(matcher_)) {
54 : 522 : MultiMatch * multimatch = static_cast<MultiMatch*>(matcher_);
55 : 522 : multimatch->recalc_maxweight();
56 : : }
57 : 4030 : max_weight_ = max_weight;
58 : 4030 : }
59 : :
60 : : Xapian::weight
61 : 36 : PostingSource::get_weight() const
62 : : {
63 : 36 : return 0;
64 : : }
65 : :
66 : : void
67 : 0 : PostingSource::skip_to(Xapian::docid did, Xapian::weight min_wt)
68 : : {
69 [ # # ][ # # ]: 0 : while (!at_end() && get_docid() < did) {
[ # # ]
70 : 0 : next(min_wt);
71 : : }
72 : 0 : }
73 : :
74 : : bool
75 : 77 : PostingSource::check(Xapian::docid did, Xapian::weight min_wt)
76 : : {
77 : 77 : skip_to(did, min_wt);
78 : 77 : return true;
79 : : }
80 : :
81 : : PostingSource *
82 : 24 : PostingSource::clone() const
83 : : {
84 : 24 : return NULL;
85 : : }
86 : :
87 : : string
88 : 12 : PostingSource::name() const
89 : : {
90 : 12 : return string();
91 : : }
92 : :
93 : : string
94 : 1 : PostingSource::serialise() const
95 : : {
96 : 1 : throw Xapian::UnimplementedError("serialise() not supported for this PostingSource");
97 : : }
98 : :
99 : : PostingSource *
100 : 1 : PostingSource::unserialise(const string &) const
101 : : {
102 : 1 : throw Xapian::UnimplementedError("unserialise() not supported for this PostingSource");
103 : : }
104 : :
105 : : string
106 : 1 : PostingSource::get_description() const
107 : : {
108 : 1 : return "Xapian::PostingSource subclass";
109 : : }
110 : :
111 : :
112 : 5447 : ValuePostingSource::ValuePostingSource(Xapian::valueno slot_)
113 : 5447 : : slot(slot_)
114 : : {
115 : 5447 : }
116 : :
117 : : Xapian::doccount
118 : 211 : ValuePostingSource::get_termfreq_min() const
119 : : {
120 : 211 : return termfreq_min;
121 : : }
122 : :
123 : : Xapian::doccount
124 : 251 : ValuePostingSource::get_termfreq_est() const
125 : : {
126 : 251 : return termfreq_est;
127 : : }
128 : :
129 : : Xapian::doccount
130 : 211 : ValuePostingSource::get_termfreq_max() const
131 : : {
132 : 211 : return termfreq_max;
133 : : }
134 : :
135 : : void
136 : 1695 : ValuePostingSource::next(Xapian::weight min_wt)
137 : : {
138 [ + + ]: 1695 : if (!started) {
139 : 272 : started = true;
140 : 272 : value_it = db.valuestream_begin(slot);
141 : : } else {
142 : 1423 : ++value_it;
143 : : }
144 : :
145 [ + + ]: 1695 : if (value_it == db.valuestream_end(slot)) return;
146 : :
147 [ - + ]: 1453 : if (min_wt > get_maxweight()) {
148 : 0 : value_it = db.valuestream_end(slot);
149 : 1695 : return;
150 : : }
151 : : }
152 : :
153 : : void
154 : 55 : ValuePostingSource::skip_to(Xapian::docid min_docid, Xapian::weight min_wt)
155 : : {
156 [ + + ]: 55 : if (!started) {
157 : 17 : started = true;
158 : 17 : value_it = db.valuestream_begin(slot);
159 : :
160 [ + + ]: 17 : if (value_it == db.valuestream_end(slot)) return;
161 : : }
162 : :
163 [ - + ]: 45 : if (min_wt > get_maxweight()) {
164 : 0 : value_it = db.valuestream_end(slot);
165 : 0 : return;
166 : : }
167 : 55 : value_it.skip_to(min_docid);
168 : : }
169 : :
170 : : bool
171 : 292 : ValuePostingSource::check(Xapian::docid min_docid,
172 : : Xapian::weight min_wt)
173 : : {
174 [ + + ]: 292 : if (!started) {
175 : 56 : started = true;
176 : 56 : value_it = db.valuestream_begin(slot);
177 : :
178 [ + + ]: 56 : if (value_it == db.valuestream_end(slot)) return true;
179 : : }
180 : :
181 [ - + ]: 282 : if (min_wt > get_maxweight()) {
182 : 0 : value_it = db.valuestream_end(slot);
183 : 0 : return true;
184 : : }
185 : 292 : return value_it.check(min_docid);
186 : : }
187 : :
188 : : bool
189 : 2079 : ValuePostingSource::at_end() const
190 : : {
191 [ + + ][ + + ]: 2079 : return started && value_it == db.valuestream_end(slot);
192 : : }
193 : :
194 : : Xapian::docid
195 : 2420 : ValuePostingSource::get_docid() const
196 : : {
197 : 2420 : return value_it.get_docid();
198 : : }
199 : :
200 : : void
201 : 354 : ValuePostingSource::init(const Database & db_)
202 : : {
203 : 354 : db = db_;
204 : 354 : started = false;
205 : 354 : set_maxweight(DBL_MAX);
206 : : try {
207 : 354 : termfreq_max = db.get_value_freq(slot);
208 : 253 : termfreq_est = termfreq_max;
209 : 253 : termfreq_min = termfreq_max;
210 : 202 : } catch (const Xapian::UnimplementedError &) {
211 : 101 : termfreq_max = db.get_doccount();
212 : 101 : termfreq_est = termfreq_max / 2;
213 : 101 : termfreq_min = 0;
214 : : }
215 : 354 : }
216 : :
217 : :
218 : 3742 : ValueWeightPostingSource::ValueWeightPostingSource(Xapian::valueno slot_)
219 : 3742 : : ValuePostingSource(slot_)
220 : : {
221 : 3742 : }
222 : :
223 : : Xapian::weight
224 : 1246 : ValueWeightPostingSource::get_weight() const
225 : : {
226 : : Assert(!at_end());
227 : : Assert(started);
228 : 1246 : return sortable_unserialise(*value_it);
229 : : }
230 : :
231 : : ValueWeightPostingSource *
232 : 151 : ValueWeightPostingSource::clone() const
233 : : {
234 : 151 : return new ValueWeightPostingSource(slot);
235 : : }
236 : :
237 : : string
238 : 1596 : ValueWeightPostingSource::name() const
239 : : {
240 : 1596 : return string("Xapian::ValueWeightPostingSource");
241 : : }
242 : :
243 : : string
244 : 20 : ValueWeightPostingSource::serialise() const
245 : : {
246 : 20 : return encode_length(slot);
247 : : }
248 : :
249 : : ValueWeightPostingSource *
250 : 20 : ValueWeightPostingSource::unserialise(const string &s) const
251 : : {
252 : 20 : const char * p = s.data();
253 : 20 : const char * end = p + s.size();
254 : :
255 : 20 : Xapian::valueno new_valno = decode_length(&p, end, false);
256 [ - + ]: 20 : if (p != end) {
257 : 0 : throw Xapian::NetworkError("Bad serialised ValueWeightPostingSource - junk at end");
258 : : }
259 : :
260 : 20 : return new ValueWeightPostingSource(new_valno);
261 : : }
262 : :
263 : : void
264 : 292 : ValueWeightPostingSource::init(const Database & db_)
265 : : {
266 : 292 : ValuePostingSource::init(db_);
267 : :
268 : 292 : string upper_bound;
269 : : try {
270 : 292 : upper_bound = db.get_value_upper_bound(slot);
271 : 82 : } catch (const Xapian::UnimplementedError &) {
272 : : // ValuePostingSource::init() set the maxweight to DBL_MAX.
273 : : return;
274 : : }
275 : :
276 [ + + ]: 210 : if (upper_bound.empty()) {
277 : : // This should only happen if there are no entries, in which case the
278 : : // maxweight is 0.
279 : 13 : set_maxweight(0.0);
280 : : } else {
281 : 210 : set_maxweight(sortable_unserialise(upper_bound));
282 : 292 : }
283 : : }
284 : :
285 : : string
286 : 7 : ValueWeightPostingSource::get_description() const
287 : : {
288 : 7 : string desc("Xapian::ValueWeightPostingSource(slot=");
289 : 7 : desc += str(slot);
290 : 7 : desc += ")";
291 : 0 : return desc;
292 : : }
293 : :
294 : :
295 : 1696 : ValueMapPostingSource::ValueMapPostingSource(Xapian::valueno slot_)
296 : : : ValuePostingSource(slot_),
297 : : default_weight(0.0),
298 : 1696 : max_weight_in_map(0.0)
299 : : {
300 : 1696 : }
301 : :
302 : : void
303 : 480 : ValueMapPostingSource::add_mapping(const string & key, double weight)
304 : : {
305 : 480 : weight_map[key] = weight;
306 : 480 : max_weight_in_map = max(weight, max_weight_in_map);
307 : 480 : }
308 : :
309 : : void
310 : 13 : ValueMapPostingSource::clear_mappings()
311 : : {
312 : 13 : weight_map.clear();
313 : 13 : max_weight_in_map = 0.0;
314 : 13 : }
315 : :
316 : : void
317 : 89 : ValueMapPostingSource::set_default_weight(double wt)
318 : : {
319 : 89 : default_weight = wt;
320 : 89 : }
321 : :
322 : : Xapian::weight
323 : 442 : ValueMapPostingSource::get_weight() const
324 : : {
325 : 442 : map<string, double>::const_iterator wit = weight_map.find(*value_it);
326 [ + + ]: 442 : if (wit == weight_map.end()) {
327 : 312 : return default_weight;
328 : : }
329 : 442 : return wit->second;
330 : : }
331 : :
332 : : ValueMapPostingSource *
333 : 60 : ValueMapPostingSource::clone() const
334 : : {
335 : 60 : AutoPtr<ValueMapPostingSource> res(new ValueMapPostingSource(slot));
336 : 60 : map<string, double>::const_iterator i;
337 [ + + ]: 350 : for (i = weight_map.begin(); i != weight_map.end(); ++i) {
338 : 290 : res->add_mapping(i->first, i->second);
339 : : }
340 : 60 : res->set_default_weight(default_weight);
341 : 60 : return res.release();
342 : : }
343 : :
344 : : string
345 : 1590 : ValueMapPostingSource::name() const
346 : : {
347 : 1590 : return string("Xapian::ValueMapPostingSource");
348 : : }
349 : :
350 : : string
351 : 14 : ValueMapPostingSource::serialise() const
352 : : {
353 : 14 : string result = encode_length(slot);
354 : 14 : result += serialise_double(default_weight);
355 : :
356 : 14 : map<string, double>::const_iterator i;
357 [ + + ]: 74 : for (i = weight_map.begin(); i != weight_map.end(); ++i) {
358 : 60 : result.append(encode_length(i->first.size()));
359 : 60 : result.append(i->first);
360 : 60 : result.append(serialise_double(i->second));
361 : : }
362 : :
363 : 0 : return result;
364 : : }
365 : :
366 : : ValueMapPostingSource *
367 : 14 : ValueMapPostingSource::unserialise(const string &s) const
368 : : {
369 : 14 : const char * p = s.data();
370 : 14 : const char * end = p + s.size();
371 : :
372 : 14 : Xapian::valueno new_slot = decode_length(&p, end, false);
373 : 14 : AutoPtr<ValueMapPostingSource> res(new ValueMapPostingSource(new_slot));
374 : 14 : res->set_default_weight(unserialise_double(&p, end));
375 [ + + ]: 74 : while (p != end) {
376 : 60 : size_t keylen = decode_length(&p, end, true);
377 : 60 : string key(p, keylen);
378 : 60 : p += keylen;
379 : 60 : res->add_mapping(key, unserialise_double(&p, end));
380 : : }
381 : 14 : return res.release();
382 : : }
383 : :
384 : : void
385 : 62 : ValueMapPostingSource::init(const Database & db_)
386 : : {
387 : 62 : ValuePostingSource::init(db_);
388 : 62 : set_maxweight(max(max_weight_in_map, default_weight));
389 : 62 : }
390 : :
391 : : string
392 : 7 : ValueMapPostingSource::get_description() const
393 : : {
394 : 7 : string desc("Xapian::ValueMapPostingSource(slot=");
395 : 7 : desc += str(slot);
396 : 7 : desc += ")";
397 : 0 : return desc;
398 : : }
399 : :
400 : 1704 : FixedWeightPostingSource::FixedWeightPostingSource(Xapian::weight wt)
401 : 1704 : : started(false)
402 : : {
403 : : // The weight is fixed at wt, so that's the maxweight too. So just store wt
404 : : // as the maxweight and we can read it from there when we need it.
405 : 1704 : set_maxweight(wt);
406 : 1704 : }
407 : :
408 : : Xapian::doccount
409 : 24 : FixedWeightPostingSource::get_termfreq_min() const
410 : : {
411 : 24 : return termfreq;
412 : : }
413 : :
414 : : Xapian::doccount
415 : 32 : FixedWeightPostingSource::get_termfreq_est() const
416 : : {
417 : 32 : return termfreq;
418 : : }
419 : :
420 : : Xapian::doccount
421 : 24 : FixedWeightPostingSource::get_termfreq_max() const
422 : : {
423 : 24 : return termfreq;
424 : : }
425 : :
426 : : Xapian::weight
427 : 249 : FixedWeightPostingSource::get_weight() const
428 : : {
429 : 249 : return get_maxweight();
430 : : }
431 : :
432 : : void
433 : 290 : FixedWeightPostingSource::next(Xapian::weight min_wt)
434 : : {
435 [ + + ]: 290 : if (!started) {
436 : 43 : started = true;
437 : 43 : it = db.postlist_begin(string());
438 : : } else {
439 : 247 : ++it;
440 : : }
441 : :
442 [ + + ]: 290 : if (it == db.postlist_end(string())) return;
443 : :
444 [ + + ]: 273 : if (check_docid) {
445 : 13 : it.skip_to(check_docid + 1);
446 : 13 : check_docid = 0;
447 : : }
448 : :
449 [ + + ]: 273 : if (min_wt > get_maxweight()) {
450 : 290 : it = db.postlist_end(string());
451 : : }
452 : : }
453 : :
454 : : void
455 : 40 : FixedWeightPostingSource::skip_to(Xapian::docid min_docid,
456 : : Xapian::weight min_wt)
457 : : {
458 [ + + ]: 40 : if (!started) {
459 : 14 : started = true;
460 : 14 : it = db.postlist_begin(string());
461 : :
462 [ + + ]: 14 : if (it == db.postlist_end(string())) return;
463 : : }
464 : :
465 [ + + ]: 39 : if (check_docid) {
466 [ - + ]: 13 : if (min_docid < check_docid)
467 : 0 : min_docid = check_docid + 1;
468 : 13 : check_docid = 0;
469 : : }
470 : :
471 [ + + ]: 39 : if (min_wt > get_maxweight()) {
472 : 13 : it = db.postlist_end(string());
473 : 13 : return;
474 : : }
475 : 40 : it.skip_to(min_docid);
476 : : }
477 : :
478 : : bool
479 : 54 : FixedWeightPostingSource::check(Xapian::docid min_docid,
480 : : Xapian::weight)
481 : : {
482 : : // We're guaranteed not to be called if the document doesn't
483 : : // exist, so just remember the docid passed, and return true.
484 : 54 : check_docid = min_docid;
485 : 54 : return true;
486 : : }
487 : :
488 : : bool
489 : 386 : FixedWeightPostingSource::at_end() const
490 : : {
491 [ + + ]: 386 : if (check_docid != 0) return false;
492 [ + + ][ + + ]: 386 : return started && it == db.postlist_end(string());
[ + + ][ # # ]
[ # # ][ + + ]
493 : : }
494 : :
495 : : Xapian::docid
496 : 340 : FixedWeightPostingSource::get_docid() const
497 : : {
498 [ + + ]: 340 : if (check_docid != 0) return check_docid;
499 : 340 : return *it;
500 : : }
501 : :
502 : : FixedWeightPostingSource *
503 : 55 : FixedWeightPostingSource::clone() const
504 : : {
505 : 55 : return new FixedWeightPostingSource(get_maxweight());
506 : : }
507 : :
508 : : string
509 : 1584 : FixedWeightPostingSource::name() const
510 : : {
511 : 1584 : return string("Xapian::FixedWeightPostingSource");
512 : : }
513 : :
514 : : string
515 : 8 : FixedWeightPostingSource::serialise() const
516 : : {
517 : 8 : return serialise_double(get_maxweight());
518 : : }
519 : :
520 : : FixedWeightPostingSource *
521 : 8 : FixedWeightPostingSource::unserialise(const string &s) const
522 : : {
523 : 8 : const char * p = s.data();
524 : 8 : const char * s_end = p + s.size();
525 : 8 : double new_wt = unserialise_double(&p, s_end);
526 [ - + ]: 8 : if (p != s_end) {
527 : 0 : throw Xapian::NetworkError("Bad serialised FixedWeightPostingSource - junk at end");
528 : : }
529 : 8 : return new FixedWeightPostingSource(new_wt);
530 : : }
531 : :
532 : : void
533 : 65 : FixedWeightPostingSource::init(const Xapian::Database & db_)
534 : : {
535 : 65 : db = db_;
536 : 65 : termfreq = db_.get_doccount();
537 : 65 : started = false;
538 : 65 : check_docid = 0;
539 : 65 : }
540 : :
541 : : string
542 : 7 : FixedWeightPostingSource::get_description() const
543 : : {
544 : 7 : string desc("Xapian::FixedWeightPostingSource(wt=");
545 : 7 : desc += str(get_maxweight());
546 : 7 : desc += ")";
547 : 0 : return desc;
548 : : }
549 : :
550 : 0 : }
|