xapian-core  2.0.0
api_posdb.cc
Go to the documentation of this file.
1 
4 /* Copyright 1999,2000,2001 BrightStation PLC
5  * Copyright 2002 Ananova Ltd
6  * Copyright 2002,2003,2004,2005,2006,2007,2009,2016,2019 Olly Betts
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, see
20  * <https://www.gnu.org/licenses/>.
21  */
22 
23 #include <config.h>
24 
25 #include "api_posdb.h"
26 
27 #include <string>
28 #include <vector>
29 
30 using namespace std;
31 
32 #include <xapian.h>
33 #include "testsuite.h"
34 #include "testutils.h"
35 
36 #include "apitest.h"
37 
39 DEFINE_TESTCASE(near1, positional) {
40  Xapian::Database mydb(get_database("apitest_phrase"));
41  Xapian::Enquire enquire(mydb);
42  Xapian::Stem stemmer("english");
44 
45  // make a query
46  vector<Xapian::Query> subqs;
47  Xapian::Query q;
48  subqs.push_back(Xapian::Query(stemmer("phrase")));
49  subqs.push_back(Xapian::Query(stemmer("fridge")));
50  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 2);
51  enquire.set_query(q);
52 
53  // retrieve the top ten results
54  Xapian::MSet mymset = enquire.get_mset(0, 10);
55  mset_expect_order(mymset);
56 
57  subqs.clear();
58  subqs.push_back(Xapian::Query(stemmer("phrase")));
59  subqs.push_back(Xapian::Query(stemmer("near")));
60  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 2);
61  enquire.set_query(q);
62 
63  // retrieve the top ten results
64  mymset = enquire.get_mset(0, 10);
65  mset_expect_order(mymset, 3);
66 
67  subqs.clear();
68  subqs.push_back(Xapian::Query(stemmer("phrase")));
69  subqs.push_back(Xapian::Query(stemmer("near")));
70  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 3);
71  enquire.set_query(q);
72 
73  // retrieve the top ten results
74  mymset = enquire.get_mset(0, 10);
75  mset_expect_order(mymset, 1, 3);
76 
77  subqs.clear();
78  subqs.push_back(Xapian::Query(stemmer("phrase")));
79  subqs.push_back(Xapian::Query(stemmer("near")));
80  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 5);
81  enquire.set_query(q);
82 
83  // retrieve the top ten results
84  mymset = enquire.get_mset(0, 10);
85  mset_expect_order(mymset, 1, 3);
86 
87  subqs.clear();
88  subqs.push_back(Xapian::Query(stemmer("phrase")));
89  subqs.push_back(Xapian::Query(stemmer("near")));
90  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 6);
91  enquire.set_query(q);
92 
93  // retrieve the top ten results
94  mymset = enquire.get_mset(0, 10);
95  mset_expect_order(mymset, 1, 2, 3);
96 
97  subqs.clear();
98  subqs.push_back(Xapian::Query(stemmer("leave")));
99  subqs.push_back(Xapian::Query(stemmer("fridge")));
100  subqs.push_back(Xapian::Query(stemmer("on")));
101  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 3);
102  enquire.set_query(q);
103 
104  // retrieve the top ten results
105  mymset = enquire.get_mset(0, 10);
106  mset_expect_order(mymset, 4, 5, 6, 7, 8, 9);
107 
108  subqs.clear();
109  subqs.push_back(Xapian::Query(stemmer("leave")));
110  subqs.push_back(Xapian::Query(stemmer("fridge")));
111  subqs.push_back(Xapian::Query(stemmer("on")));
112  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 4);
113  enquire.set_query(q);
114 
115  // retrieve the top ten results
116  mymset = enquire.get_mset(0, 10);
117  mset_expect_order(mymset, 4, 5, 6, 7, 8, 9, 10);
118 
119  subqs.clear();
120  subqs.push_back(Xapian::Query(stemmer("leave")));
121  subqs.push_back(Xapian::Query(stemmer("fridge")));
122  subqs.push_back(Xapian::Query(stemmer("on")));
123  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 5);
124  enquire.set_query(q);
125 
126  // retrieve the top ten results
127  mymset = enquire.get_mset(0, 10);
128  mset_expect_order(mymset, 4, 5, 6, 7, 8, 9, 10, 11);
129 
130  subqs.clear();
131  subqs.push_back(Xapian::Query(stemmer("leave")));
132  subqs.push_back(Xapian::Query(stemmer("fridge")));
133  subqs.push_back(Xapian::Query(stemmer("on")));
134  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 6);
135  enquire.set_query(q);
136 
137  // retrieve the top ten results
138  mymset = enquire.get_mset(0, 10);
139  mset_expect_order(mymset, 4, 5, 6, 7, 8, 9, 10, 11, 12);
140 
141  subqs.clear();
142  subqs.push_back(Xapian::Query(stemmer("leave")));
143  subqs.push_back(Xapian::Query(stemmer("fridge")));
144  subqs.push_back(Xapian::Query(stemmer("on")));
145  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 7);
146  enquire.set_query(q);
147 
148  // retrieve the top twenty results
149  mymset = enquire.get_mset(0, 20);
150  mset_expect_order(mymset, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
151 
152  subqs.clear();
153  subqs.push_back(Xapian::Query(stemmer("leave")));
154  subqs.push_back(Xapian::Query(stemmer("fridge")));
155  subqs.push_back(Xapian::Query(stemmer("on")));
156  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 8);
157  enquire.set_query(q);
158 
159  // retrieve the top twenty results
160  mymset = enquire.get_mset(0, 20);
161  mset_expect_order(mymset, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
162 
163  subqs.clear();
164  subqs.push_back(Xapian::Query(stemmer("leave")));
165  subqs.push_back(Xapian::Query(stemmer("fridge")));
166  subqs.push_back(Xapian::Query(stemmer("on")));
167  // test really large window size
168  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 999999999);
169  enquire.set_query(q);
170 
171  // retrieve the top twenty results
172  mymset = enquire.get_mset(0, 20);
173  mset_expect_order(mymset, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
174 }
175 
177 DEFINE_TESTCASE(near2, positional) {
178  Xapian::Database mydb(get_database("apitest_phrase"));
179  Xapian::Enquire enquire(mydb);
180  Xapian::Stem stemmer("english");
182  Xapian::MSet mymset;
183 
184  // make a query
185  vector<Xapian::Query> subqs;
186  Xapian::Query q;
187  subqs.push_back(Xapian::Query(Xapian::Query::OP_AND,
188  Xapian::Query(stemmer("phrase")),
189  Xapian::Query(stemmer("near"))));
190  subqs.push_back(Xapian::Query(stemmer("and")));
192  q = Xapian::Query(q.OP_NEAR, subqs.begin(), subqs.end(), 2);
193  enquire.set_query(q);
194 
195  // retrieve the top ten results
196  mymset = enquire.get_mset(0, 10)
197  );
198 #if 0 // Disable until we reimplement this.
199  mset_expect_order(mymset, 1);
200 
201  subqs.clear();
202  subqs.push_back(Xapian::Query(Xapian::Query::OP_AND,
203  Xapian::Query(stemmer("phrase")),
204  Xapian::Query(stemmer("near"))));
205  subqs.push_back(Xapian::Query(stemmer("operator")));
206  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 2);
207  enquire.set_query(q);
208 
209  // retrieve the top ten results
210  mymset = enquire.get_mset(0, 10);
211  mset_expect_order(mymset, 2);
212 
213  subqs.clear();
214  subqs.push_back(Xapian::Query(stemmer("operator")));
215  subqs.push_back(Xapian::Query(Xapian::Query::OP_AND,
216  Xapian::Query(stemmer("phrase")),
217  Xapian::Query(stemmer("near"))));
218  q = Xapian::Query(Xapian::Query::OP_NEAR, subqs.begin(), subqs.end(), 2);
219  enquire.set_query(q);
220 
221  // retrieve the top ten results
222  mymset = enquire.get_mset(0, 10);
223  mset_expect_order(mymset, 2);
224 #endif
225 }
226 
228 DEFINE_TESTCASE(phrase1, positional) {
229  Xapian::Database mydb(get_database("apitest_phrase"));
230  Xapian::Enquire enquire(mydb);
231  Xapian::Stem stemmer("english");
233 
234  // make a query
235  vector<Xapian::Query> subqs;
236  Xapian::Query q;
237  subqs.push_back(Xapian::Query(stemmer("phrase")));
238  subqs.push_back(Xapian::Query(stemmer("fridge")));
239  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 2);
240  enquire.set_query(q);
241 
242  // retrieve the top ten results
243  Xapian::MSet mymset = enquire.get_mset(0, 10);
244  mset_expect_order(mymset);
245 
246  subqs.clear();
247  subqs.push_back(Xapian::Query(stemmer("phrase")));
248  subqs.push_back(Xapian::Query(stemmer("near")));
249  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 2);
250  enquire.set_query(q);
251 
252  // retrieve the top ten results
253  mymset = enquire.get_mset(0, 10);
254  mset_expect_order(mymset);
255 
256  subqs.clear();
257  subqs.push_back(Xapian::Query(stemmer("phrase")));
258  subqs.push_back(Xapian::Query(stemmer("near")));
259  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 3);
260  enquire.set_query(q);
261 
262  // retrieve the top ten results
263  mymset = enquire.get_mset(0, 10);
264  mset_expect_order(mymset, 1);
265 
266  subqs.clear();
267  subqs.push_back(Xapian::Query(stemmer("phrase")));
268  subqs.push_back(Xapian::Query(stemmer("near")));
269  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 5);
270  enquire.set_query(q);
271 
272  // retrieve the top ten results
273  mymset = enquire.get_mset(0, 10);
274  mset_expect_order(mymset, 1);
275 
276  subqs.clear();
277  subqs.push_back(Xapian::Query(stemmer("phrase")));
278  subqs.push_back(Xapian::Query(stemmer("near")));
279  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 6);
280  enquire.set_query(q);
281 
282  // retrieve the top ten results
283  mymset = enquire.get_mset(0, 10);
284  mset_expect_order(mymset, 1, 2);
285 
286  subqs.clear();
287  subqs.push_back(Xapian::Query(stemmer("leave")));
288  subqs.push_back(Xapian::Query(stemmer("fridge")));
289  subqs.push_back(Xapian::Query(stemmer("on")));
290  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 3);
291  enquire.set_query(q);
292 
293  // retrieve the top ten results
294  mymset = enquire.get_mset(0, 10);
295  mset_expect_order(mymset, 4);
296 
297  subqs.clear();
298  subqs.push_back(Xapian::Query(stemmer("leave")));
299  subqs.push_back(Xapian::Query(stemmer("fridge")));
300  subqs.push_back(Xapian::Query(stemmer("on")));
301  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 4);
302  enquire.set_query(q);
303 
304  // retrieve the top ten results
305  mymset = enquire.get_mset(0, 10);
306  mset_expect_order(mymset, 4);
307 
308  subqs.clear();
309  subqs.push_back(Xapian::Query(stemmer("leave")));
310  subqs.push_back(Xapian::Query(stemmer("fridge")));
311  subqs.push_back(Xapian::Query(stemmer("on")));
312  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 5);
313  enquire.set_query(q);
314 
315  // retrieve the top ten results
316  mymset = enquire.get_mset(0, 10);
317  mset_expect_order(mymset, 4);
318 
319  subqs.clear();
320  subqs.push_back(Xapian::Query(stemmer("leave")));
321  subqs.push_back(Xapian::Query(stemmer("fridge")));
322  subqs.push_back(Xapian::Query(stemmer("on")));
323  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 6);
324  enquire.set_query(q);
325 
326  // retrieve the top ten results
327  mymset = enquire.get_mset(0, 10);
328  mset_expect_order(mymset, 4);
329 
330  subqs.clear();
331  subqs.push_back(Xapian::Query(stemmer("leave")));
332  subqs.push_back(Xapian::Query(stemmer("fridge")));
333  subqs.push_back(Xapian::Query(stemmer("on")));
334  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 7);
335  enquire.set_query(q);
336 
337  // retrieve the top twenty results
338  mymset = enquire.get_mset(0, 20);
339  mset_expect_order(mymset, 4);
340 
341  subqs.clear();
342  subqs.push_back(Xapian::Query(stemmer("leave")));
343  subqs.push_back(Xapian::Query(stemmer("fridge")));
344  subqs.push_back(Xapian::Query(stemmer("on")));
345  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 8);
346  enquire.set_query(q);
347 
348  // retrieve the top 20 results
349  mymset = enquire.get_mset(0, 20);
350  mset_expect_order(mymset, 4);
351 
352  // test really large window size
353  subqs.clear();
354  subqs.push_back(Xapian::Query(stemmer("leave")));
355  subqs.push_back(Xapian::Query(stemmer("fridge")));
356  subqs.push_back(Xapian::Query(stemmer("on")));
357  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 999999999);
358  enquire.set_query(q);
359 
360  // retrieve the top 20 results
361  mymset = enquire.get_mset(0, 20);
362  mset_expect_order(mymset, 4);
363 
364  // regression test (was matching doc 15, should fail)
365  subqs.clear();
366  subqs.push_back(Xapian::Query(stemmer("first")));
367  subqs.push_back(Xapian::Query(stemmer("second")));
368  subqs.push_back(Xapian::Query(stemmer("third")));
369  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 9);
370  enquire.set_query(q);
371 
372  // retrieve the top ten results
373  mymset = enquire.get_mset(0, 10);
374  mset_expect_order(mymset);
375 
376  // regression test (should match doc 15, make sure still does with fix)
377  subqs.clear();
378  subqs.push_back(Xapian::Query(stemmer("first")));
379  subqs.push_back(Xapian::Query(stemmer("second")));
380  subqs.push_back(Xapian::Query(stemmer("third")));
381  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 10);
382  enquire.set_query(q);
383 
384  // retrieve the top ten results
385  mymset = enquire.get_mset(0, 10);
386  mset_expect_order(mymset, 15);
387 
388  // regression test (phrase matching was getting order wrong when
389  // build_and_tree reordered vector of PostLists)
390  subqs.clear();
391  subqs.push_back(Xapian::Query(stemmer("milk")));
392  subqs.push_back(Xapian::Query(stemmer("rare")));
393  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 2);
394  enquire.set_query(q);
395 
396  // retrieve the top ten results
397  mymset = enquire.get_mset(0, 10);
398  mset_expect_order(mymset, 16);
399 
400  // regression test (phrase matching was getting order wrong when
401  // build_and_tree reordered vector of PostLists)
402  subqs.clear();
403  subqs.push_back(Xapian::Query(stemmer("rare")));
404  subqs.push_back(Xapian::Query(stemmer("milk")));
405  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 2);
406  enquire.set_query(q);
407 
408  // retrieve the top ten results
409  mymset = enquire.get_mset(0, 10);
410  mset_expect_order(mymset, 17);
411 }
412 
414 DEFINE_TESTCASE(phrase2, positional) {
415  Xapian::Database mydb(get_database("apitest_phrase"));
416  Xapian::Enquire enquire(mydb);
417  Xapian::Stem stemmer("english");
419  Xapian::MSet mymset;
420 
421  // make a query
422  vector<Xapian::Query> subqs;
423  Xapian::Query q;
424  subqs.push_back(Xapian::Query(Xapian::Query::OP_AND,
425  Xapian::Query(stemmer("phrase")),
426  Xapian::Query(stemmer("near"))));
427  subqs.push_back(Xapian::Query(stemmer("and")));
429  q = Xapian::Query(q.OP_PHRASE, subqs.begin(), subqs.end(), 2);
430  enquire.set_query(q);
431 
432  // retrieve the top ten results
433  mymset = enquire.get_mset(0, 10)
434  );
435 #if 0 // Disable until we reimplement this.
436  mset_expect_order(mymset);
437 
438  subqs.clear();
439  subqs.push_back(Xapian::Query(Xapian::Query::OP_AND,
440  Xapian::Query(stemmer("phrase")),
441  Xapian::Query(stemmer("near"))));
442  subqs.push_back(Xapian::Query(stemmer("operator")));
443  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 2);
444  enquire.set_query(q);
445 
446  // retrieve the top ten results
447  mymset = enquire.get_mset(0, 10);
448  mset_expect_order(mymset, 2);
449 
450  subqs.clear();
451  subqs.push_back(Xapian::Query(stemmer("operator")));
452  subqs.push_back(Xapian::Query(Xapian::Query::OP_AND,
453  Xapian::Query(stemmer("phrase")),
454  Xapian::Query(stemmer("near"))));
455  q = Xapian::Query(Xapian::Query::OP_PHRASE, subqs.begin(), subqs.end(), 2);
456  enquire.set_query(q);
457 
458  // retrieve the top ten results
459  mymset = enquire.get_mset(0, 10);
460  mset_expect_order(mymset);
461 #endif
462 }
463 
465 DEFINE_TESTCASE(poslist1, positional) {
466  Xapian::Database mydb(get_database("apitest_poslist"));
467 
468  Xapian::Stem stemmer("english");
469  string term = stemmer("sponge");
470 
472 
473  TEST(pli != mydb.positionlist_end(2, term));
474  TEST_EQUAL(*pli, 1);
475  pli++;
476  TEST(pli != mydb.positionlist_end(2, term));
477  TEST_EQUAL(*pli, 2);
478  pli++;
479  TEST(pli != mydb.positionlist_end(2, term));
480  TEST_EQUAL(*pli, 3);
481  pli++;
482  TEST(pli != mydb.positionlist_end(2, term));
483  TEST_EQUAL(*pli, 5);
484  pli++;
485  TEST(pli != mydb.positionlist_end(2, term));
486  TEST_EQUAL(*pli, 8);
487  pli++;
488  TEST(pli != mydb.positionlist_end(2, term));
489  TEST_EQUAL(*pli, 13);
490  pli++;
491  TEST(pli != mydb.positionlist_end(2, term));
492  TEST_EQUAL(*pli, 21);
493  pli++;
494  TEST(pli != mydb.positionlist_end(2, term));
495  TEST_EQUAL(*pli, 34);
496  pli++;
497  TEST(pli == mydb.positionlist_end(2, term));
498 }
499 
500 DEFINE_TESTCASE(poslist2, positional && writable) {
502 
503  Xapian::Document doc;
504  doc.add_term("nopos");
505  Xapian::docid did = db.add_document(doc);
506 
507  // Check what happens when term doesn't exist - should give an empty list.
508  // Threw RangeError in Xapian < 1.1.0.
509  TEST_EQUAL(db.positionlist_begin(did, "nosuchterm"),
510  db.positionlist_end(did, "nosuchterm"));
511 
512  // Check what happens when the document doesn't even exist - should give
513  // an empty list. Threw DocNotFoundError in Xapian < 1.1.0.
514  TEST_EQUAL(db.positionlist_begin(123, "nosuchterm"),
515  db.positionlist_end(123, "nosuchterm"));
516 
517  TEST_EQUAL(db.positionlist_begin(did, "nopos"),
518  db.positionlist_end(did, "nopos"));
519 
520  Xapian::Document doc2 = db.get_document(did);
521 
523 
524  {
525  Xapian::PositionIterator i = term.positionlist_begin();
526  TEST_EQUAL(i, term.positionlist_end());
527  }
528 
529  Xapian::Document doc3;
530  doc3.add_posting("hadpos", 1);
531  Xapian::docid did2 = db.add_document(doc3);
532 
533  Xapian::Document doc4 = db.get_document(did2);
534  doc4.remove_posting("hadpos", 1);
535  db.replace_document(did2, doc4);
536  // Removing the last position should remove the term if the wdf is 0
537  // (since 2.0.0).
538  TEST(!db.term_exists("hadpos"));
539  {
540  Xapian::PositionIterator i = db.positionlist_begin(did2, "hadpos");
541  TEST_EQUAL(i, db.positionlist_end(did2, "hadpos"));
542  }
543 
544  doc4.add_posting("extrawdf", 12, 2);
545  doc4.remove_posting("extrawdf", 12);
546  db.replace_document(did2, doc4);
547  // Removing the last position should leave the term if the wdf is non-zero.
548  TEST(db.term_exists("extrawdf"));
549  {
550  Xapian::PositionIterator i = db.positionlist_begin(did2, "extrawdf");
551  TEST_EQUAL(i, db.positionlist_end(did2, "extrawdf"));
552  }
553 
554  db.delete_document(did);
555  // Check what happens when the document doesn't exist (but once did).
556  TEST_EQUAL(db.positionlist_begin(did, "nosuchterm"),
557  db.positionlist_end(did, "nosuchterm"));
558 }
559 
562 DEFINE_TESTCASE(poslist3, positional && writable) {
564 
565  Xapian::Document document;
566  document.add_posting("foo", 5);
567  document.add_posting("foo", 8);
568  document.add_posting("foo", 10);
569  document.add_posting("foo", 12);
570  db.add_document(document);
571 
573  Xapian::PositionIterator pl_end = db.positionlist_end(1, "foo");
574 
575  TEST(pl != pl_end);
576  TEST_EQUAL(*pl, 5);
577  ++pl;
578  TEST(pl != pl_end);
579  TEST_EQUAL(*pl, 8);
580  ++pl;
581  TEST(pl != pl_end);
582  TEST_EQUAL(*pl, 10);
583  ++pl;
584  TEST(pl != pl_end);
585  TEST_EQUAL(*pl, 12);
586  ++pl;
587  TEST(pl == pl_end);
588 
589  pl = db.positionlist_begin(1, "foo");
590  pl.skip_to(5);
591  TEST(pl != pl_end);
592  TEST_EQUAL(*pl, 5);
593 
594  pl.skip_to(9);
595  TEST(pl != pl_end);
596  TEST_EQUAL(*pl, 10);
597 
598  ++pl;
599  TEST(pl != pl_end);
600  TEST_EQUAL(*pl, 12);
601 
602  pl.skip_to(12);
603  TEST(pl != pl_end);
604  TEST_EQUAL(*pl, 12);
605 
606  pl.skip_to(13);
607  TEST(pl == pl_end);
608 }
609 
610 // Regression test - in 0.9.4 (and many previous versions) you couldn't get a
611 // PositionIterator from a TermIterator from Database::termlist_begin().
612 //
613 // Also test that positionlist_count() is implemented for this case, which it
614 // wasn't in 1.0.2 and earlier.
615 DEFINE_TESTCASE(positfromtermit1, positional) {
616  Xapian::Database db(get_database("apitest_phrase"));
618  TEST_NOT_EQUAL(t, db.termlist_end(7));
621 
623  t.skip_to("on");
624  TEST_NOT_EQUAL(t, db.termlist_end(7));
626 }
DEFINE_TESTCASE(near1, positional)
Simple test of NEAR.
Definition: api_posdb.cc:39
Xapian::WritableDatabase get_writable_database(const string &dbname)
Definition: apitest.cc:86
Xapian::Database get_database(const string &dbname)
Definition: apitest.cc:47
test functionality of the Xapian API
Class implementing a "boolean" weighting scheme.
Definition: weight.h:678
An indexed database of documents.
Definition: database.h:75
PositionIterator positionlist_end(Xapian::docid, std::string_view) const noexcept
End iterator corresponding to positionlist_begin().
Definition: database.h:292
TermIterator termlist_begin(Xapian::docid did) const
Start iterating the terms in a document.
Definition: database.cc:200
PositionIterator positionlist_begin(Xapian::docid did, std::string_view term) const
Start iterating positions for a term in a document.
Definition: database.cc:221
bool term_exists(std::string_view term) const
Test is a particular term is present in any document.
Definition: database.cc:378
TermIterator termlist_end(Xapian::docid) const noexcept
End iterator corresponding to termlist_begin().
Definition: database.h:271
Xapian::Document get_document(Xapian::docid did, unsigned flags=0) const
Get a document from the database.
Definition: database.cc:368
Class representing a document.
Definition: document.h:64
void add_term(std::string_view term, Xapian::termcount wdf_inc=1)
Add a term to this document.
Definition: document.cc:87
void remove_posting(std::string_view term, Xapian::termpos term_pos, Xapian::termcount wdf_dec=1)
Remove posting for a term.
Definition: document.cc:122
TermIterator termlist_begin() const
Start iterating the terms in this document.
Definition: document.cc:179
void add_posting(std::string_view term, Xapian::termpos term_pos, Xapian::termcount wdf_inc=1)
Add a posting for a term.
Definition: document.cc:111
Querying session.
Definition: enquire.h:57
void set_weighting_scheme(const Weight &weight)
Set the weighting scheme to use.
Definition: enquire.cc:85
MSet get_mset(doccount first, doccount maxitems, doccount checkatleast=0, const RSet *rset=NULL, const MatchDecider *mdecider=NULL) const
Run the query.
Definition: enquire.cc:200
void set_query(const Query &query, termcount query_length=0)
Set the query.
Definition: enquire.cc:72
Class representing a list of search results.
Definition: mset.h:46
Class for iterating over term positions.
void skip_to(Xapian::termpos termpos)
Advance the iterator to term position termpos.
Class representing a query.
Definition: query.h:45
@ OP_NEAR
Match only documents where all subqueries match near each other.
Definition: query.h:140
@ OP_AND
Match only documents which all subqueries match.
Definition: query.h:84
@ OP_PHRASE
Match only documents where all subqueries match near and in order.
Definition: query.h:152
Class representing a stemming algorithm.
Definition: stem.h:74
Class for iterating over a list of terms.
Definition: termiterator.h:41
void skip_to(std::string_view term)
Advance the iterator to term term.
PositionIterator positionlist_end() const noexcept
Return an end PositionIterator for the current term.
Definition: termiterator.h:109
Xapian::termcount positionlist_count() const
Return the length of the position list for the current position.
PositionIterator positionlist_begin() const
Return a PositionIterator for the current term.
UnimplementedError indicates an attempt to use an unimplemented feature.
Definition: error.h:313
This class provides read/write access to a database.
Definition: database.h:964
void delete_document(Xapian::docid did)
Delete a document from the database.
Definition: database.cc:567
void replace_document(Xapian::docid did, const Xapian::Document &document)
Replace a document in the database.
Definition: database.cc:582
Xapian::docid add_document(const Xapian::Document &doc)
Add a document to the database.
Definition: database.cc:561
string term
PositionList * p
unsigned XAPIAN_DOCID_BASE_TYPE docid
A unique identifier for a document.
Definition: types.h:51
static Xapian::Stem stemmer
Definition: stemtest.cc:42
a generic test suite engine
#define TEST_EQUAL(a, b)
Test for equality of two things.
Definition: testsuite.h:276
#define TEST(a)
Test a condition, without an additional explanation for failure.
Definition: testsuite.h:273
#define TEST_NOT_EQUAL(a, b)
Test for non-equality of two things.
Definition: testsuite.h:303
void mset_expect_order(const Xapian::MSet &A, Xapian::docid d1, Xapian::docid d2, Xapian::docid d3, Xapian::docid d4, Xapian::docid d5, Xapian::docid d6, Xapian::docid d7, Xapian::docid d8, Xapian::docid d9, Xapian::docid d10, Xapian::docid d11, Xapian::docid d12)
Definition: testutils.cc:224
Xapian-specific test helper functions and macros.
#define TEST_EXCEPTION(TYPE, CODE)
Check that CODE throws exactly Xapian exception TYPE.
Definition: testutils.h:112
Public interfaces for the Xapian library.