Branch data Line data Source code
1 : : /* omdocument.cc: class for performing a match
2 : : *
3 : : * Copyright 1999,2000,2001 BrightStation PLC
4 : : * Copyright 2002 Ananova Ltd
5 : : * Copyright 2003,2004,2006,2007,2008,2009 Olly Betts
6 : : * Copyright 2009 Lemur Consulting Ltd
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
21 : : * USA
22 : : */
23 : :
24 : : #include <config.h>
25 : :
26 : : #include <xapian/document.h>
27 : :
28 : : #include "document.h"
29 : : #include "documentvaluelist.h"
30 : : #include "maptermlist.h"
31 : : #include "serialise.h"
32 : : #include "str.h"
33 : :
34 : : #include <xapian/error.h>
35 : : #include <xapian/types.h>
36 : : #include <xapian/valueiterator.h>
37 : :
38 : : #include <algorithm>
39 : : #include <string>
40 : :
41 : : using namespace std;
42 : :
43 : : namespace Xapian {
44 : :
45 : : // implementation of Document
46 : :
47 : 1180003 : Document::Document(Document::Internal *internal_) : internal(internal_)
48 : : {
49 : 1180003 : }
50 : :
51 : 237662 : Document::Document() : internal(new Xapian::Document::Internal)
52 : : {
53 : 237662 : }
54 : :
55 : : string
56 : 494627 : Document::get_value(Xapian::valueno value) const
57 : : {
58 : : LOGCALL(API, string, "Document::get_value", value);
59 : 494627 : RETURN(internal->get_value(value));
60 : : }
61 : :
62 : : string
63 : 778040 : Document::get_data() const
64 : : {
65 : : LOGCALL(API, string, "Document::get_data", NO_ARGS);
66 : 778040 : RETURN(internal->get_data());
67 : : }
68 : :
69 : : void
70 : 131867 : Document::set_data(const string &data)
71 : : {
72 : : LOGCALL_VOID(API, "Document::set_data", data);
73 : 131867 : internal->set_data(data);
74 : 131867 : }
75 : :
76 : : void
77 : 70726 : Document::operator=(const Document &other)
78 : : {
79 : : // pointers are reference counted.
80 : 70726 : internal = other.internal;
81 : 70726 : }
82 : :
83 : 121863 : Document::Document(const Document &other)
84 : 121863 : : internal(other.internal)
85 : : {
86 : 121863 : }
87 : :
88 : 1539528 : Document::~Document()
89 : : {
90 : 1539528 : }
91 : :
92 : : string
93 : 2 : Document::get_description() const
94 : : {
95 : 2 : return "Document(" + internal->get_description() + ")";
96 : : }
97 : :
98 : : void
99 : 1374947 : Document::add_value(Xapian::valueno valueno, const string &value)
100 : : {
101 : : LOGCALL_VOID(API, "Document::add_value", valueno | value);
102 : 1374947 : internal->add_value(valueno, value);
103 : 1374947 : }
104 : :
105 : : void
106 : 3 : Document::remove_value(Xapian::valueno valueno)
107 : : {
108 : : LOGCALL_VOID(API, "Document::remove_value", valueno);
109 : 3 : internal->remove_value(valueno);
110 : 3 : }
111 : :
112 : : void
113 : 0 : Document::clear_values()
114 : : {
115 : : LOGCALL_VOID(API, "Document::clear_values", NO_ARGS);
116 : 0 : internal->clear_values();
117 : 0 : }
118 : :
119 : : void
120 : 4773559 : Document::add_posting(const string & tname,
121 : : Xapian::termpos tpos,
122 : : Xapian::termcount wdfinc)
123 : : {
124 : : LOGCALL_VOID(API, "Document::add_posting", tname | tpos | wdfinc);
125 [ - + ]: 4773559 : if (tname.empty()) {
126 : 0 : throw InvalidArgumentError("Empty termnames aren't allowed.");
127 : : }
128 : 4773559 : internal->add_posting(tname, tpos, wdfinc);
129 : 4773559 : }
130 : :
131 : : void
132 : 1327967 : Document::add_term(const string & tname, Xapian::termcount wdfinc)
133 : : {
134 : : LOGCALL_VOID(API, "Document::add_term", tname | wdfinc);
135 [ - + ]: 1327967 : if (tname.empty()) {
136 : 0 : throw InvalidArgumentError("Empty termnames aren't allowed.");
137 : : }
138 : 1327967 : internal->add_term(tname, wdfinc);
139 : 1327967 : }
140 : :
141 : : void
142 : 20 : Document::remove_posting(const string & tname, Xapian::termpos tpos,
143 : : Xapian::termcount wdfdec)
144 : : {
145 : : LOGCALL_VOID(API, "Document::remove_posting", tname | tpos | wdfdec);
146 [ - + ]: 20 : if (tname.empty()) {
147 : 0 : throw InvalidArgumentError("Empty termnames aren't allowed.");
148 : : }
149 : 20 : internal->remove_posting(tname, tpos, wdfdec);
150 : 20 : }
151 : :
152 : : void
153 : 150 : Document::remove_term(const string & tname)
154 : : {
155 : : LOGCALL_VOID(API, "Document::remove_term", tname);
156 : 150 : internal->remove_term(tname);
157 : 150 : }
158 : :
159 : : void
160 : 0 : Document::clear_terms()
161 : : {
162 : : LOGCALL_VOID(API, "Document::clear_terms", NO_ARGS);
163 : 0 : internal->clear_terms();
164 : 0 : }
165 : :
166 : : Xapian::termcount
167 : 330892 : Document::termlist_count() const {
168 : : LOGCALL(API, Xapian::termcount, "Document::termlist_count", NO_ARGS);
169 : 330892 : RETURN(internal->termlist_count());
170 : : }
171 : :
172 : : TermIterator
173 : 469797 : Document::termlist_begin() const
174 : : {
175 : : LOGCALL(API, TermIterator, "Document::termlist_begin", NO_ARGS);
176 : 469797 : RETURN(TermIterator(internal->open_term_list()));
177 : : }
178 : :
179 : : Xapian::termcount
180 : 248726 : Document::values_count() const {
181 : : LOGCALL(API, Xapian::termcount, "Document::values_count", NO_ARGS);
182 : 248726 : RETURN(internal->values_count());
183 : : }
184 : :
185 : : ValueIterator
186 : 923686 : Document::values_begin() const
187 : : {
188 : : LOGCALL(API, ValueIterator, "Document::values_begin", NO_ARGS);
189 : : // Calling values_count() has the side effect of making sure that they have
190 : : // been read into the std::map "values" member of internal.
191 [ + + ]: 923686 : if (internal->values_count() == 0) RETURN(ValueIterator());
192 : 923686 : RETURN(ValueIterator(new DocumentValueList(internal)));
193 : : }
194 : :
195 : : docid
196 : 1 : Document::get_docid() const
197 : : {
198 : : LOGCALL(API, docid, "Document::get_docid", NO_ARGS);
199 : 1 : RETURN(internal->get_docid());
200 : : }
201 : :
202 : : std::string
203 : 11 : Document::serialise() const
204 : : {
205 : : LOGCALL(API, std::string, "Document::serialise", NO_ARGS);
206 : 11 : return serialise_document(*this);
207 : : }
208 : :
209 : : Document
210 : 11 : Document::unserialise(const std::string &s)
211 : : {
212 : : LOGCALL_STATIC(API, Document, "Document::unserialise", s);
213 : 11 : return unserialise_document(s);
214 : : }
215 : :
216 : : }
217 : :
218 : : /////////////////////////////////////////////////////////////////////////////
219 : :
220 : : void
221 : 4777951 : OmDocumentTerm::add_position(Xapian::termpos tpos)
222 : : {
223 : : LOGCALL_VOID(DB, "OmDocumentTerm::add_position", tpos);
224 : :
225 : : // We generally expect term positions to be added in approximately
226 : : // increasing order, so check the end first
227 [ + + ][ + + ]: 4777951 : if (positions.empty() || tpos > positions.back()) {
[ + + ]
228 : 4777851 : positions.push_back(tpos);
229 : 4777851 : return;
230 : : }
231 : :
232 : : // Search for the position the term occurs at. Use binary chop to
233 : : // search, since this is a sorted list.
234 : 100 : vector<Xapian::termpos>::iterator i;
235 : 100 : i = lower_bound(positions.begin(), positions.end(), tpos);
236 [ + - - + ]: 100 : if (i == positions.end() || *i != tpos) {
[ - + ]
237 : 4777951 : positions.insert(i, tpos);
238 : : }
239 : : }
240 : :
241 : : void
242 : 20 : OmDocumentTerm::remove_position(Xapian::termpos tpos)
243 : : {
244 : : LOGCALL_VOID(DB, "OmDocumentTerm::remove_position", tpos);
245 : :
246 : : // Search for the position the term occurs at. Use binary chop to
247 : : // search, since this is a sorted list.
248 : 20 : vector<Xapian::termpos>::iterator i;
249 : 20 : i = lower_bound(positions.begin(), positions.end(), tpos);
250 [ + - - + ]: 20 : if (i == positions.end() || *i != tpos) {
[ - + ]
251 : : throw Xapian::InvalidArgumentError("Position `" + str(tpos) +
252 : : "' not found in list of positions that `" +
253 : : tname +
254 : : "' occurs at,"
255 : 0 : " when removing position from list");
256 : : }
257 : 20 : positions.erase(i);
258 : 20 : }
259 : :
260 : : string
261 : 0 : OmDocumentTerm::get_description() const
262 : : {
263 : 0 : string description;
264 : :
265 : : description = "OmDocumentTerm(" + tname +
266 : : ", wdf = " + str(wdf) +
267 : : ", positions[" + str(positions.size()) + "]" +
268 : 0 : ")";
269 : 0 : return description;
270 : : }
271 : :
272 : : string
273 : 1024643 : Xapian::Document::Internal::get_value(Xapian::valueno valueid) const
274 : : {
275 [ + + ]: 1024643 : if (values_here) {
276 : 449289 : map<Xapian::valueno, string>::const_iterator i;
277 : 449289 : i = values.find(valueid);
278 [ + + ]: 449289 : if (i == values.end()) return string();
279 : 394225 : return i->second;
280 : : }
281 [ + + ]: 575354 : if (!database.get()) return string();
282 : 1024643 : return do_get_value(valueid);
283 : : }
284 : :
285 : : string
286 : 778040 : Xapian::Document::Internal::get_data() const
287 : : {
288 [ + + ]: 778040 : if (data_here) return data;
289 [ + + ]: 644245 : if (!database.get()) return string();
290 : 778040 : return do_get_data();
291 : : }
292 : :
293 : : void
294 : 582817 : Xapian::Document::Internal::set_data(const string &data_)
295 : : {
296 : 582817 : data = data_;
297 : 582817 : data_here = true;
298 : 582817 : }
299 : :
300 : : TermList *
301 : 469797 : Xapian::Document::Internal::open_term_list() const
302 : : {
303 : : LOGCALL(MATCH, TermList *, "Document::Internal::open_term_list", NO_ARGS);
304 [ + + ]: 469797 : if (terms_here) {
305 : 345898 : RETURN(new MapTermList(terms.begin(), terms.end()));
306 : : }
307 [ + + ]: 123899 : if (!database.get()) RETURN(NULL);
308 : 469797 : RETURN(database->open_term_list(did));
309 : : }
310 : :
311 : : void
312 : 1374947 : Xapian::Document::Internal::add_value(Xapian::valueno valueno, const string &value)
313 : : {
314 : 1374947 : need_values();
315 [ + + ]: 1374947 : if (!value.empty()) {
316 : 1368597 : values[valueno] = value;
317 : : } else {
318 : : // Empty values aren't stored, but replace any existing value by
319 : : // removing it.
320 : 6350 : values.erase(valueno);
321 : : }
322 : 1374947 : }
323 : :
324 : : void
325 : 3 : Xapian::Document::Internal::remove_value(Xapian::valueno valueno)
326 : : {
327 : 3 : need_values();
328 : 3 : map<Xapian::valueno, string>::iterator i = values.find(valueno);
329 [ - + ]: 3 : if (i == values.end()) {
330 : : throw Xapian::InvalidArgumentError("Value #" + str(valueno) +
331 : : " is not present in document, in "
332 : 0 : "Xapian::Document::Internal::remove_value()");
333 : : }
334 : 3 : values.erase(i);
335 : 3 : }
336 : :
337 : : void
338 : 0 : Xapian::Document::Internal::clear_values()
339 : : {
340 : 0 : values.clear();
341 : 0 : values_here = true;
342 : 0 : }
343 : :
344 : : void
345 : 4773559 : Xapian::Document::Internal::add_posting(const string & tname, Xapian::termpos tpos,
346 : : Xapian::termcount wdfinc)
347 : : {
348 : 4773559 : need_terms();
349 : :
350 : 4773559 : map<string, OmDocumentTerm>::iterator i;
351 : 4773559 : i = terms.find(tname);
352 [ + + ]: 4773559 : if (i == terms.end()) {
353 : 2996956 : OmDocumentTerm newterm(tname, wdfinc);
354 : 2996956 : newterm.add_position(tpos);
355 : 2996956 : terms.insert(make_pair(tname, newterm));
356 : : } else {
357 : 1776603 : i->second.add_position(tpos);
358 [ + + ]: 1776603 : if (wdfinc) i->second.inc_wdf(wdfinc);
359 : : }
360 : 4773559 : }
361 : :
362 : : void
363 : 1327967 : Xapian::Document::Internal::add_term(const string & tname, Xapian::termcount wdfinc)
364 : : {
365 : 1327967 : need_terms();
366 : :
367 : 1327967 : map<string, OmDocumentTerm>::iterator i;
368 : 1327967 : i = terms.find(tname);
369 [ + + ]: 1327967 : if (i == terms.end()) {
370 : 1321937 : OmDocumentTerm newterm(tname, wdfinc);
371 : 1321937 : terms.insert(make_pair(tname, newterm));
372 : : } else {
373 [ + - ]: 6030 : if (wdfinc) i->second.inc_wdf(wdfinc);
374 : : }
375 : 1327967 : }
376 : :
377 : : void
378 : 20 : Xapian::Document::Internal::remove_posting(const string & tname,
379 : : Xapian::termpos tpos,
380 : : Xapian::termcount wdfdec)
381 : : {
382 : 20 : need_terms();
383 : :
384 : 20 : map<string, OmDocumentTerm>::iterator i;
385 : 20 : i = terms.find(tname);
386 [ - + ]: 20 : if (i == terms.end()) {
387 : : throw Xapian::InvalidArgumentError("Term `" + tname +
388 : : "' is not present in document, in "
389 : 0 : "Xapian::Document::Internal::remove_posting()");
390 : : }
391 : 20 : i->second.remove_position(tpos);
392 [ + - ]: 20 : if (wdfdec) i->second.dec_wdf(wdfdec);
393 : 20 : }
394 : :
395 : : void
396 : 150 : Xapian::Document::Internal::remove_term(const string & tname)
397 : : {
398 : 150 : need_terms();
399 : 150 : map<string, OmDocumentTerm>::iterator i;
400 : 150 : i = terms.find(tname);
401 [ - + ]: 150 : if (i == terms.end()) {
402 : : throw Xapian::InvalidArgumentError("Term `" + tname +
403 : : "' is not present in document, in "
404 : 0 : "Xapian::Document::Internal::remove_term()");
405 : : }
406 : 150 : terms.erase(i);
407 : 150 : }
408 : :
409 : : void
410 : 0 : Xapian::Document::Internal::clear_terms()
411 : : {
412 : 0 : terms.clear();
413 : 0 : terms_here = true;
414 : 0 : }
415 : :
416 : : Xapian::termcount
417 : 330892 : Xapian::Document::Internal::termlist_count() const
418 : : {
419 [ + + ]: 330892 : if (!terms_here) {
420 : : // How equivalent is this line to the rest?
421 : : // return database.get() ? database->open_term_list(did)->get_approx_size() : 0;
422 : 131527 : need_terms();
423 : : }
424 : : Assert(terms_here);
425 : 330892 : return terms.size();
426 : : }
427 : :
428 : : void
429 : 6233223 : Xapian::Document::Internal::need_terms() const
430 : : {
431 [ + + ]: 6233223 : if (terms_here) return;
432 [ + + ]: 222909 : if (database.get()) {
433 : 30760 : Xapian::TermIterator t(database->open_term_list(did));
434 : 30760 : Xapian::TermIterator tend(NULL);
435 [ + + ]: 65201 : for ( ; t != tend; ++t) {
436 : 34441 : Xapian::PositionIterator p = t.positionlist_begin();
437 : 34441 : Xapian::PositionIterator pend = t.positionlist_end();
438 : 34441 : OmDocumentTerm term(*t, t.get_wdf());
439 [ + + ]: 38833 : for ( ; p != pend; ++p) {
440 : 4392 : term.add_position(*p);
441 : : }
442 : 34441 : terms.insert(make_pair(*t, term));
443 : 30760 : }
444 : : }
445 : 6233223 : terms_here = true;
446 : : }
447 : :
448 : : Xapian::valueno
449 : 1172412 : Xapian::Document::Internal::values_count() const
450 : : {
451 : : LOGLINE(DB, "Xapian::Document::Internal::values_count() called");
452 : 1172412 : need_values();
453 : : Assert(values_here);
454 : 1172412 : return values.size();
455 : : }
456 : :
457 : : string
458 : 2 : Xapian::Document::Internal::get_description() const
459 : : {
460 : 2 : string description = "Xapian::Document::Internal(";
461 : :
462 [ - + ]: 2 : if (data_here) description += "data=`" + data + "'";
463 : :
464 [ - + ]: 2 : if (values_here) {
465 [ # # ]: 0 : if (data_here) description += ", ";
466 : 0 : description += "values[" + str(values.size()) + "]";
467 : : }
468 : :
469 [ - + ]: 2 : if (terms_here) {
470 [ # # ][ # # ]: 0 : if (data_here || values_here) description += ", ";
471 : 0 : description += "terms[" + str(terms.size()) + "]";
472 : : }
473 : :
474 [ - + ]: 2 : if (database.get()) {
475 [ # # ][ # # ]: 0 : if (data_here || values_here || terms_here) description += ", ";
[ # # ]
476 : 0 : description += "doc=";
477 : 0 : description += "?"; // do_get_description(); ?
478 : : }
479 : :
480 : 2 : description += ')';
481 : :
482 : 0 : return description;
483 : : }
484 : :
485 : : void
486 : 2565740 : Xapian::Document::Internal::need_values() const
487 : : {
488 [ + + ]: 2565740 : if (!values_here) {
489 [ + + ]: 726596 : if (database.get()) {
490 : : Assert(values.empty());
491 : 529458 : do_get_all_values(values);
492 : : }
493 : 726596 : values_here = true;
494 : : }
495 : 2565740 : }
496 : :
497 : 1949663 : Xapian::Document::Internal::~Internal()
498 : : {
499 [ - + ][ # # ]: 1949663 : if (database.get())
[ + - ]
500 : 1712001 : database->invalidate_doc_object(this);
501 [ + - ][ # # ]: 1949663 : }
[ - + ]
|