source: trunk/gsdl/src/recpt/queryaction.cpp@ 421

Last change on this file since 421 was 421, checked in by sjboddie, 25 years ago

added collectinfo argument to some functions

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 18.8 KB
Line 
1/**********************************************************************
2 *
3 * queryaction.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * PUT COPYRIGHT NOTICE HERE
7 *
8 * $Id: queryaction.cpp 421 1999-07-30 02:24:45Z sjboddie $
9 *
10 *********************************************************************/
11
12/*
13 $Log$
14 Revision 1.17 1999/07/30 02:24:42 sjboddie
15 added collectinfo argument to some functions
16
17 Revision 1.16 1999/07/19 00:16:58 sjboddie
18 no longer display documents that don't match all phrases in query string
19
20 Revision 1.15 1999/07/16 08:33:36 rjmcnab
21 Changed the logic for getting the results string slightly
22
23 Revision 1.14 1999/07/16 03:41:29 sjboddie
24 changed isApprox
25
26 Revision 1.13 1999/07/16 00:19:01 sjboddie
27 some changes to the way quoted queries are handled
28
29 Revision 1.12 1999/07/09 02:17:55 rjmcnab
30 Setting macros needed for a second query.
31
32 Revision 1.11 1999/07/07 06:13:10 rjmcnab
33 Added ability to combine two independant queries.
34
35 Revision 1.10 1999/07/07 05:49:35 sjboddie
36 had another crack at the format string code - created a new formattools
37 module. It can now handle {If} and {Or} statements although there's a
38 bug preventing nested if's and or's.
39
40 Revision 1.9 1999/07/01 22:48:46 sjboddie
41 had a go at getting a query result format string working
42
43 Revision 1.8 1999/06/27 22:02:11 sjboddie
44 author is added to queryresults if there is one
45
46 Revision 1.7 1999/06/26 01:10:18 rjmcnab
47 Made h, i, and n arguments saved in the compressed arguments.
48
49 Revision 1.6 1999/06/24 05:12:25 sjboddie
50 lots of small changes
51
52 Revision 1.5 1999/06/16 04:03:48 sjboddie
53 Now sets "cl" arg to "search" when going to a document from a search
54 results page. This allows the close book icon (in hierarchy toc) to
55 take you back to the results page if that's where you came from.
56 If you got to the document page somehow other than from a
57 classification or a search (i.e. if "cl" isn't set) then the close
58 book icon is disabled
59
60 Revision 1.4 1999/06/16 02:08:38 sjboddie
61 got queryaction working
62
63 Revision 1.3 1999/03/25 03:06:45 sjboddie
64
65 altered receptionist slightly so it now passes *collectproto to
66 define_internal_macros and define_external_macros - need it
67 for browseaction
68
69 Revision 1.2 1999/03/03 20:26:50 rjmcnab
70
71 Modified stuff.
72
73 Revision 1.1 1999/02/28 22:45:21 rjmcnab
74
75 Initial revision.
76
77 */
78
79
80#include "queryaction.h"
81#include "querytools.h"
82#include "formattools.h"
83
84queryaction::queryaction () {
85
86 num_phrases = 0;
87
88 // this action uses cgi variable "a"
89 cgiarginfo arg_ainfo;
90 arg_ainfo.shortname = "a";
91 arg_ainfo.longname = "action";
92 arg_ainfo.multiplechar = true;
93 arg_ainfo.defaultstatus = cgiarginfo::weak;
94 arg_ainfo.argdefault = "q";
95 arg_ainfo.savedarginfo = cgiarginfo::must;
96 argsinfo.addarginfo (NULL, arg_ainfo);
97
98 // "h"
99 arg_ainfo.shortname = "h";
100 arg_ainfo.longname = "main index";
101 arg_ainfo.multiplechar = true;
102 arg_ainfo.defaultstatus = cgiarginfo::weak;
103 arg_ainfo.argdefault = "";
104 arg_ainfo.savedarginfo = cgiarginfo::must;
105 argsinfo.addarginfo (NULL, arg_ainfo);
106
107 // "h2"
108 arg_ainfo.shortname = "h2";
109 arg_ainfo.longname = "main index for second query";
110 arg_ainfo.multiplechar = true;
111 arg_ainfo.defaultstatus = cgiarginfo::weak;
112 arg_ainfo.argdefault = "";
113 arg_ainfo.savedarginfo = cgiarginfo::must;
114 argsinfo.addarginfo (NULL, arg_ainfo);
115
116 // "j"
117 arg_ainfo.shortname = "j";
118 arg_ainfo.longname = "sub collection index";
119 arg_ainfo.multiplechar = true;
120 arg_ainfo.defaultstatus = cgiarginfo::weak;
121 arg_ainfo.argdefault = "";
122 arg_ainfo.savedarginfo = cgiarginfo::must;
123 argsinfo.addarginfo (NULL, arg_ainfo);
124
125 // "j2"
126 arg_ainfo.shortname = "j2";
127 arg_ainfo.longname = "sub collection index for second query";
128 arg_ainfo.multiplechar = true;
129 arg_ainfo.defaultstatus = cgiarginfo::weak;
130 arg_ainfo.argdefault = "";
131 arg_ainfo.savedarginfo = cgiarginfo::must;
132 argsinfo.addarginfo (NULL, arg_ainfo);
133
134 // "n"
135 arg_ainfo.shortname = "n";
136 arg_ainfo.longname = "language index";
137 arg_ainfo.multiplechar = true;
138 arg_ainfo.defaultstatus = cgiarginfo::weak;
139 arg_ainfo.argdefault = "";
140 arg_ainfo.savedarginfo = cgiarginfo::must;
141 argsinfo.addarginfo (NULL, arg_ainfo);
142
143 // "n2"
144 arg_ainfo.shortname = "n2";
145 arg_ainfo.longname = "language index for second query";
146 arg_ainfo.multiplechar = true;
147 arg_ainfo.defaultstatus = cgiarginfo::weak;
148 arg_ainfo.argdefault = "";
149 arg_ainfo.savedarginfo = cgiarginfo::must;
150 argsinfo.addarginfo (NULL, arg_ainfo);
151
152 // "q"
153 arg_ainfo.shortname = "q";
154 arg_ainfo.longname = "query string";
155 arg_ainfo.multiplechar = true;
156 arg_ainfo.defaultstatus = cgiarginfo::weak;
157 arg_ainfo.argdefault = "";
158 arg_ainfo.savedarginfo = cgiarginfo::must;
159 argsinfo.addarginfo (NULL, arg_ainfo);
160
161 // "q2"
162 arg_ainfo.shortname = "q2";
163 arg_ainfo.longname = "query string for second query";
164 arg_ainfo.multiplechar = true;
165 arg_ainfo.defaultstatus = cgiarginfo::weak;
166 arg_ainfo.argdefault = "";
167 arg_ainfo.savedarginfo = cgiarginfo::must;
168 argsinfo.addarginfo (NULL, arg_ainfo);
169
170 // "cq2" ""=don't combine, "and", "or", "not"
171 arg_ainfo.shortname = "cq2";
172 arg_ainfo.longname = "combine queries";
173 arg_ainfo.multiplechar = true;
174 arg_ainfo.defaultstatus = cgiarginfo::weak;
175 arg_ainfo.argdefault = "";
176 arg_ainfo.savedarginfo = cgiarginfo::must;
177 argsinfo.addarginfo (NULL, arg_ainfo);
178
179 // "t" - 1 = ranked 0 = boolean
180 arg_ainfo.shortname = "t";
181 arg_ainfo.longname = "search type";
182 arg_ainfo.multiplechar = false;
183 arg_ainfo.defaultstatus = cgiarginfo::weak;
184 arg_ainfo.argdefault = "1";
185 arg_ainfo.savedarginfo = cgiarginfo::must;
186 argsinfo.addarginfo (NULL, arg_ainfo);
187
188 // "k"
189 arg_ainfo.shortname = "k";
190 arg_ainfo.longname = "casefolding";
191 arg_ainfo.multiplechar = false;
192 arg_ainfo.defaultstatus = cgiarginfo::weak;
193 arg_ainfo.argdefault = "1";
194 arg_ainfo.savedarginfo = cgiarginfo::must;
195 argsinfo.addarginfo (NULL, arg_ainfo);
196
197 // "s"
198 arg_ainfo.shortname = "s";
199 arg_ainfo.longname = "stemming";
200 arg_ainfo.multiplechar = false;
201 arg_ainfo.defaultstatus = cgiarginfo::weak;
202 arg_ainfo.argdefault ="0";
203 arg_ainfo.savedarginfo = cgiarginfo::must;
204 argsinfo.addarginfo (NULL, arg_ainfo);
205
206 // "m"
207 arg_ainfo.shortname = "m";
208 arg_ainfo.longname = "maximum number of documents";
209 arg_ainfo.multiplechar = true;
210 arg_ainfo.defaultstatus = cgiarginfo::weak;
211 arg_ainfo.argdefault = "50";
212 arg_ainfo.savedarginfo = cgiarginfo::must;
213 argsinfo.addarginfo (NULL, arg_ainfo);
214
215 // "o"
216 arg_ainfo.shortname = "o";
217 arg_ainfo.longname = "hits per page";
218 arg_ainfo.multiplechar = true;
219 arg_ainfo.defaultstatus = cgiarginfo::weak;
220 arg_ainfo.argdefault = "20";
221 arg_ainfo.savedarginfo = cgiarginfo::must;
222 argsinfo.addarginfo (NULL, arg_ainfo);
223
224 // "r"
225 arg_ainfo.shortname = "r";
226 arg_ainfo.longname = "start results from";
227 arg_ainfo.multiplechar = true;
228 arg_ainfo.defaultstatus = cgiarginfo::weak;
229 arg_ainfo.argdefault = "1";
230 arg_ainfo.savedarginfo = cgiarginfo::must;
231 argsinfo.addarginfo (NULL, arg_ainfo);
232}
233
234void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
235 action::configure (key, cfgline);
236}
237
238bool queryaction::init (ostream &logout) {
239 return action::init (logout);
240}
241
242bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
243 ostream &logout) {
244
245 // check t argument
246 int arg_t = args.getintarg("t");
247 if (arg_t != 0 && arg_t != 1) {
248 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
249 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
250 if (tinfo != NULL) args["t"] = tinfo->argdefault;
251 }
252
253 // check k argument
254 int arg_k = args.getintarg("k");
255 if (arg_k != 0 && arg_k != 1) {
256 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
257 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
258 if (kinfo != NULL) args["k"] = kinfo->argdefault;
259 }
260
261 // check s argument
262 int arg_s = args.getintarg("s");
263 if (arg_s != 0 && arg_s != 1) {
264 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
265 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
266 if (sinfo != NULL) args["s"] = sinfo->argdefault;
267 }
268
269 // check m argument
270 int arg_m = args.getintarg("m");
271 if (arg_m < 0) {
272 logout << "Warning: \"m\" argument less than 0 (" << arg_m << ")\n";
273 cgiarginfo *minfo = argsinfo.getarginfo ("m");
274 if (minfo != NULL) args["m"] = minfo->argdefault;
275 }
276
277 // check o argument
278 int arg_o = args.getintarg("o");
279 if (arg_o < 0) {
280 logout << "Warning: \"o\" argument less than 0 (" << arg_o << ")\n";
281 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
282 if (oinfo != NULL) args["o"] = oinfo->argdefault;
283 }
284
285 // check r argument
286 int arg_r = args.getintarg("r");
287 if (arg_r < 1) {
288 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
289 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
290 if (rinfo != NULL) args["r"] = rinfo->argdefault;
291 }
292
293 return true;
294}
295
296void queryaction::get_cgihead_info (cgiargsclass &/*args*/, response_t &response,
297 text_t &response_data, ostream &/*logout*/) {
298 response = content;
299 response_data = "text/html";
300}
301
302void queryaction::define_internal_macros (const ColInfoResponse_t &/*collectinfo*/, displayclass &disp,
303 cgiargsclass &args, recptproto */*collectproto*/,
304 ostream &/*logout*/) {
305
306 // define_internal_macros sets the following macros:
307
308 // _quotedquery_ the part of the query string that was quoted for post-processing
309
310
311
312 // The following macros are set later (in define_query_macros) as they can't be set until
313 // the query has been done.
314
315 // _freqmsg_ the term frequency string
316
317 // _resultline_ the "x documents matched the query" string
318
319 // _prevfirst_ these are used when setting up the links to previous/next
320 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
321 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
322 // _nextlast_
323 // _thisfirst_
324 // _thislast_
325
326
327 // get the quoted bits of the query string and set _quotedquery_
328 text_tarray phrases;
329 get_phrases (args["q"], phrases);
330 text_tarray::const_iterator phere = phrases.begin();
331 text_tarray::const_iterator pend = phrases.end();
332 bool first = true;
333 text_t quotedquery;
334 while (phere != pend) {
335 if (!first)
336 if ((phere +1) == pend) quotedquery += " and ";
337 else quotedquery += ", ";
338
339 quotedquery += "\"" + *phere + "\"";
340 first = false;
341 phere ++;
342 }
343 if (args.getintarg("s")) quotedquery += "_textstemon_";
344 disp.setmacro ("quotedquery", "query", quotedquery);
345
346 // we'll also set num_phrases here so we don't have to parse the
347 // querystring again later (we need to know this before outputting
348 // results so we don't include results for documents not containing
349 // all requested phrases).
350 num_phrases = phrases.size();
351
352}
353
354// sets the selection box macros _hselection_, _jselection_, and _nselection_.
355// each option will need an _optionxoption_ macro (i.e. an _hselection_ macro
356// with options stx and ptx will need _optionhstx_ and _optionhptx_ macros)
357void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
358 const FilterOption_t &option, displayclass &disp) {
359
360 if (option.validValues.size() < 2) return;
361
362 text_t macrovalue = "<select name=\"" + macroname + "\">\n";
363
364 if (current_value.empty()) current_value = option.defaultValue;
365
366 text_tarray::const_iterator thisvalue = option.validValues.begin();
367 text_tarray::const_iterator endvalue = option.validValues.end();
368
369 while (thisvalue != endvalue) {
370 macrovalue += "<option value=\"" + *thisvalue + "\"";
371 if (*thisvalue == current_value)
372 macrovalue += " selected";
373 macrovalue += ">_option" + macroname + *thisvalue + "_\n";
374 thisvalue ++;
375 }
376 macrovalue += "</select>\n";
377 disp.setmacro (macroname + "selection", "Global", macrovalue);
378}
379
380void queryaction::define_external_macros (const ColInfoResponse_t &/*collectinfo*/, displayclass &disp,
381 cgiargsclass &args, recptproto *collectproto,
382 ostream &logout) {
383
384 // define_external_macros sets the following macros:
385
386 // some or all of these may not be required to be set
387 // _hselection_, _h2selection_ the selection box for the main part of the index
388 // _jselection_, _j2selection_ the selection box for the subcollection part of the index
389 // _nselection_, _n2selection_ the selection box for the language part of the index
390 // _cq2selection the selection box for combining two queries
391
392
393 // can't do anything if collectproto is null (i.e. no collection was specified)
394 if (collectproto == NULL) return;
395
396 comerror_t err;
397 InfoFilterOptionsResponse_t response;
398 InfoFilterOptionsRequest_t request;
399 request.filterName = "QueryFilter";
400
401 collectproto->get_filteroptions (args["c"], request, response, err, logout);
402 if (err == noError) {
403
404 FilterOption_tmap::const_iterator it;
405 FilterOption_tmap::const_iterator end = response.filterOptions.end();
406
407 // _hselection_ and _h2selection_ (Index)
408 it = response.filterOptions.find ("Index");
409 if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
410 if (it != end) set_option_macro ("h2", args["h2"], (*it).second, disp);
411
412 // _jselection_ and _j2selection_ (Subcollection)
413 it = response.filterOptions.find ("Subcollection");
414 if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
415 if (it != end) set_option_macro ("j2", args["j2"], (*it).second, disp);
416
417 // _nselection_ and _n2selection_ (Language)
418 it = response.filterOptions.find ("Language");
419 if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
420 if (it != end) set_option_macro ("n2", args["n2"], (*it).second, disp);
421
422 // _cq2selection_ (CombineQuery)
423 it = response.filterOptions.find ("CombineQuery");
424 if (it != end) set_option_macro ("cq2", args["cq2"], (*it).second, disp);
425 }
426}
427
428bool queryaction::do_action (cgiargsclass &args, const ColInfoResponse_t &collectinfo,
429 recptproto *collectproto, displayclass &disp,
430 outconvertclass &outconvert, ostream &textout,
431 ostream &logout) {
432
433 if (formatstring.empty()) {
434 text_tmap::const_iterator result = collectinfo.format.find("result");
435 if (result != collectinfo.format.end())
436 formatstring = (*result).second;
437 }
438
439 // if we still don't have a format string use the default
440 if (formatstring.empty())
441 formatstring = "<td valign=top nowrap>[link]_icontext_[/link]</td><td>[Title]</td>";
442
443 if (collectproto == NULL) {
444 logout << "queryaction::do_action called with NULL collectproto\n";
445 textout << outconvert << disp << "_query:header_\n"
446 << "Error: Attempt to do query without setting collection\n"
447 << "_query:footer_\n";
448 } else {
449
450 FilterRequest_t request;
451 FilterResponse_t response;
452 format_t *formatlistptr = new format_t();
453
454 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
455
456 // do the query
457 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
458 if (!do_query (request, args, collectproto, response, logout))
459 return false;
460
461 // set macros
462 define_query_macros (args, disp, response);
463
464 // output the header
465 textout << outconvert << disp << "_query:header_\n"
466 << "_query:content_";
467
468 // output the results
469 textout << "<table cellspacing=4>\n";
470 ResultDocInfo_tarray::const_iterator this_doc = response.docInfo.begin();
471 ResultDocInfo_tarray::const_iterator end_doc = response.docInfo.end();
472
473 while (this_doc != end_doc) {
474 // don't include docs that didn't match phrases (if there were any)
475 // those that did match will have been sorted to the top
476 if ((*this_doc).num_phrase_match < num_phrases) break;
477 textout << outconvert << disp << "<tr>\n"
478
479 // << "<td valign=top nowrap>r: " << (*this_doc).ranking
480 // << " t: " << (*this_doc).num_terms_matched << " p: "
481 // << (*this_doc).num_phrase_match << "</td>\n"
482
483 << get_formatted_string (*this_doc, formatlistptr) << "\n"
484 << "</tr>\n";
485
486 this_doc ++;
487 }
488 textout << "</table>\n";
489
490 delete (formatlistptr);
491
492 // output the footer
493 textout << outconvert << disp << "_query:footer_";
494 }
495
496 return true;
497}
498
499// define_query_macros sets the macros that couldn't be set until the
500// query had been done. Those macros are _freqmsg_, _quotedquery_,
501// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
502// _thisfirst_, and _thislast_
503void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
504 const FilterResponse_t &response) {
505 // set up _freqmsg_ and _quotedquery_ macros
506 text_t freqmsg = "_textfreqmsg1_";
507 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
508 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
509 while (this_term != end_term) {
510 freqmsg += (*this_term).term + ": " + (*this_term).freq;
511 if ((this_term + 1) != end_term)
512 freqmsg += ", ";
513 this_term ++;
514 }
515
516 disp.setmacro ("freqmsg", "query", freqmsg);
517
518
519 // set up _resultline_ macro
520 text_t resline;
521 int maxdocs = args.getintarg("m");
522 int numdocs = response.numDocs;
523 isapprox isApprox = response.isApprox;
524
525 // if there were phrases (post-processing) we're not going to include
526 // those documents that didn't match
527 if (num_phrases > 0) {
528 numdocs = 0;
529 isApprox = Exact;
530 ResultDocInfo_tarray::const_iterator this_doc = response.docInfo.begin();
531 ResultDocInfo_tarray::const_iterator end_doc = response.docInfo.end();
532 while (this_doc != end_doc) {
533 if ((*this_doc).num_phrase_match == num_phrases) numdocs ++;
534 else break; // we can bail here as matching docs are sorted to top
535 this_doc++;
536 }
537 }
538
539 if (isApprox == MoreThan && numdocs > maxdocs) numdocs = maxdocs;
540
541 if (isApprox == Approximate) resline = "_textapprox_";
542 else if (isApprox == MoreThan) resline = "_textmorethan_";
543
544 if (numdocs == 0) resline = "_textnodocs_";
545 else if (numdocs == 1) resline += "_text1doc_";
546 else resline += text_t(numdocs) + " _textlotsdocs_";
547
548 disp.setmacro("resultline", "query", resline);
549
550
551 int firstdoc = args.getintarg("r");
552 int hitsperpage = args.getintarg("o");
553
554 // set up _thisfirst_ and _thislast_ macros
555 disp.setmacro ("thisfirst", "query", firstdoc);
556 int thislast = firstdoc + (hitsperpage - 1);
557 if (thislast > numdocs) thislast = numdocs;
558 disp.setmacro ("thislast", "query", thislast);
559
560 // set up _prevfirst_ and _prevlast_ macros
561 if (firstdoc > 1) {
562 disp.setmacro ("prevlast", "query", firstdoc - 1);
563 int prevfirst = firstdoc - hitsperpage;
564 if (prevfirst < 1) prevfirst = 1;
565 disp.setmacro ("prevfirst", "query", prevfirst);
566 }
567
568 // set up _nextfirst_ and _nextlast_ macros
569 if (thislast < numdocs) {
570 disp.setmacro ("nextfirst", "query", thislast + 1);
571 int nextlast = thislast + hitsperpage;
572 if (nextlast > numdocs) nextlast = numdocs;
573 disp.setmacro ("nextlast", "query", nextlast);
574 }
575}
576
577
578
Note: See TracBrowser for help on using the repository browser.