xapian-core  1.4.25
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, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20  * USA
21  */
22 
23 #include <config.h>
24 
25 #include "soaktest/soaktest.h"
27 
28 #include <xapian.h>
29 
30 #include "backendmanager.h"
31 #include "str.h"
32 #include "testrunner.h"
33 #include "testsuite.h"
34 #include "testutils.h"
35 
36 #include <list>
37 
38 using namespace std;
39 
45 static void
47 {
48  unsigned int doccount = 1000;
49  unsigned int maxtermsperfield = atoi(arg.c_str());
50  for (unsigned int i = 0; i < doccount; ++i) {
51  Xapian::Document doc;
52  for (unsigned int j = randint(maxtermsperfield) + 1; j != 0; --j) {
53  doc.add_term("N" + str(j));
54  }
55  db.add_document(doc);
56  }
57  db.commit();
58 }
59 
63  list<Xapian::Query> pieces;
64 
65  unsigned int maxtermsperfield;
66  unsigned int maxchildren;
67 
68  QueryBuilderEnv(unsigned int maxtermsperfield_,
69  unsigned int maxchildren_)
70  : maxtermsperfield(maxtermsperfield_),
71  maxchildren(maxchildren_)
72  {}
73 
76  if (pieces.empty()) return Xapian::Query();
77  Xapian::Query result = pieces.front();
78  pieces.pop_front();
79  return result;
80  }
81 
83  list<Xapian::Query>::iterator pick(unsigned int num) {
84  list<Xapian::Query>::iterator i = pieces.begin();
85  for (unsigned int c = 0; c != num && i != pieces.end(); ++c, ++i) {}
86  return i;
87  }
88 };
89 
90 typedef void (*QueryStep)(QueryBuilderEnv &);
91 
93 static void push_leaf_N(QueryBuilderEnv & env)
94 {
95  env.pieces.push_back(Xapian::Query(
96  "N" + str(randint(env.maxtermsperfield) + 1)));
97 }
98 
104 static void combine_OR(QueryBuilderEnv & env)
105 {
106  list<Xapian::Query>::iterator i = env.pick(randint(env.maxchildren));
107  Xapian::Query combined(Xapian::Query::OP_OR, env.pieces.begin(), i);
108  env.pieces.erase(env.pieces.begin(), i);
109  env.pieces.push_back(combined);
110 }
111 
117 static void combine_AND(QueryBuilderEnv & env)
118 {
119  list<Xapian::Query>::iterator i = env.pick(randint(env.maxchildren));
120  Xapian::Query combined(Xapian::Query::OP_AND, env.pieces.begin(), i);
121  env.pieces.erase(env.pieces.begin(), i);
122  env.pieces.push_back(combined);
123 }
124 
130 static void combine_XOR(QueryBuilderEnv & env)
131 {
132  list<Xapian::Query>::iterator i = env.pick(randint(env.maxchildren));
133  Xapian::Query combined(Xapian::Query::OP_XOR, env.pieces.begin(), i);
134  env.pieces.erase(env.pieces.begin(), i);
135  env.pieces.push_back(combined);
136 }
137 
143 static void combine_NOT(QueryBuilderEnv & env)
144 {
145  if (env.pieces.size() < 2) return;
146  list<Xapian::Query>::iterator i = env.pick(2);
147  Xapian::Query combined(Xapian::Query::OP_AND_NOT, env.pieces.begin(), i);
148  env.pieces.erase(env.pieces.begin(), i);
149  env.pieces.push_back(combined);
150 }
151 
155  vector<QueryStep> options;
156 
159 
161  unsigned int maxsteps;
162 
163  public:
164  QueryBuilder(unsigned int maxtermsperfield_,
165  unsigned int maxchildren_,
166  unsigned int maxsteps_)
167  : env(maxtermsperfield_, maxchildren_),
168  maxsteps(maxsteps_)
169  {
170  // Build up the set of options.
171  // Some options are added multiple times to make them more likely.
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(push_leaf_N);
176  options.push_back(combine_OR);
177  options.push_back(combine_AND);
178  options.push_back(combine_XOR);
179  options.push_back(combine_NOT);
180  }
181 
191  unsigned int steps = randint(maxsteps) + 1;
192  while (steps-- != 0) {
193  QueryStep & step = options[randint(options.size())];
194  step(env);
195  }
196  return env.pop();
197  }
198 };
199 
200 // Generate a load of random queries, and run them checking that the first
201 // returned result is the same when asking for 1 result as it is when asking
202 // for all results. This is a basic test that early-termination query
203 // optimisations aren't causing different results to be returned.
204 DEFINE_TESTCASE(queries1, writable && !remote && !inmemory) {
205  unsigned int seed = initrand();
206  unsigned int maxtermsperfield = 100;
207  unsigned int repetitions = 10000;
208  QueryBuilder builder(maxtermsperfield, 10, 10);
209 
210  Xapian::Database db;
211  string arg(str(maxtermsperfield));
212  db = backendmanager->get_database("queries1_" + str(seed) + "_" + arg,
213  builddb_queries1, arg);
214 
215  // Reset the random seed, to make results repeatable whether database was
216  // created or not.
217  initrand();
218 
219  Xapian::Enquire enquire(db);
220 
221  unsigned int count = 0;
222  while (++count != repetitions) {
223  Xapian::Query query(builder.make_query());
224  tout.str(string());
225  tout << "query " << count << ": " << query << "\n";
226 
227  enquire.set_query(query);
228  Xapian::MSet mset1 = enquire.get_mset(0, 1);
229  Xapian::MSet mset10 = enquire.get_mset(0, 10);
230  Xapian::MSet msetall = enquire.get_mset(0, db.get_doccount());
231  tout << mset1 << "\n";
232  tout << mset10 << "\n";
233  tout << msetall << "\n";
234  if (mset1.empty()) {
235  TEST(mset10.empty());
236  TEST(msetall.empty());
237  continue;
238  }
239  TEST(mset_range_is_same(mset1, 0, msetall, 0, mset1.size()));
240  TEST(mset_range_is_same(mset10, 0, msetall, 0, mset10.size()));
241  }
242 }
Xapian::docid add_document(const Xapian::Document &document)
Add a new document to the database.
Definition: omdatabase.cc:902
The environment used by the steps when building a query.
Run multiple tests for different backends.
unsigned int maxchildren
#define TEST(a)
Test a condition, without an additional explanation for failure.
Definition: testsuite.h:275
This class is used to access a database, or a group of databases.
Definition: database.h:68
Xapian::Database get_database(const std::vector< std::string > &files)
Get a database instance of the current type.
void(* QueryStep)(QueryBuilderEnv &)
Match documents which an odd number of subqueries match.
Definition: query.h:107
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:46
static void combine_XOR(QueryBuilderEnv &env)
Combine some queries with XOR.
list< Xapian::Query >::iterator pick(unsigned int num)
Get an iterator pointing to the "num"th element in pieces.
a generic test suite engine
vector< QueryStep > options
The possible steps.
Class representing a list of search results.
Definition: mset.h:44
STL namespace.
MSet get_mset(Xapian::doccount first, Xapian::doccount maxitems, Xapian::doccount checkatleast=0, const RSet *omrset=0, const MatchDecider *mdecider=0) const
Get (a portion of) the match set for the current query.
Definition: omenquire.cc:932
Convert types to std::string.
Xapian::doccount get_doccount() const
Get the number of documents in the database.
Definition: omdatabase.cc:267
QueryBuilder(unsigned int maxtermsperfield_, unsigned int maxchildren_, unsigned int maxsteps_)
QueryBuilderEnv(unsigned int maxtermsperfield_, unsigned int maxchildren_)
unsigned int maxtermsperfield
list< Xapian::Query > pieces
Workspace for the query builder steps.
Base class for backend handling in test harness.
Xapian::Query make_query()
Build a random query.
This class provides read/write access to a database.
Definition: database.h:789
std::ostringstream tout
The debug printing stream.
Definition: testsuite.cc:103
Xapian::Query pop()
Pop a query from the front of the list of pieces, and return it.
Public interfaces for the Xapian library.
BackendManager * backendmanager
backendmanager is global so that it can be accessed by individual tests.
Definition: testrunner.cc:42
string str(int value)
Convert int to std::string.
Definition: str.cc:90
static int seed
Definition: stemtest.cc:45
void commit()
Commit any pending modifications made to the database.
Definition: omdatabase.cc:857
DEFINE_TESTCASE(queries1, writable &&!remote &&!inmemory)
static void combine_AND(QueryBuilderEnv &env)
Combine some queries with AND.
void set_query(const Xapian::Query &query, Xapian::termcount qlen=0)
Set the query to run.
Definition: omenquire.cc:793
static void builddb_queries1(Xapian::WritableDatabase &db, const string &arg)
Make a database in which docs have the fields:
static void push_leaf_N(QueryBuilderEnv &env)
Push a leaf query on field N onto the list of query pieces.
Match only documents which all subqueries match.
Definition: query.h:84
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:63
Random query builder.
QueryBuilderEnv env
The environment for the build steps.
This class provides an interface to the information retrieval system for the purpose of searching...
Definition: enquire.h:152
unsigned XAPIAN_DOCID_BASE_TYPE doccount
A count of documents.
Definition: types.h:38
Match documents which the first subquery matches but no others do.
Definition: query.h:99
Match documents which at least one subquery matches.
Definition: query.h:92
Xapian-specific test helper functions and macros.
static void combine_NOT(QueryBuilderEnv &env)
Combine some queries with AND_NOT.
static void combine_OR(QueryBuilderEnv &env)
Combine some queries with OR.
unsigned int randint(unsigned int s)
Return a random integer in the range 0 to s-1.
Definition: soaktest.cc:46
Class representing a query.
Definition: query.h:46
Long-running "soak" tests for Xapian.
unsigned int maxsteps
Maximum number of steps to take when building a query.
A handle representing a document in a Xapian database.
Definition: document.h:61
unsigned int initrand()
Initialise the random number generator with the seed.
Definition: soaktest.cc:39
void add_term(const std::string &tname, Xapian::termcount wdfinc=1)
Add a term to the document, without positional information.
Definition: omdocument.cc:140