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

Last change on this file since 919 was 865, checked in by sjboddie, 24 years ago

fixed bug in cross-collection searching, tidied up a bit

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 30.4 KB
Line 
1/**********************************************************************
2 *
3 * queryaction.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * $Id: queryaction.cpp 865 2000-01-24 22:58:00Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.33 2000/01/24 22:57:59 sjboddie
31 fixed bug in cross-collection searching, tidied up a bit
32
33 Revision 1.32 1999/12/13 02:54:11 davidb
34 Support for cross collection searching (CCS)
35
36 Revision 1.31 1999/12/05 21:22:33 sjboddie
37 tidied up cross-collection searching a bit
38
39 Revision 1.30 1999/11/08 20:26:37 sjboddie
40 added multiplevalue option to cgiarginfo
41
42 Revision 1.29 1999/11/04 20:29:53 sjboddie
43 small change to cross-collection searching
44
45 Revision 1.28 1999/11/03 22:49:50 sjboddie
46 A few changes to cross-collection searching for fao
47
48 Revision 1.27 1999/11/01 21:53:27 sjboddie
49 added cross-collection searching capability - still needs lots of
50 work but the basic functionality is there
51
52 Revision 1.26 1999/10/10 08:14:10 sjboddie
53 - metadata now returns mp rather than array
54 - redesigned browsing support (although it's not finished so
55 won't currently work ;-)
56
57 Revision 1.25 1999/09/24 04:49:39 sjboddie
58 fixed up the query selection boxes to display properly if there's only
59 a single index/sub-collection
60
61 Revision 1.24 1999/09/22 03:44:31 sjboddie
62 EndResults query filter option may now take '-1' for 'all'
63
64 Revision 1.23 1999/09/21 11:34:42 sjboddie
65 added Maxdocs queryfilter option which may be -1 for 'all'
66
67 Revision 1.22 1999/09/07 23:08:51 rjmcnab
68 removed some compiler warnings
69
70 Revision 1.21 1999/09/07 04:56:57 sjboddie
71 added GPL notice
72
73 Revision 1.20 1999/08/25 04:47:55 sjboddie
74 added advanced search option - other minor changes
75
76 Revision 1.19 1999/08/13 04:17:24 sjboddie
77 small change to do with new collection-level metadata
78
79 Revision 1.18 1999/08/10 22:46:33 sjboddie
80 changed format option result to QueryResults and added QueryLinks option
81
82 Revision 1.17 1999/07/30 02:24:42 sjboddie
83 added collectinfo argument to some functions
84
85 Revision 1.16 1999/07/19 00:16:58 sjboddie
86 no longer display documents that don't match all phrases in query string
87
88 Revision 1.15 1999/07/16 08:33:36 rjmcnab
89 Changed the logic for getting the results string slightly
90
91 Revision 1.14 1999/07/16 03:41:29 sjboddie
92 changed isApprox
93
94 Revision 1.13 1999/07/16 00:19:01 sjboddie
95 some changes to the way quoted queries are handled
96
97 Revision 1.12 1999/07/09 02:17:55 rjmcnab
98 Setting macros needed for a second query.
99
100 Revision 1.11 1999/07/07 06:13:10 rjmcnab
101 Added ability to combine two independant queries.
102
103 Revision 1.10 1999/07/07 05:49:35 sjboddie
104 had another crack at the format string code - created a new formattools
105 module. It can now handle {If} and {Or} statements although there's a
106 bug preventing nested if's and or's.
107
108 Revision 1.9 1999/07/01 22:48:46 sjboddie
109 had a go at getting a query result format string working
110
111 Revision 1.8 1999/06/27 22:02:11 sjboddie
112 author is added to queryresults if there is one
113
114 Revision 1.7 1999/06/26 01:10:18 rjmcnab
115 Made h, i, and n arguments saved in the compressed arguments.
116
117 Revision 1.6 1999/06/24 05:12:25 sjboddie
118 lots of small changes
119
120 Revision 1.5 1999/06/16 04:03:48 sjboddie
121 Now sets "cl" arg to "search" when going to a document from a search
122 results page. This allows the close book icon (in hierarchy toc) to
123 take you back to the results page if that's where you came from.
124 If you got to the document page somehow other than from a
125 classification or a search (i.e. if "cl" isn't set) then the close
126 book icon is disabled
127
128 Revision 1.4 1999/06/16 02:08:38 sjboddie
129 got queryaction working
130
131 Revision 1.3 1999/03/25 03:06:45 sjboddie
132
133 altered receptionist slightly so it now passes *collectproto to
134 define_internal_macros and define_external_macros - need it
135 for browseaction
136
137 Revision 1.2 1999/03/03 20:26:50 rjmcnab
138
139 Modified stuff.
140
141 Revision 1.1 1999/02/28 22:45:21 rjmcnab
142
143 Initial revision.
144
145 */
146
147
148#include "queryaction.h"
149#include "querytools.h"
150#include "formattools.h"
151#include "cgiutils.h"
152#include "OIDtools.h"
153
154void colinfo_t::clear () {
155 formatlistptr = NULL;
156 browserptr = NULL;
157}
158
159void QueryResult_t::clear() {
160 doc.clear();
161 collection.clear();
162}
163
164queryaction::queryaction () {
165
166 num_phrases = 0;
167
168 // this action uses cgi variable "a"
169 cgiarginfo arg_ainfo;
170 arg_ainfo.shortname = "a";
171 arg_ainfo.longname = "action";
172 arg_ainfo.multiplechar = true;
173 arg_ainfo.defaultstatus = cgiarginfo::weak;
174 arg_ainfo.argdefault = "q";
175 arg_ainfo.savedarginfo = cgiarginfo::must;
176 argsinfo.addarginfo (NULL, arg_ainfo);
177
178 // "b" - 0 = simple, 1 = advanced
179 arg_ainfo.shortname = "b";
180 arg_ainfo.longname = "query mode";
181 arg_ainfo.multiplechar = false;
182 arg_ainfo.defaultstatus = cgiarginfo::weak;
183 arg_ainfo.argdefault = "0";
184 arg_ainfo.savedarginfo = cgiarginfo::must;
185 argsinfo.addarginfo (NULL, arg_ainfo);
186
187 // "h"
188 arg_ainfo.shortname = "h";
189 arg_ainfo.longname = "main index";
190 arg_ainfo.multiplechar = true;
191 arg_ainfo.defaultstatus = cgiarginfo::weak;
192 arg_ainfo.argdefault = "";
193 arg_ainfo.savedarginfo = cgiarginfo::must;
194 argsinfo.addarginfo (NULL, arg_ainfo);
195
196 // "h2"
197 arg_ainfo.shortname = "h2";
198 arg_ainfo.longname = "main index for second query";
199 arg_ainfo.multiplechar = true;
200 arg_ainfo.defaultstatus = cgiarginfo::weak;
201 arg_ainfo.argdefault = "";
202 arg_ainfo.savedarginfo = cgiarginfo::must;
203 argsinfo.addarginfo (NULL, arg_ainfo);
204
205 // "j"
206 arg_ainfo.shortname = "j";
207 arg_ainfo.longname = "sub collection index";
208 arg_ainfo.multiplechar = true;
209 arg_ainfo.defaultstatus = cgiarginfo::weak;
210 arg_ainfo.argdefault = "";
211 arg_ainfo.savedarginfo = cgiarginfo::must;
212 argsinfo.addarginfo (NULL, arg_ainfo);
213
214 // "j2"
215 arg_ainfo.shortname = "j2";
216 arg_ainfo.longname = "sub collection index for second query";
217 arg_ainfo.multiplechar = true;
218 arg_ainfo.defaultstatus = cgiarginfo::weak;
219 arg_ainfo.argdefault = "";
220 arg_ainfo.savedarginfo = cgiarginfo::must;
221 argsinfo.addarginfo (NULL, arg_ainfo);
222
223 // "n"
224 arg_ainfo.shortname = "n";
225 arg_ainfo.longname = "language index";
226 arg_ainfo.multiplechar = true;
227 arg_ainfo.defaultstatus = cgiarginfo::weak;
228 arg_ainfo.argdefault = "";
229 arg_ainfo.savedarginfo = cgiarginfo::must;
230 argsinfo.addarginfo (NULL, arg_ainfo);
231
232 // "n2"
233 arg_ainfo.shortname = "n2";
234 arg_ainfo.longname = "language index for second query";
235 arg_ainfo.multiplechar = true;
236 arg_ainfo.defaultstatus = cgiarginfo::weak;
237 arg_ainfo.argdefault = "";
238 arg_ainfo.savedarginfo = cgiarginfo::must;
239 argsinfo.addarginfo (NULL, arg_ainfo);
240
241 // "q"
242 arg_ainfo.shortname = "q";
243 arg_ainfo.longname = "query string";
244 arg_ainfo.multiplechar = true;
245 arg_ainfo.defaultstatus = cgiarginfo::weak;
246 arg_ainfo.argdefault = "";
247 arg_ainfo.savedarginfo = cgiarginfo::must;
248 argsinfo.addarginfo (NULL, arg_ainfo);
249
250 // "q2"
251 arg_ainfo.shortname = "q2";
252 arg_ainfo.longname = "query string for second query";
253 arg_ainfo.multiplechar = true;
254 arg_ainfo.defaultstatus = cgiarginfo::weak;
255 arg_ainfo.argdefault = "";
256 arg_ainfo.savedarginfo = cgiarginfo::must;
257 argsinfo.addarginfo (NULL, arg_ainfo);
258
259 // "cq2" ""=don't combine, "and", "or", "not"
260 arg_ainfo.shortname = "cq2";
261 arg_ainfo.longname = "combine queries";
262 arg_ainfo.multiplechar = true;
263 arg_ainfo.defaultstatus = cgiarginfo::weak;
264 arg_ainfo.argdefault = "";
265 arg_ainfo.savedarginfo = cgiarginfo::must;
266 argsinfo.addarginfo (NULL, arg_ainfo);
267
268 // "t" - 1 = ranked 0 = boolean
269 arg_ainfo.shortname = "t";
270 arg_ainfo.longname = "search type";
271 arg_ainfo.multiplechar = false;
272 arg_ainfo.defaultstatus = cgiarginfo::weak;
273 arg_ainfo.argdefault = "1";
274 arg_ainfo.savedarginfo = cgiarginfo::must;
275 argsinfo.addarginfo (NULL, arg_ainfo);
276
277 // "k"
278 arg_ainfo.shortname = "k";
279 arg_ainfo.longname = "casefolding";
280 arg_ainfo.multiplechar = false;
281 arg_ainfo.defaultstatus = cgiarginfo::weak;
282 arg_ainfo.argdefault = "1";
283 arg_ainfo.savedarginfo = cgiarginfo::must;
284 argsinfo.addarginfo (NULL, arg_ainfo);
285
286 // "s"
287 arg_ainfo.shortname = "s";
288 arg_ainfo.longname = "stemming";
289 arg_ainfo.multiplechar = false;
290 arg_ainfo.defaultstatus = cgiarginfo::weak;
291 arg_ainfo.argdefault ="0";
292 arg_ainfo.savedarginfo = cgiarginfo::must;
293 argsinfo.addarginfo (NULL, arg_ainfo);
294
295 // "m"
296 arg_ainfo.shortname = "m";
297 arg_ainfo.longname = "maximum number of documents";
298 arg_ainfo.multiplechar = true;
299 arg_ainfo.defaultstatus = cgiarginfo::weak;
300 arg_ainfo.argdefault = "50";
301 arg_ainfo.savedarginfo = cgiarginfo::must;
302 argsinfo.addarginfo (NULL, arg_ainfo);
303
304 // "o"
305 arg_ainfo.shortname = "o";
306 arg_ainfo.longname = "hits per page";
307 arg_ainfo.multiplechar = true;
308 arg_ainfo.defaultstatus = cgiarginfo::weak;
309 arg_ainfo.argdefault = "20";
310 arg_ainfo.savedarginfo = cgiarginfo::must;
311 argsinfo.addarginfo (NULL, arg_ainfo);
312
313 // "r"
314 arg_ainfo.shortname = "r";
315 arg_ainfo.longname = "start results from";
316 arg_ainfo.multiplechar = true;
317 arg_ainfo.defaultstatus = cgiarginfo::weak;
318 arg_ainfo.argdefault = "1";
319 arg_ainfo.savedarginfo = cgiarginfo::must;
320 argsinfo.addarginfo (NULL, arg_ainfo);
321
322 // "ccs"
323 arg_ainfo.shortname = "ccs";
324 arg_ainfo.longname = "cross collection searching";
325 arg_ainfo.multiplechar = false;
326 arg_ainfo.defaultstatus = cgiarginfo::weak;
327 arg_ainfo.argdefault = "0";
328 arg_ainfo.savedarginfo = cgiarginfo::must;
329 argsinfo.addarginfo (NULL, arg_ainfo);
330
331 // "ccp"
332 arg_ainfo.shortname = "ccp";
333 arg_ainfo.longname = "cross collection page";
334 arg_ainfo.multiplechar = false;
335 arg_ainfo.defaultstatus = cgiarginfo::weak;
336 arg_ainfo.argdefault = "0";
337 arg_ainfo.savedarginfo = cgiarginfo::must;
338 argsinfo.addarginfo (NULL, arg_ainfo);
339
340 // "cc"
341 arg_ainfo.shortname = "cc";
342 arg_ainfo.longname = "collections to search";
343 arg_ainfo.multiplechar = true;
344 arg_ainfo.multiplevalue = true;
345 arg_ainfo.defaultstatus = cgiarginfo::weak;
346 arg_ainfo.argdefault = "";
347 arg_ainfo.savedarginfo = cgiarginfo::must;
348 argsinfo.addarginfo (NULL, arg_ainfo);
349
350}
351
352void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
353 action::configure (key, cfgline);
354}
355
356bool queryaction::init (ostream &logout) {
357 return action::init (logout);
358}
359
360bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
361 ostream &logout) {
362
363 // check t argument
364 int arg_t = args.getintarg("t");
365 if (arg_t != 0 && arg_t != 1) {
366 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
367 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
368 if (tinfo != NULL) args["t"] = tinfo->argdefault;
369 }
370
371 // check k argument
372 int arg_k = args.getintarg("k");
373 if (arg_k != 0 && arg_k != 1) {
374 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
375 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
376 if (kinfo != NULL) args["k"] = kinfo->argdefault;
377 }
378
379 // check s argument
380 int arg_s = args.getintarg("s");
381 if (arg_s != 0 && arg_s != 1) {
382 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
383 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
384 if (sinfo != NULL) args["s"] = sinfo->argdefault;
385 }
386
387 // check m argument
388 int arg_m = args.getintarg("m");
389 if (arg_m < -1) {
390 logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
391 cgiarginfo *minfo = argsinfo.getarginfo ("m");
392 if (minfo != NULL) args["m"] = minfo->argdefault;
393 }
394
395 // check o argument
396 int arg_o = args.getintarg("o");
397 if (arg_o < -1) {
398 logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
399 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
400 if (oinfo != NULL) args["o"] = oinfo->argdefault;
401 }
402
403 // check r argument
404 int arg_r = args.getintarg("r");
405 if (arg_r < 1) {
406 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
407 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
408 if (rinfo != NULL) args["r"] = rinfo->argdefault;
409 }
410
411 return true;
412}
413
414void queryaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
415 response_t &response, text_t &response_data,
416 ostream &/*logout*/) {
417 response = content;
418 response_data = "text/html";
419}
420
421void queryaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
422 recptprotolistclass * /*protos*/,
423 ostream &/*logout*/) {
424
425 // define_internal_macros sets the following macros:
426
427 // _quotedquery_ the part of the query string that was quoted for post-processing
428
429
430
431 // The following macros are set later (in define_query_macros) as they can't be set until
432 // the query has been done.
433
434 // _freqmsg_ the term frequency string
435
436 // _resultline_ the "x documents matched the query" string
437
438 // _prevfirst_ these are used when setting up the links to previous/next
439 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
440 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
441 // _nextlast_
442 // _thisfirst_
443 // _thislast_
444
445
446 // get the quoted bits of the query string and set _quotedquery_
447 text_tarray phrases;
448 get_phrases (args["q"], phrases);
449 num_phrases = phrases.size();
450 text_tarray::const_iterator phere = phrases.begin();
451 text_tarray::const_iterator pend = phrases.end();
452 bool first = true;
453 text_t quotedquery;
454 while (phere != pend) {
455 if (!first)
456 if ((phere +1) == pend) quotedquery += " and ";
457 else quotedquery += ", ";
458
459 quotedquery += "\"" + *phere + "\"";
460 first = false;
461 phere ++;
462 }
463 if (args.getintarg("s")) quotedquery += "_textstemon_";
464 disp.setmacro ("quotedquery", "query", quotedquery);
465}
466
467// sets the selection box macros _hselection_, _jselection_, and _nselection_.
468void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
469 const FilterOption_t &option, displayclass &disp) {
470
471 if (option.validValues.empty()) return;
472 else if (option.validValues.size() == 1) {
473 disp.setmacro (macroname + "selection", "Global", "_" + option.defaultValue + "_");
474 return;
475 }
476 if (option.validValues.size() < 2) return;
477
478 text_t macrovalue = "<select name=\"" + macroname + "\">\n";
479
480 if (current_value.empty()) current_value = option.defaultValue;
481
482 text_tarray::const_iterator thisvalue = option.validValues.begin();
483 text_tarray::const_iterator endvalue = option.validValues.end();
484
485 while (thisvalue != endvalue) {
486 macrovalue += "<option value=\"" + *thisvalue + "\"";
487 if (*thisvalue == current_value)
488 macrovalue += " selected";
489 macrovalue += ">_" + *thisvalue + "_\n";
490 thisvalue ++;
491 }
492 macrovalue += "</select>\n";
493 disp.setmacro (macroname + "selection", "Global", macrovalue);
494}
495
496void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args,
497 recptprotolistclass *protos, ostream &logout) {
498
499 // define_external_macros sets the following macros:
500
501 // some or all of these may not be required to be set
502 // _hselection_, _h2selection_ the selection box for the main part of the index
503 // _jselection_, _j2selection_ the selection box for the subcollection part of the index
504 // _nselection_, _n2selection_ the selection box for the language part of the index
505 // _cq2selection the selection box for combining two queries
506
507
508 // can't do anything if collectproto is null (i.e. no collection was specified)
509 recptproto *collectproto = protos->getrecptproto (args["c"], logout);
510 if (collectproto == NULL) return;
511
512 comerror_t err;
513 InfoFilterOptionsResponse_t response;
514 InfoFilterOptionsRequest_t request;
515 request.filterName = "QueryFilter";
516
517 collectproto->get_filteroptions (args["c"], request, response, err, logout);
518 if (err == noError) {
519
520 FilterOption_tmap::const_iterator it;
521 FilterOption_tmap::const_iterator end = response.filterOptions.end();
522
523 // _hselection_ and _h2selection_ (Index)
524 it = response.filterOptions.find ("Index");
525 if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
526 if (it != end) set_option_macro ("h2", args["h2"], (*it).second, disp);
527
528 // _jselection_ and _j2selection_ (Subcollection)
529 it = response.filterOptions.find ("Subcollection");
530 if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
531 if (it != end) set_option_macro ("j2", args["j2"], (*it).second, disp);
532
533 // _nselection_ and _n2selection_ (Language)
534 it = response.filterOptions.find ("Language");
535 if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
536 if (it != end) set_option_macro ("n2", args["n2"], (*it).second, disp);
537
538 // _cq2selection_ (CombineQuery)
539 it = response.filterOptions.find ("CombineQuery");
540 if (it != end) set_option_macro ("cq2", args["cq2"], (*it).second, disp);
541 }
542}
543
544bool queryaction::do_action (cgiargsclass &args, recptprotolistclass *protos,
545 browsermapclass *browsers, displayclass &disp,
546 outconvertclass &outconvert, ostream &textout,
547 ostream &logout) {
548
549 if (args["ccs"] == "1") {
550 if (!args["cc"].empty()) {
551 // query the selected collections
552 text_t::const_iterator b = args["cc"].begin();
553 text_t::const_iterator e = args["cc"].end();
554 if (findchar (b, e, ',') != e) {
555 if (!search_multiple_collections (args, protos, browsers, disp, outconvert,
556 textout, logout)) return false;
557 return true;
558 } else {
559 if (!search_single_collection (args, args["cc"], protos, browsers, disp,
560 outconvert, textout, logout)) return false;
561 return true;
562 }
563 }
564 }
565
566 // simply query the current collection
567 if (!search_single_collection (args, args["c"], protos, browsers, disp,
568 outconvert, textout, logout)) return false;
569 return true;
570}
571
572bool queryaction::search_multiple_collections (cgiargsclass &args, recptprotolistclass *protos,
573 browsermapclass *browsers, displayclass &disp,
574 outconvertclass &outconvert, ostream &textout,
575 ostream &logout) {
576
577 text_tarray collections;
578
579 text_t arg_cc = args["cc"];
580 decode_cgi_arg (arg_cc);
581 splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
582
583 if (collections.empty()) {
584 logout << "queryaction::search_multiple_collections: No collections "
585 << "set for doing multiple query - will search current collection\n";
586 textout << outconvert << disp << "_query:textwarningnocollections_\n";
587 return search_single_collection (args, args["c"], protos, browsers, disp,
588 outconvert, textout, logout);
589 }
590
591 // queryaction uses "VList" browser to display results,
592 // a queries clasification is "Search"
593 text_t browsertype = "VList";
594 text_t classification = "Search";
595
596 QueryResult_tset results;
597 map<text_t, colinfo_t, lttext_t> colinfomap;
598
599 ColInfoResponse_t cinfo;
600 comerror_t err;
601 FilterRequest_t request;
602 FilterResponse_t response;
603 request.filterResultOptions = FROID | FRmetadata | FRtermFreq | FRranking;
604 text_t formattedstring = args["q"];
605 text_t freqmsg = "_textfreqmsg1_";
606 int numdocs = 0;
607 isapprox isApprox = Exact;
608
609 format_querystring (formattedstring, args.getintarg("b"));
610 set_queryfilter_options (request, formattedstring, args);
611
612 // need to retrieve maxdocs matches for each collection
613 // (will eventually want to tidy this up, do so caching etc.)
614 OptionValue_t option;
615 option.name = "StartResults";
616 option.value = "1";
617 request.filterOptions.push_back (option);
618
619 option.name = "EndResults";
620 option.value = args["m"];
621 request.filterOptions.push_back (option);
622
623 text_tarray::iterator col_here = collections.begin();
624 text_tarray::iterator col_end = collections.end();
625
626 map<text_t, int, lttext_t> termfreqs;
627 while (col_here != col_end) {
628
629 request.fields.erase (request.fields.begin(), request.fields.end());
630 request.getParents = false;
631
632 recptproto *collectproto = protos->getrecptproto (*col_here, logout);
633 if (collectproto == NULL) {
634 logout << outconvert << "queryaction::search_multiple_collections: " << *col_here
635 << " collection has a NULL collectproto, ignoring\n";
636 col_here ++;
637 continue;
638 }
639 collectproto->get_collectinfo (*col_here, cinfo, err, logout);
640
641 browserclass *bptr = browsers->getbrowser (browsertype);
642
643 // get the formatstring if there is one
644 text_t formatstring;
645 if (!get_formatstring (classification, browsertype,
646 cinfo.format, formatstring))
647 formatstring = bptr->get_default_formatstring();
648
649 bptr->load_metadata_defaults (request.fields);
650
651 format_t *formatlistptr = new format_t();
652 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
653
654 colinfo_t thiscolinfo;
655 thiscolinfo.formatlistptr = formatlistptr;
656 thiscolinfo.browserptr = bptr;
657 colinfomap[*col_here] = thiscolinfo;
658
659 // do the query
660 collectproto->filter (*col_here, request, response, err, logout);
661 if (err != noError) {
662 outconvertclass text_t2ascii;
663 logout << text_t2ascii
664 << "queryaction::search_multiple_collections: call to QueryFilter failed "
665 << "for " << *col_here << " collection (" << get_comerror_string (err) << ")\n";
666 return false;
667 }
668
669 if (isApprox == Exact)
670 isApprox = response.isApprox;
671 else if (isApprox == MoreThan)
672 if (response.isApprox == Approximate)
673 isApprox = response.isApprox;
674
675 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
676 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
677 while (this_term != end_term) {
678 termfreqs[(*this_term).term] += (*this_term).freq;
679 if ((col_here+1) == col_end) {
680 freqmsg += (*this_term).term + ": " + termfreqs[(*this_term).term];
681 if ((this_term+1) != end_term) freqmsg += ", ";
682 }
683 this_term ++;
684 }
685
686 if (response.numDocs > 0) {
687 numdocs += response.numDocs;
688
689 QueryResult_t thisresult;
690 thisresult.collection = *col_here;
691 ResultDocInfo_tarray::iterator doc_here = response.docInfo.begin();
692 ResultDocInfo_tarray::iterator doc_end = response.docInfo.end();
693 while (doc_here != doc_end) {
694 thisresult.doc = *doc_here;
695 results.insert (thisresult);
696 doc_here ++;
697 }
698 }
699 col_here ++;
700 }
701
702 disp.setmacro ("freqmsg", "query", freqmsg);
703
704 text_t resline;
705 if (num_phrases > 0) isApprox = Exact;
706 if (isApprox == Approximate) resline = "_textapprox_";
707 else if (isApprox == MoreThan) resline = "_textmorethan_";
708
709 if (numdocs == 0) resline = "_textnodocs_";
710 else if (numdocs == 1) resline += "_text1doc_";
711 else resline += text_t(numdocs) + " _textlotsdocs_";
712 disp.setmacro("resultline", "query", resline);
713
714 QueryResult_tset::iterator res_here = results.begin();
715 QueryResult_tset::iterator res_end = results.end();
716 text_tset metadata; // empty !!
717 bool getParents = false; // don't care !!
718 recptproto *collectproto = NULL;
719 bool use_table;
720 ResultDocInfo_t thisdoc;
721 format_t *formatlistptr = NULL;
722 browserclass *browserptr = NULL;
723
724 int maxdocs = args.getintarg("m");
725 int firstdoc = args.getintarg("r");
726 int hitsperpage = args.getintarg("o");
727 if (numdocs > maxdocs) numdocs = maxdocs;
728 if (hitsperpage == -1) hitsperpage = numdocs;
729
730 // set up _thisfirst_ and _thislast_ macros
731 disp.setmacro ("thisfirst", "query", firstdoc);
732 int thislast = firstdoc + (hitsperpage - 1);
733 if (thislast > numdocs) thislast = numdocs;
734 disp.setmacro ("thislast", "query", thislast);
735
736 // set up _prevfirst_ and _prevlast_ macros
737 if (firstdoc > 1) {
738 disp.setmacro ("prevlast", "query", firstdoc - 1);
739 int prevfirst = firstdoc - hitsperpage;
740 if (prevfirst < 1) prevfirst = 1;
741 disp.setmacro ("prevfirst", "query", prevfirst);
742 }
743
744 // set up _nextfirst_ and _nextlast_ macros
745 if (thislast < numdocs) {
746 disp.setmacro ("nextfirst", "query", thislast + 1);
747 int nextlast = thislast + hitsperpage;
748 if (nextlast > numdocs) nextlast = numdocs;
749 disp.setmacro ("nextlast", "query", nextlast);
750 }
751
752 textout << outconvert << disp << "_query:header_\n"
753 << "_query:content_";
754
755 int count = 1;
756
757 // output results
758 while (res_here != res_end) {
759 if (count < firstdoc) {count ++; res_here ++; continue;}
760 if (count > thislast) break;
761 formatlistptr = colinfomap[(*res_here).collection].formatlistptr;
762 browserptr = colinfomap[(*res_here).collection].browserptr;
763 thisdoc = (*res_here).doc;
764 use_table = is_table_content (formatlistptr);
765 browserptr->output_section_group (thisdoc, args, (*res_here).collection, 0,
766 formatlistptr, use_table, metadata, getParents,
767 collectproto, disp, outconvert, textout, logout);
768 // textout << outconvert << "(ranking: " << (*res_here).doc.ranking << ")\n";
769 res_here ++;
770 count ++;
771 }
772
773 textout << outconvert << disp << "_query:footer_";
774
775 // clean up the format_t pointers
776 map<text_t, colinfo_t, lttext_t>::iterator here = colinfomap.begin();
777 map<text_t, colinfo_t, lttext_t>::iterator end = colinfomap.end();
778 while (here != end) {
779 delete ((*here).second.formatlistptr);
780 here ++;
781 }
782 return true;
783}
784
785bool queryaction::search_single_collection (cgiargsclass &args, const text_t &collection,
786 recptprotolistclass *protos, browsermapclass *browsers,
787 displayclass &disp, outconvertclass &outconvert,
788 ostream &textout, ostream &logout) {
789
790 recptproto *collectproto = protos->getrecptproto (collection, logout);
791 if (collectproto == NULL) {
792 logout << outconvert << "queryaction::search_single_collection: " << collection
793 << " collection has a NULL collectproto\n";
794 return false;
795 }
796
797 // queryaction uses "VList" browser to display results,
798 // a queries clasification is "Search"
799 text_t browsertype = "VList";
800 text_t classification = "Search";
801
802 ColInfoResponse_t cinfo;
803 comerror_t err;
804 collectproto->get_collectinfo (collection, cinfo, err, logout);
805
806 browserclass *bptr = browsers->getbrowser (browsertype);
807
808 // get the formatstring if there is one
809 text_t formatstring;
810 if (!get_formatstring (classification, browsertype,
811 cinfo.format, formatstring))
812 formatstring = bptr->get_default_formatstring();
813
814 FilterRequest_t request;
815 FilterResponse_t response;
816 bptr->set_filter_options (request, args);
817 bptr->load_metadata_defaults (request.fields);
818
819 format_t *formatlistptr = new format_t();
820 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
821
822 // do the query
823 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
824 text_t formattedstring = args["q"];
825 format_querystring (formattedstring, args.getintarg("b"));
826 set_queryfilter_options (request, formattedstring, args);
827 collectproto->filter (collection, request, response, err, logout);
828 if (err != noError) {
829 outconvertclass text_t2ascii;
830 logout << text_t2ascii
831 << "queryaction::search_single_collections: call to QueryFilter failed "
832 << "for " << collection << " collection (" << get_comerror_string (err) << ")\n";
833 return false;
834 }
835
836 define_query_macros (args, disp, response);
837
838 textout << outconvert << disp << "_query:header_\n"
839 << "_query:content_";
840
841 // output the results
842 bool use_table = is_table_content (formatlistptr);
843 bptr->output_section_group (response, args, collection, 0, formatlistptr,
844 use_table, request.fields, request.getParents,
845 collectproto, disp, outconvert, textout, logout);
846
847
848 textout << outconvert << disp << "_query:footer_";
849
850 delete (formatlistptr);
851
852 return true;
853}
854
855// define_query_macros sets the macros that couldn't be set until the
856// query had been done. Those macros are _freqmsg_, _quotedquery_,
857// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
858// _thisfirst_, and _thislast_
859void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
860 const FilterResponse_t &response) {
861 // set up _freqmsg_ and _quotedquery_ macros
862 text_t freqmsg = "_textfreqmsg1_";
863 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
864 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
865 while (this_term != end_term) {
866 freqmsg += (*this_term).term + ": " + (*this_term).freq;
867 if ((this_term + 1) != end_term)
868 freqmsg += ", ";
869 this_term ++;
870 }
871
872 disp.setmacro ("freqmsg", "query", freqmsg);
873
874
875 // set up _resultline_ macro
876 text_t resline;
877 int maxdocs = args.getintarg("m");
878 int numdocs = response.numDocs;
879 if (maxdocs == -1) maxdocs = response.numDocs;
880 isapprox isApprox = response.isApprox;
881
882 // if there were phrases (post-processing) we're not going to include
883 // those documents that didn't match
884 if (num_phrases > 0) isApprox = Exact;
885
886 if (isApprox == Approximate) resline = "_textapprox_";
887 else if (isApprox == MoreThan) resline = "_textmorethan_";
888
889 if (numdocs == 0) resline = "_textnodocs_";
890 else if (numdocs == 1) resline += "_text1doc_";
891 else resline += text_t(numdocs) + " _textlotsdocs_";
892
893 disp.setmacro("resultline", "query", resline);
894
895 int firstdoc = args.getintarg("r");
896 int hitsperpage = args.getintarg("o");
897 if (hitsperpage == -1) hitsperpage = numdocs;
898
899 // set up _thisfirst_ and _thislast_ macros
900 disp.setmacro ("thisfirst", "query", firstdoc);
901 int thislast = firstdoc + (hitsperpage - 1);
902 if (thislast > numdocs) thislast = numdocs;
903 disp.setmacro ("thislast", "query", thislast);
904
905 // set up _prevfirst_ and _prevlast_ macros
906 if (firstdoc > 1) {
907 disp.setmacro ("prevlast", "query", firstdoc - 1);
908 int prevfirst = firstdoc - hitsperpage;
909 if (prevfirst < 1) prevfirst = 1;
910 disp.setmacro ("prevfirst", "query", prevfirst);
911 }
912
913 // set up _nextfirst_ and _nextlast_ macros
914 if (thislast < numdocs) {
915 disp.setmacro ("nextfirst", "query", thislast + 1);
916 int nextlast = thislast + hitsperpage;
917 if (nextlast > numdocs) nextlast = numdocs;
918 disp.setmacro ("nextlast", "query", nextlast);
919 }
920}
921
922
923
Note: See TracBrowser for help on using the repository browser.