xapian-core  2.0.0
soaktest_queries.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2010 Richard Boulton
5  * Copyright (C) 2015 Olly Betts
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 
24 #include "soaktest/soaktest.h"
26 
27 #include <xapian.h>
28 
29 #include "backendmanager.h"
30 #include "str.h"
31 #include "testrunner.h"
32 #include "testsuite.h"
33 #include "testutils.h"
34 
35 #include <list>
36 
37 using namespace std;
38 
44 static void
46 {
47  unsigned int doccount = 1000;
48  unsigned int maxtermsperfield = atoi(arg.c_str());
49  for (unsigned int i = 0; i < doccount; ++i) {
50  Xapian::Document doc;
51  for (unsigned int j = randint(maxtermsperfield) + 1; j != 0; --j) {
52  doc.add_term("N" + str(j));
53  }
54  db.add_document(doc);
55  }
56  db.commit();
57 }
58 
62  list<Xapian::Query> pieces;
63 
64  unsigned int maxtermsperfield;
65  unsigned int maxchildren;
66 
67  QueryBuilderEnv(unsigned int maxtermsperfield_,
68  unsigned int maxchildren_)
69  : maxtermsperfield(maxtermsperfield_),
70  maxchildren(maxchildren_)
71  {}
72 
75  if (pieces.empty()) return Xapian::Query();
76  Xapian::Query result = pieces.front();
77  pieces.pop_front();
78  return result;
79  }
80 
82  list<Xapian::Query>::iterator pick(unsigned int num) {
83  list<Xapian::Query>::iterator i = pieces.begin();
84  for (unsigned int c = 0; c != num && i != pieces.end(); ++c, ++i) {}
85  return i;
86  }
87 };
88 
89 typedef void (*QueryStep)(QueryBuilderEnv &);
90 
92 static void push_leaf_N(QueryBuilderEnv & env)
93 {
94  env.pieces.push_back(Xapian::Query(
95  "N" + str(randint(env.maxtermsperfield) + 1)));
96 }
97 
103 static void combine_OR(QueryBuilderEnv & env)
104 {
105  list<Xapian::Query>::iterator i = env.pick(randint(env.maxchildren));
106  Xapian::Query combined(Xapian::Query::OP_OR, env.pieces.begin(), i);
107  env.pieces.erase(env.pieces.begin(), i);
108  env.pieces.push_back(combined);
109 }
110 
116 static void combine_AND(QueryBuilderEnv & env)
117 {
118  list<Xapian::Query>::iterator i = env.pick(randint(env.maxchildren));
119  Xapian::Query combined(Xapian::Query::OP_AND, env.pieces.begin(), i);
120  env.pieces.erase(env.pieces.begin(), i);
121  env.pieces.push_back(combined);
122 }
123 
129 static void combine_XOR(QueryBuilderEnv & env)
130 {
131  list<Xapian::Query>::iterator i = env.pick(randint(env.maxchildren));
132  Xapian::Query combined(Xapian::Query::OP_XOR, env.pieces.begin(), i);
133  env.pieces.erase(env.pieces.begin(), i);
134  env.pieces.push_back(combined);
135 }
136 
142 static void combine_NOT(QueryBuilderEnv & env)
143 {
144  if (env.pieces.size() < 2) return;
145  list<Xapian::Query>::iterator i = env.pick(2);
146  Xapian::Query combined(Xapian::Query::OP_AND_NOT, env.pieces.begin(), i);
147  env.pieces.erase(env.pieces.begin(), i);
148  env.pieces.push_back(combined);
149 }
150 
154  vector<QueryStep> options;
155 
158 
160  unsigned int maxsteps;
161 
162  public:
163  QueryBuilder(unsigned int maxtermsperfield_,
164  unsigned int maxchildren_,
165  unsigned int maxsteps_)
166  : env(maxtermsperfield_, maxchildren_),
167  maxsteps(maxsteps_)
168  {
169  // Build up the set of options.
170  // Some options are added multiple times to make them more likely.
171  options.push_back(push_leaf_N);
172  options.push_back(push_leaf_N);
173  options.push_back(push_leaf_N);
174  options.push_back(push_leaf_N);
175  options.push_back(combine_OR);
176  options.push_back(combine_AND);
177  options.push_back(combine_XOR);
178  options.push_back(combine_NOT);
179  }
180 
190  unsigned int steps = randint(maxsteps) + 1;
191  while (steps-- != 0) {
192  QueryStep & step = options[randint(options.size())];
193  step(env);
194  }
195  return env.pop();
196  }
197 };
198 
199 // Generate a load of random queries, and run them checking that the first
200 // returned result is the same when asking for 1 result as it is when asking
201 // for all results. This is a basic test that early-termination query
202 // optimisations aren't causing different results to be returned.
203 DEFINE_TESTCASE(queries1, writable && !remote && !inmemory) {
204  unsigned int seed = initrand();
205  unsigned int maxtermsperfield = 100;
206  unsigned int repetitions = 10000;
207  QueryBuilder builder(maxtermsperfield, 10, 10);
208 
209  Xapian::Database db;
210  string arg(str(maxtermsperfield));
211  db = backendmanager->get_database("queries1_" + str(seed) + "_" + arg,
212  builddb_queries1, arg);
213 
214  // Reset the random seed, to make results repeatable whether database was
215  // created or not.
216  initrand();
217 
218  Xapian::Enquire enquire(db);
219 
220  unsigned int count = 0;
221  while (++count != repetitions) {
222  Xapian::Query query(builder.make_query());
223  tout.str(string());
224  tout << "query " << count << ": " << query << "\n";
225 
226  enquire.set_query(query);
227  Xapian::MSet mset1 = enquire.get_mset(0, 1);
228  Xapian::MSet mset10 = enquire.get_mset(0, 10);
229  Xapian::MSet msetall = enquire.get_mset(0, db.get_doccount());
230  tout << mset1 << "\n";
231  tout << mset10 << "\n";
232  tout << msetall << "\n";
233  if (mset1.empty()) {
234  TEST(mset10.empty());
235  TEST(msetall.empty());
236  continue;
237  }
238  TEST(mset_range_is_same(mset1, 0, msetall, 0, mset1.size()));
239  TEST(mset_range_is_same(mset10, 0, msetall, 0, mset10.size()));
240  }
241 }
static Xapian::Query query(Xapian::Query::op op, const string &t1=string(), const string &t2=string(), const string &t3=string(), const string &t4=string(), const string &t5=string(), const string &t6=string(), const string &t7=string(), const string &t8=string(), const string &t9=string(), const string &t10=string())
Definition: api_anydb.cc:62
Base class for backend handling in test harness.
Xapian::Database get_database(const std::vector< std::string > &files)
Get a database instance of the current type.
Random query builder.
Xapian::Query make_query()
Build a random query.
vector< QueryStep > options
The possible steps.
unsigned int maxsteps
Maximum number of steps to take when building a query.
QueryBuilder(unsigned int maxtermsperfield_, unsigned int maxchildren_, unsigned int maxsteps_)
QueryBuilderEnv env
The environment for the build steps.
An indexed database of documents.
Definition: database.h:75
Xapian::doccount get_doccount() const
Get the number of documents in the database.
Definition: database.cc:233
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
Querying session.
Definition: enquire.h:57
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
Xapian::doccount size() const
Return number of items in this MSet object.
Definition: mset.cc:374
bool empty() const
Return true if this MSet object is empty.
Definition: mset.h:467
Class representing a query.
Definition: query.h:45
@ OP_XOR
Match documents which an odd number of subqueries match.
Definition: query.h:107
@ OP_AND
Match only documents which all subqueries match.
Definition: query.h:84
@ OP_OR
Match documents which at least one subquery matches.
Definition: query.h:92
@ OP_AND_NOT
Match documents which the first subquery matches but no others do.
Definition: query.h:99
This class provides read/write access to a database.
Definition: database.h:964
void commit()
Commit pending modifications.
Definition: database.cc:543
Xapian::docid add_document(const Xapian::Document &doc)
Add a document to the database.
Definition: database.cc:561
string str(int value)
Convert int to std::string.
Definition: str.cc:91
unsigned XAPIAN_DOCID_BASE_TYPE doccount
A count of documents.
Definition: types.h:37
unsigned int initrand()
Initialise the random number generator with the seed.
Definition: soaktest.cc:38
unsigned int randint(unsigned int s)
Return a random integer in the range 0 to s-1.
Definition: soaktest.cc:45
Long-running "soak" tests for Xapian.
static void combine_XOR(QueryBuilderEnv &env)
Combine some queries with XOR.
static void push_leaf_N(QueryBuilderEnv &env)
Push a leaf query on field N onto the list of query pieces.
DEFINE_TESTCASE(queries1, writable &&!remote &&!inmemory)
static void builddb_queries1(Xapian::WritableDatabase &db, const string &arg)
Make a database in which docs have the fields:
static void combine_NOT(QueryBuilderEnv &env)
Combine some queries with AND_NOT.
static void combine_OR(QueryBuilderEnv &env)
Combine some queries with OR.
void(* QueryStep)(QueryBuilderEnv &)
static void combine_AND(QueryBuilderEnv &env)
Combine some queries with AND.
static int seed
Definition: stemtest.cc:46
Convert types to std::string.
The environment used by the steps when building a query.
QueryBuilderEnv(unsigned int maxtermsperfield_, unsigned int maxchildren_)
unsigned int maxchildren
list< Xapian::Query > pieces
Workspace for the query builder steps.
unsigned int maxtermsperfield
Xapian::Query pop()
Pop a query from the front of the list of pieces, and return it.
list< Xapian::Query >::iterator pick(unsigned int num)
Get an iterator pointing to the "num"th element in pieces.
BackendManager * backendmanager
backendmanager is global so that it can be accessed by individual tests.
Definition: testrunner.cc:41
Run multiple tests for different backends.
std::ostringstream tout
The debug printing stream.
Definition: testsuite.cc:104
a generic test suite engine
#define TEST(a)
Test a condition, without an additional explanation for failure.
Definition: testsuite.h:273
bool mset_range_is_same(const Xapian::MSet &mset1, unsigned int first1, const Xapian::MSet &mset2, unsigned int first2, unsigned int count)
Definition: testutils.cc:45
Xapian-specific test helper functions and macros.
Public interfaces for the Xapian library.