Changeset 24856
- Timestamp:
- 2011-12-06T11:03:45+13:00 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java
r24394 r24856 18 18 package org.greenstone.gsdl3.service; 19 19 20 21 20 // Greenstone classes 22 21 import org.greenstone.gsdl3.util.*; … … 24 23 // XML classes 25 24 import org.w3c.dom.Document; 26 import org.w3c.dom.Element; 25 import org.w3c.dom.Element; 27 26 import org.w3c.dom.NodeList; 28 27 … … 38 37 import org.apache.log4j.*; 39 38 40 41 abstract public class AbstractGS2FieldSearch 42 extends AbstractGS2TextSearch 39 abstract public class AbstractGS2FieldSearch extends AbstractGS2TextSearch 43 40 { 44 41 45 // extra services offered by mgpp collections 46 protected static final String FIELD_QUERY_SERVICE = "FieldQuery"; 47 protected static final String ADVANCED_FIELD_QUERY_SERVICE = "AdvancedFieldQuery"; 48 49 // extra parameters used 50 protected static final String LEVEL_PARAM = "level"; 51 protected static final String RANK_PARAM = "sortBy"; 52 protected static final String RANK_PARAM_RANK = "1"; 53 protected static final String RANK_PARAM_NONE = "0"; 54 protected static final String SIMPLE_FIELD_PARAM = "simpleField"; 55 protected static final String ADVANCED_FIELD_PARAM = "complexField"; 56 57 // more params for field query 58 protected static final String FIELD_QUERY_PARAM = "fqv"; 59 protected static final String FIELD_STEM_PARAM = "fqs"; 60 protected static final String FIELD_CASE_PARAM = "fqc"; 61 protected static final String FIELD_ACCENT_PARAM="fqa"; 62 protected static final String FIELD_FIELD_PARAM = "fqf"; 63 protected static final String FIELD_COMBINE_PARAM = "fqk"; 64 protected static final String FIELD_COMBINE_PARAM_AND = "0"; 65 protected static final String FIELD_COMBINE_PARAM_OR = "1"; 66 protected static final String FIELD_COMBINE_PARAM_NOT = "2"; 67 68 // some stuff for config files 69 protected static final String SEARCH_TYPE_ELEM = "searchType"; 70 protected static final String SEARCH_TYPE_PLAIN = "plain"; 71 protected static final String SEARCH_TYPE_SIMPLE_FORM = "simpleform"; 72 protected static final String SEARCH_TYPE_ADVANCED_FORM = "advancedform"; 73 74 protected static final String DEFAULT_LEVEL_ELEM = "defaultLevel"; 75 protected static final String DEFAULT_DB_LEVEL_ELEM = "defaultDBLevel"; 76 protected static final String LEVEL_ELEM = "level"; 77 protected static final String FIELD_ATT = "field"; 78 79 80 protected static final int TEXT_QUERY = 0; 81 protected static final int SIMPLE_QUERY = 1; 82 protected static final int ADVANCED_QUERY = 2; 83 84 protected String AND_OPERATOR = "&"; 85 protected String OR_OPERATOR = "|"; 86 protected String NOT_OPERATOR = "!"; 87 88 // the default level for searching 89 protected String default_level=null; 90 // default level for collection db 91 protected String default_db_level = null; 92 // which search services will we offer?? 93 protected boolean plain_search = false; 94 protected boolean simple_form_search = false; 95 protected boolean advanced_form_search = false; 96 97 98 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2FieldSearch.class.getName()); 99 100 /** constructor */ 101 public AbstractGS2FieldSearch() 102 { 103 } 104 105 public void cleanUp() { 106 super.cleanUp(); 107 } 108 109 /** configure this service */ 110 public boolean configure(Element info, Element extra_info) 111 { 112 if (!super.configure(info, extra_info)){ 113 return false; 114 } 115 116 // Get the default level out of <defaultLevel> (buildConfig.xml) 117 Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_LEVEL_ELEM); 118 if (def != null) { 119 this.default_level = def.getAttribute(GSXML.SHORTNAME_ATT); 120 } 121 if (this.default_level == null || this.default_level.equals("")) { 122 logger.error("default level not specified!, assuming Doc"); 123 this.default_level = "Doc"; 124 } 125 126 // Get the default DB level 127 def = (Element) GSXML.getChildByTagName(info, DEFAULT_DB_LEVEL_ELEM); 128 if (def != null) { 129 this.default_db_level = def.getAttribute(GSXML.SHORTNAME_ATT); 130 } 131 if (this.default_db_level == null || this.default_db_level.equals("")) { 132 logger.error("default database level (defaultDBLevel) not specified!, assuming Sec"); 133 this.default_db_level = "Sec"; 134 } 135 136 // get stuff from from extra info (which is collectionConfig.xml) 137 if (extra_info !=null) { 138 139 // the search element 140 Element config_search = (Element)GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM); 141 142 NodeList search_types = config_search.getElementsByTagName(SEARCH_TYPE_ELEM); 143 if (search_types == null) { 144 // none specified, assume plain only 145 this.plain_search = true; 146 } 147 else { 148 for (int i=0; i<search_types.getLength(); i++) { 149 Element t = (Element)search_types.item(i); 150 String type_name = t.getAttribute(GSXML.NAME_ATT); 151 if (type_name.equals(SEARCH_TYPE_PLAIN)) { 152 this.plain_search = true; 153 } else if (type_name.equals(SEARCH_TYPE_SIMPLE_FORM)) { 154 this.simple_form_search = true; 155 } else if (type_name.equals(SEARCH_TYPE_ADVANCED_FORM)) { 156 this.advanced_form_search = true; 157 } 158 } 159 } 160 161 // AbstractGS2TextSearch has set up the TextQuery service, but we may not want it 162 if (!this.plain_search) { 163 // need to remove the TextQuery service 164 Element tq_service = GSXML.getNamedElement(short_service_info, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, QUERY_SERVICE); 165 short_service_info.removeChild(tq_service); 166 167 } 168 169 Document owner = info.getOwnerDocument(); 170 171 NodeList levels = info.getElementsByTagName(GSXML.LEVEL_ELEM); 172 173 174 for (int i=0; i<levels.getLength();i++) { 175 Element lev = (Element)levels.item(i); 176 String name = lev.getAttribute(GSXML.NAME_ATT); 177 Element node_extra = GSXML.getNamedElement(config_search, 178 GSXML.LEVEL_ELEM, 179 GSXML.NAME_ATT, 180 name); 181 if (node_extra == null) { 182 logger.error("haven't found extra info for level named "+name); 183 continue; 184 } 185 186 // get the display elements if any - displayName 187 NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM); 188 if (display_names !=null) { 189 for (int j=0; j<display_names.getLength(); j++) { 190 Element e = (Element)display_names.item(j); 191 lev.appendChild(owner.importNode(e, true)); 192 } 193 } 194 } // for each level 195 } else { 196 // for soem reason we don't have the collectionConfig file. assume plain only 197 this.plain_search = true; 198 } 199 200 201 // the format info is the same for all services 202 Element format_info = (Element)format_info_map.get(QUERY_SERVICE); 203 204 // set up the extra services which are available for this collection 205 if (this.simple_form_search) { 206 // set up short_service_info_ - for now just has id and type - name will be added in on the fly 207 Element fq_service = this.doc.createElement(GSXML.SERVICE_ELEM); 208 fq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY); 209 fq_service.setAttribute(GSXML.NAME_ATT, FIELD_QUERY_SERVICE); 210 this.short_service_info.appendChild(fq_service); 211 212 if (format_info != null) { 213 this.format_info_map.put(FIELD_QUERY_SERVICE, format_info); 214 } 215 } 216 217 if (this.advanced_form_search) { 218 Element afq_service = this.doc.createElement(GSXML.SERVICE_ELEM); 219 afq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY); 220 afq_service.setAttribute(GSXML.NAME_ATT, ADVANCED_FIELD_QUERY_SERVICE); 221 this.short_service_info.appendChild(afq_service); 222 223 if (format_info != null) { 224 this.format_info_map.put(ADVANCED_FIELD_QUERY_SERVICE, format_info); 225 } 226 } 227 228 return true; 229 } 230 231 232 protected Element getServiceDescription(String service_id, String lang, String subset) { 233 // should we check that the service is actually on offer? presumably we wont get asked for services that we haven't advertised previously. 234 235 if (!service_id.equals(FIELD_QUERY_SERVICE) && !service_id.equals(ADVANCED_FIELD_QUERY_SERVICE)) { 236 return super.getServiceDescription(service_id, lang, subset); 237 } 238 239 240 Element service = this.doc.createElement(GSXML.SERVICE_ELEM); 241 service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY); 242 service.setAttribute(GSXML.NAME_ATT, service_id); 243 if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) { 244 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(service_id+".name", lang))); 245 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service_id+".submit", lang))); 246 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(service_id+".description", lang))); 247 248 } 249 if (subset == null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) { 250 Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER); 251 service.appendChild(param_list); 252 if (service_id.equals(FIELD_QUERY_SERVICE)) { 253 254 addCustomQueryParams(param_list, lang); 255 createParameter(MAXDOCS_PARAM, param_list, lang); 256 if (!default_index_subcollection.equals("")){ 257 createParameter(INDEX_SUBCOLLECTION_PARAM,param_list, lang); 258 } 259 if (!default_index_language.equals("")){ 260 createParameter(INDEX_LANGUAGE_PARAM,param_list, lang); 261 } 262 // create a multi param for the fields etc 263 // text box, field 264 Element multiparam = null; 265 Element param=null; 266 multiparam = GSXML.createParameterDescription(this.doc, SIMPLE_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null); 267 multiparam.setAttribute("occurs", "4"); 268 param_list.appendChild(multiparam); 269 270 // the components 271 272 createParameter(FIELD_QUERY_PARAM, multiparam, lang); 273 createParameter(FIELD_FIELD_PARAM, multiparam, lang); 274 275 } else { 276 createParameter(LEVEL_PARAM, param_list, lang); 277 createParameter(RANK_PARAM, param_list, lang); 278 createParameter(MAXDOCS_PARAM, param_list, lang); 279 if (!default_index_subcollection.equals("")){ 280 createParameter(INDEX_SUBCOLLECTION_PARAM,param_list, lang); 281 } 282 if (!default_index_language.equals("")){ 283 createParameter(INDEX_LANGUAGE_PARAM,param_list, lang); 284 } 285 286 // create a multi param for the fields etc 287 // text box, stem, case, field 288 289 Element multiparam = null; 290 Element param=null; 291 292 multiparam = GSXML.createParameterDescription(this.doc, ADVANCED_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null); 293 multiparam.setAttribute("occurs", "4"); 294 param_list.appendChild(multiparam); 295 296 createParameter(FIELD_COMBINE_PARAM, multiparam, lang); 297 createParameter(FIELD_QUERY_PARAM, multiparam, lang); 298 if (this.does_case) { 299 createParameter(FIELD_CASE_PARAM, multiparam, lang); 300 } 301 if (this.does_stem) { 302 createParameter(FIELD_STEM_PARAM, multiparam, lang); 303 } 304 if (this.does_accent) { 305 createParameter(FIELD_ACCENT_PARAM, multiparam, lang); 306 } 307 createParameter(FIELD_FIELD_PARAM, multiparam, lang); 308 309 } 310 } 311 return service; 312 313 } 314 315 /** add in the level params to TextQuery */ 316 protected void addCustomQueryParams(Element param_list, String lang) 317 { 318 createParameter(LEVEL_PARAM, param_list, lang); 319 super.addCustomQueryParams(param_list, lang); 320 } 321 322 /** create a param and add to the list */ 323 protected void createParameter(String name, Element param_list, String lang) 324 { 325 Element param = null; 326 if (name.equals(LEVEL_PARAM)) { 327 ArrayList level_ids = new ArrayList(); 328 ArrayList level_names = new ArrayList(); 329 getLevelData(level_ids, level_names, lang); 330 if (level_ids.size()>1) { 331 // the first one is the default 332 //param = GSXML.createParameterDescription2(this.doc, LEVEL_PARAM, getTextString("param."+LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)level_ids.get(0), level_ids, level_names); 333 param = GSXML.createParameterDescription2(this.doc, LEVEL_PARAM, getTextString("param."+LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, this.default_level, level_ids, level_names); 334 } else { 335 // we need to set the level, but hidden, in case there is an invalid level saved 336 //param = GSXML.createParameterDescription(this.doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, (String)level_ids.get(0), null, null); 337 param = GSXML.createParameterDescription(this.doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, this.default_level, null, null); 338 } 339 } else if (name.equals(RANK_PARAM)) { 340 String [] vals1 = {RANK_PARAM_RANK, RANK_PARAM_NONE }; 341 String [] vals1_texts = { getTextString("param."+RANK_PARAM+"."+RANK_PARAM_RANK, lang), getTextString("param."+RANK_PARAM+"."+RANK_PARAM_NONE, lang)}; 342 343 param = GSXML.createParameterDescription(this.doc, RANK_PARAM, getTextString("param."+RANK_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, RANK_PARAM_RANK, vals1, vals1_texts ); 344 345 } else if (name.equals(FIELD_QUERY_PARAM)) { 346 param = GSXML.createParameterDescription(this.doc, FIELD_QUERY_PARAM, getTextString("param."+FIELD_QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null); 347 348 349 } else if (name.equals(FIELD_CASE_PARAM) || name.equals(FIELD_STEM_PARAM) || name.equals(FIELD_ACCENT_PARAM)) { 350 String[] bool_ops = {"0", "1"}; 351 String[] bool_texts = {getTextString("param.boolean.off", lang, "AbstractTextSearch"),getTextString("param.boolean.on", lang, "AbstractTextSearch")}; 352 param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_BOOLEAN, BOOLEAN_PARAM_ON, bool_ops, bool_texts); 353 354 } else if (name.equals(FIELD_FIELD_PARAM)) { 355 ArrayList fields = new ArrayList(); 356 ArrayList field_names = new ArrayList(); 357 getIndexData(fields, field_names, lang); 358 // the field list - read from config file 359 360 // Fix for http://trac.greenstone.org/ticket/245 "java crash, index out of bounds" 361 // org.greenstone.gsdl3.service.AbstractGS2FieldSearch.createParameter(AbstractGS2FieldSearch.java:362) 362 // Changed from: 363 // param = GSXML.createParameterDescription2(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)fields.get(0), fields, field_names ); 364 String default_value = (fields.size() > 0) ? (String)fields.get(0) : null; 365 // don't want to access element 0 if fields.size()==0, and 366 // GSXML.createParameterDescription2 checks for default_value==null condition 367 param = GSXML.createParameterDescription2(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, default_value, fields, field_names ); 368 369 } else if (name.equals(FIELD_COMBINE_PARAM)) { 370 371 String []vals = {FIELD_COMBINE_PARAM_AND, FIELD_COMBINE_PARAM_OR, FIELD_COMBINE_PARAM_NOT}; 372 String []val_texts = {getTextString("param."+FIELD_COMBINE_PARAM+"."+FIELD_COMBINE_PARAM_AND, lang), getTextString("param."+FIELD_COMBINE_PARAM+"."+FIELD_COMBINE_PARAM_OR, lang), getTextString("param."+FIELD_COMBINE_PARAM+"."+FIELD_COMBINE_PARAM_NOT, lang)}; 373 374 375 param = GSXML.createParameterDescription(this.doc, FIELD_COMBINE_PARAM, "", GSXML.PARAM_TYPE_ENUM_SINGLE, FIELD_COMBINE_PARAM_AND, vals, val_texts); 376 param.setAttribute(GSXML.PARAM_IGNORE_POS_ATT, "0"); 377 } 378 379 if (param != null) { 380 param_list.appendChild(param); 381 } else { 382 super.createParameter(name, param_list, lang); 383 } 384 } 385 386 // should cache some of this 387 protected void getLevelData(ArrayList level_ids, ArrayList level_names, String lang) 388 { 389 Element level_list = (Element)GSXML.getChildByTagName(this.config_info, LEVEL_ELEM+GSXML.LIST_MODIFIER); 390 NodeList levels = level_list.getElementsByTagName(LEVEL_ELEM); 391 for (int i=0; i<levels.getLength(); i++) { 392 Element level = (Element)levels.item(i); 393 String shortname = level.getAttribute(GSXML.SHORTNAME_ATT); 394 if (shortname.equals("")) { 395 continue; 396 } 397 level_ids.add(shortname); 398 String display_name = GSXML.getDisplayText(level, GSXML.DISPLAY_TEXT_NAME, lang, "en"); 399 if (display_name.equals("")) { 400 // we'll use the name, and the dictionary 401 display_name = level.getAttribute(GSXML.NAME_ATT); 402 if (display_name.equals("")) { 403 display_name = shortname; 404 } else { 405 display_name = getTextString("level."+display_name, lang); 406 } 407 } 408 level_names.add(display_name); 409 } 410 } 411 412 // the following three functions are needed so the base class can 413 // call the process+SERVICE_NAME methods 414 /** process a text query */ 415 protected Element processTextQuery(Element request) { 416 return processAnyQuery(request, TEXT_QUERY); 417 } 418 419 /** process a field query */ 420 protected Element processFieldQuery(Element request) { 421 return processAnyQuery(request, SIMPLE_QUERY); 422 } 423 424 /** process an advanced field query */ 425 protected Element processAdvancedFieldQuery(Element request) { 426 return processAnyQuery(request, ADVANCED_QUERY); 427 } 428 429 /** process a query */ 430 protected Element processAnyQuery(Element request, int query_type) 431 { 432 String service_name=null; 433 String empty_query_test_param=null; 434 // set up the type specific bits 435 switch (query_type) { 436 case TEXT_QUERY: 437 service_name = QUERY_SERVICE; 438 empty_query_test_param = QUERY_PARAM; 439 break; 440 case SIMPLE_QUERY: 441 service_name = FIELD_QUERY_SERVICE; 442 empty_query_test_param = FIELD_QUERY_PARAM; 443 break; 444 case ADVANCED_QUERY: 445 service_name = ADVANCED_FIELD_QUERY_SERVICE; 446 empty_query_test_param = FIELD_QUERY_PARAM; 447 break; 448 default: 449 // should never get here 450 logger.error("wrong query type!!"); 451 return null; 452 } 453 454 // Create a new (empty) result message 455 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM); 456 result.setAttribute(GSXML.FROM_ATT, service_name); 457 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS); 458 459 // Get the parameters of the request 460 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER); 461 if (param_list == null) { 462 logger.error("TextQuery request had no paramList."); 463 return result; // Return the empty result 464 } 465 466 // Process the request parameters 467 HashMap params = GSXML.extractParams(param_list, false); 468 469 // Make sure a query has been specified 470 String query = (String) params.get(empty_query_test_param); 471 if (query == null || query.equals("")) { 472 return result; // Return the empty result 473 } 474 475 // If a field hasn't been specified, use the default - for textQuery 476 String field = (String) params.get(INDEX_PARAM); 477 if (field == null) { 478 field = default_index; 479 } 480 481 // set up the appropriate query system 482 if (!setUpQueryer(params)) { 483 return result; 484 } 485 486 // if field search, create the query string 487 switch (query_type) { 488 case TEXT_QUERY: 489 query = addFieldInfo(query, field); 490 break; 491 case SIMPLE_QUERY: 492 query = parseFieldQueryParams(params); 493 break; 494 case ADVANCED_QUERY: 495 query = parseAdvancedFieldQueryParams(params); 496 break; 497 } 498 499 // run the query 500 Object query_result = runQuery(query); 501 502 // build up the response 503 504 // Create a metadata list to store information about the query results 505 // should we be using metadataList? or something else? 506 Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER); 507 result.appendChild(metadata_list); 508 509 // Add a metadata element specifying the number of matching documents 510 long totalDocs = numDocsMatched(query_result); 511 512 GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", ""+totalDocs); 513 514 // Create a document list to store the matching documents, and add them 515 String [] docs = getDocIDs(query_result); 516 String [] doc_ranks = getDocRanks(query_result); 517 518 // add a metadata item to specify docs returned 519 int docs_returned = docs.length; 520 if (does_paging) { 521 String maxdocs_str = (String)params.get(MAXDOCS_PARAM); 522 if (maxdocs_str != null) { 523 int maxdocs = Integer.parseInt(maxdocs_str); 524 docs_returned = (maxdocs < (int)totalDocs ? maxdocs : (int)totalDocs); 525 } 526 } 527 GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", ""+docs_returned); 528 529 // add a metadata item to specify what actual query was done - eg if stuff was stripped out etc. and then we can use the query later, cos we don't know which parameter was the query 530 GSXML.addMetadata(this.doc, metadata_list, "query", query); 531 if (docs.length>0) { 532 Element document_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER); 533 result.appendChild(document_list); 534 for (int d = 0; d < docs.length; d++) { 535 String doc_id = internalNum2OID(docs[d]); 536 Element doc_node = createDocNode(doc_id, doc_ranks[d]); 537 document_list.appendChild(doc_node); 538 } 539 } 540 541 // Create a term list to store the term information, and add it 542 Element term_list = this.doc.createElement(GSXML.TERM_ELEM+GSXML.LIST_MODIFIER); 543 result.appendChild(term_list); 544 addTermInfo(term_list, params, query_result); 545 546 return result; 547 548 } 549 550 /** methods to handle actually doing the query */ 551 /** do any initialisation of the query object */ 552 abstract protected boolean setUpQueryer(HashMap params); 553 /** do the query */ 554 abstract protected Object runQuery(String query); 555 /** get the total number of docs that match */ 556 abstract protected long numDocsMatched(Object query_result); 557 /** get the list of doc ids */ 558 abstract protected String [] getDocIDs(Object query_result); 559 /** get the list of doc ranks */ 560 abstract protected String [] getDocRanks(Object query_result); 561 /** add in term info if available */ 562 abstract protected boolean addTermInfo(Element term_list, HashMap params, 563 Object query_result); 564 565 /** combines all the field params into a single query 566 * - for simple field query */ 567 /** We assume the combination (AND/OR) is done by the match param */ 568 protected String parseFieldQueryParams(HashMap params) { 569 570 StringBuffer final_query = new StringBuffer(256); 571 String text_line = (String)params.get(FIELD_QUERY_PARAM); 572 String[] texts = text_line.split(",", -1); 573 String field_line = (String)params.get(FIELD_FIELD_PARAM); 574 String[] fields = field_line.split(",", -1); 575 576 for (int i=0; i<texts.length; i++) { 577 String q = texts[i].trim(); 578 if (!q.equals("")) { 579 final_query.append(" "+addFieldInfo(q, fields[i])); 580 } 581 } 582 583 return final_query.toString(); 584 } 585 586 abstract protected String addFieldInfo(String query, String field); 587 588 /** combines all the field params into a single query 589 * - for advanced field query */ 590 protected String parseAdvancedFieldQueryParams(HashMap params) { 591 592 StringBuffer final_query = new StringBuffer(256); 593 String text_line = (String)params.get(FIELD_QUERY_PARAM); 594 String[] texts = text_line.split(",", -1); 595 String field_line = (String)params.get(FIELD_FIELD_PARAM); 596 String[] fields = field_line.split(",", -1); 597 String [] cases = null; 598 String [] stems = null; 599 String [] accents = null; 600 if (does_case) { 601 String case_line = (String)params.get(FIELD_CASE_PARAM); 602 if (case_line !=null) 603 cases = case_line.split(",", -1); 604 } 605 if (does_stem) { 606 String stem_line = (String)params.get(FIELD_STEM_PARAM); 607 if (stem_line !=null) 608 stems = stem_line.split(",", -1); 609 } 610 if (does_accent) { 611 String accent_line = (String)params.get(FIELD_ACCENT_PARAM); 612 if (accent_line !=null) 613 accents = accent_line.split(",", -1); 614 } 615 String combine_line = (String)params.get(FIELD_COMBINE_PARAM); 616 String [] combines = combine_line.split(",", -1); 617 String combine = ""; 618 for (int i=0; i<texts.length; i++) { 619 if (i==0) {// assume first one is blank 620 combine = ""; 621 } else { 622 String x = combines[i]; 623 if (x.equals(FIELD_COMBINE_PARAM_AND)) { 624 combine = AND_OPERATOR; 625 } else if (x.equals(FIELD_COMBINE_PARAM_OR)) { 626 combine = OR_OPERATOR; 627 } else if (x.equals(FIELD_COMBINE_PARAM_NOT)) { 628 combine = NOT_OPERATOR; 629 } 630 631 } 632 633 String q = texts[i].trim(); 634 boolean modified = false; 635 if (!q.equals("")) { 636 String c = null; 637 String s = null; 638 String a = null; 639 if (does_case) { 640 modified = true; 641 c = cases[i]; 642 } 643 if (does_stem) { 644 modified = true; 645 s = stems[i]; 646 } 647 if (does_accent) { 648 modified = true; 649 a = accents[i]; 650 } 651 if (modified) { 652 q = addStemOptions(q, s, c, a); 653 } 654 addQueryElem(final_query, q, fields[i], combine); 655 } 656 } 657 return final_query.toString(); 658 } 659 660 abstract protected void addQueryElem(StringBuffer final_query, 661 String query, String field, 662 String combine); 663 abstract protected String addStemOptions(String query, String stem, 664 String casef, String accent); 665 42 // extra services offered by mgpp collections 43 protected static final String FIELD_QUERY_SERVICE = "FieldQuery"; 44 protected static final String ADVANCED_FIELD_QUERY_SERVICE = "AdvancedFieldQuery"; 45 46 // extra parameters used 47 protected static final String LEVEL_PARAM = "level"; 48 protected static final String RANK_PARAM = "sortBy"; 49 protected static final String RANK_PARAM_RANK = "1"; 50 protected static final String RANK_PARAM_NONE = "0"; 51 protected static final String SIMPLE_FIELD_PARAM = "simpleField"; 52 protected static final String ADVANCED_FIELD_PARAM = "complexField"; 53 54 // more params for field query 55 protected static final String FIELD_QUERY_PARAM = "fqv"; 56 protected static final String FIELD_STEM_PARAM = "fqs"; 57 protected static final String FIELD_CASE_PARAM = "fqc"; 58 protected static final String FIELD_ACCENT_PARAM = "fqa"; 59 protected static final String FIELD_FIELD_PARAM = "fqf"; 60 protected static final String FIELD_COMBINE_PARAM = "fqk"; 61 protected static final String FIELD_COMBINE_PARAM_AND = "0"; 62 protected static final String FIELD_COMBINE_PARAM_OR = "1"; 63 protected static final String FIELD_COMBINE_PARAM_NOT = "2"; 64 65 // some stuff for config files 66 protected static final String SEARCH_TYPE_ELEM = "searchType"; 67 protected static final String SEARCH_TYPE_PLAIN = "plain"; 68 protected static final String SEARCH_TYPE_SIMPLE_FORM = "simpleform"; 69 protected static final String SEARCH_TYPE_ADVANCED_FORM = "advancedform"; 70 71 protected static final String DEFAULT_LEVEL_ELEM = "defaultLevel"; 72 protected static final String DEFAULT_DB_LEVEL_ELEM = "defaultDBLevel"; 73 protected static final String LEVEL_ELEM = "level"; 74 protected static final String FIELD_ATT = "field"; 75 76 protected static final int TEXT_QUERY = 0; 77 protected static final int SIMPLE_QUERY = 1; 78 protected static final int ADVANCED_QUERY = 2; 79 80 protected String AND_OPERATOR = "&"; 81 protected String OR_OPERATOR = "|"; 82 protected String NOT_OPERATOR = "!"; 83 84 // the default level for searching 85 protected String default_level = null; 86 // default level for collection db 87 protected String default_db_level = null; 88 // which search services will we offer?? 89 protected boolean plain_search = false; 90 protected boolean simple_form_search = false; 91 protected boolean advanced_form_search = false; 92 93 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2FieldSearch.class.getName()); 94 95 /** constructor */ 96 public AbstractGS2FieldSearch() 97 { 98 } 99 100 public void cleanUp() 101 { 102 super.cleanUp(); 103 } 104 105 /** configure this service */ 106 public boolean configure(Element info, Element extra_info) 107 { 108 if (!super.configure(info, extra_info)) 109 { 110 return false; 111 } 112 113 // Get the default level out of <defaultLevel> (buildConfig.xml) 114 Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_LEVEL_ELEM); 115 if (def != null) 116 { 117 this.default_level = def.getAttribute(GSXML.SHORTNAME_ATT); 118 } 119 if (this.default_level == null || this.default_level.equals("")) 120 { 121 logger.error("default level not specified!, assuming Doc"); 122 this.default_level = "Doc"; 123 } 124 125 // Get the default DB level 126 def = (Element) GSXML.getChildByTagName(info, DEFAULT_DB_LEVEL_ELEM); 127 if (def != null) 128 { 129 this.default_db_level = def.getAttribute(GSXML.SHORTNAME_ATT); 130 } 131 if (this.default_db_level == null || this.default_db_level.equals("")) 132 { 133 logger.error("default database level (defaultDBLevel) not specified!, assuming Sec"); 134 this.default_db_level = "Sec"; 135 } 136 137 // get stuff from from extra info (which is collectionConfig.xml) 138 if (extra_info != null) 139 { 140 141 // the search element 142 Element config_search = (Element) GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM); 143 144 NodeList search_types = config_search.getElementsByTagName(SEARCH_TYPE_ELEM); 145 if (search_types == null) 146 { 147 // none specified, assume plain only 148 this.plain_search = true; 149 } 150 else 151 { 152 for (int i = 0; i < search_types.getLength(); i++) 153 { 154 Element t = (Element) search_types.item(i); 155 String type_name = t.getAttribute(GSXML.NAME_ATT); 156 if (type_name.equals(SEARCH_TYPE_PLAIN)) 157 { 158 this.plain_search = true; 159 } 160 else if (type_name.equals(SEARCH_TYPE_SIMPLE_FORM)) 161 { 162 this.simple_form_search = true; 163 } 164 else if (type_name.equals(SEARCH_TYPE_ADVANCED_FORM)) 165 { 166 this.advanced_form_search = true; 167 } 168 } 169 } 170 171 // AbstractGS2TextSearch has set up the TextQuery service, but we may not want it 172 if (!this.plain_search) 173 { 174 // need to remove the TextQuery service 175 Element tq_service = GSXML.getNamedElement(short_service_info, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, QUERY_SERVICE); 176 short_service_info.removeChild(tq_service); 177 178 } 179 180 Document owner = info.getOwnerDocument(); 181 182 NodeList levels = info.getElementsByTagName(GSXML.LEVEL_ELEM); 183 184 for (int i = 0; i < levels.getLength(); i++) 185 { 186 Element lev = (Element) levels.item(i); 187 String name = lev.getAttribute(GSXML.NAME_ATT); 188 Element node_extra = GSXML.getNamedElement(config_search, GSXML.LEVEL_ELEM, GSXML.NAME_ATT, name); 189 if (node_extra == null) 190 { 191 logger.error("haven't found extra info for level named " + name); 192 continue; 193 } 194 195 // get the display elements if any - displayName 196 NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM); 197 if (display_names != null) 198 { 199 for (int j = 0; j < display_names.getLength(); j++) 200 { 201 Element e = (Element) display_names.item(j); 202 lev.appendChild(owner.importNode(e, true)); 203 } 204 } 205 } // for each level 206 } 207 else 208 { 209 // for soem reason we don't have the collectionConfig file. assume plain only 210 this.plain_search = true; 211 } 212 213 // the format info is the same for all services 214 Element format_info = (Element) format_info_map.get(QUERY_SERVICE); 215 216 // set up the extra services which are available for this collection 217 if (this.simple_form_search) 218 { 219 // set up short_service_info_ - for now just has id and type - name will be added in on the fly 220 Element fq_service = this.doc.createElement(GSXML.SERVICE_ELEM); 221 fq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY); 222 fq_service.setAttribute(GSXML.NAME_ATT, FIELD_QUERY_SERVICE); 223 this.short_service_info.appendChild(fq_service); 224 225 if (format_info != null) 226 { 227 this.format_info_map.put(FIELD_QUERY_SERVICE, format_info); 228 } 229 } 230 231 if (this.advanced_form_search) 232 { 233 Element afq_service = this.doc.createElement(GSXML.SERVICE_ELEM); 234 afq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY); 235 afq_service.setAttribute(GSXML.NAME_ATT, ADVANCED_FIELD_QUERY_SERVICE); 236 this.short_service_info.appendChild(afq_service); 237 238 if (format_info != null) 239 { 240 this.format_info_map.put(ADVANCED_FIELD_QUERY_SERVICE, format_info); 241 } 242 } 243 244 return true; 245 } 246 247 protected Element getServiceDescription(String service_id, String lang, String subset) 248 { 249 // should we check that the service is actually on offer? presumably we wont get asked for services that we haven't advertised previously. 250 251 if (!service_id.equals(FIELD_QUERY_SERVICE) && !service_id.equals(ADVANCED_FIELD_QUERY_SERVICE)) 252 { 253 return super.getServiceDescription(service_id, lang, subset); 254 } 255 256 Element service = this.doc.createElement(GSXML.SERVICE_ELEM); 257 service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY); 258 service.setAttribute(GSXML.NAME_ATT, service_id); 259 if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER)) 260 { 261 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(service_id + ".name", lang))); 262 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service_id + ".submit", lang))); 263 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(service_id + ".description", lang))); 264 265 } 266 if (subset == null || subset.equals(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER)) 267 { 268 Element param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER); 269 service.appendChild(param_list); 270 if (service_id.equals(FIELD_QUERY_SERVICE)) 271 { 272 273 addCustomQueryParams(param_list, lang); 274 createParameter(MAXDOCS_PARAM, param_list, lang); 275 if (!default_index_subcollection.equals("")) 276 { 277 createParameter(INDEX_SUBCOLLECTION_PARAM, param_list, lang); 278 } 279 if (!default_index_language.equals("")) 280 { 281 createParameter(INDEX_LANGUAGE_PARAM, param_list, lang); 282 } 283 // create a multi param for the fields etc 284 // text box, field 285 Element multiparam = null; 286 Element param = null; 287 multiparam = GSXML.createParameterDescription(this.doc, SIMPLE_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null); 288 multiparam.setAttribute("occurs", "4"); 289 param_list.appendChild(multiparam); 290 291 // the components 292 293 createParameter(FIELD_QUERY_PARAM, multiparam, lang); 294 createParameter(FIELD_FIELD_PARAM, multiparam, lang); 295 296 } 297 else 298 { 299 createParameter(LEVEL_PARAM, param_list, lang); 300 createParameter(RANK_PARAM, param_list, lang); 301 createParameter(MAXDOCS_PARAM, param_list, lang); 302 if (!default_index_subcollection.equals("")) 303 { 304 createParameter(INDEX_SUBCOLLECTION_PARAM, param_list, lang); 305 } 306 if (!default_index_language.equals("")) 307 { 308 createParameter(INDEX_LANGUAGE_PARAM, param_list, lang); 309 } 310 311 // create a multi param for the fields etc 312 // text box, stem, case, field 313 314 Element multiparam = null; 315 Element param = null; 316 317 multiparam = GSXML.createParameterDescription(this.doc, ADVANCED_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null); 318 multiparam.setAttribute("occurs", "4"); 319 param_list.appendChild(multiparam); 320 321 createParameter(FIELD_COMBINE_PARAM, multiparam, lang); 322 createParameter(FIELD_QUERY_PARAM, multiparam, lang); 323 if (this.does_case) 324 { 325 createParameter(FIELD_CASE_PARAM, multiparam, lang); 326 } 327 if (this.does_stem) 328 { 329 createParameter(FIELD_STEM_PARAM, multiparam, lang); 330 } 331 if (this.does_accent) 332 { 333 createParameter(FIELD_ACCENT_PARAM, multiparam, lang); 334 } 335 createParameter(FIELD_FIELD_PARAM, multiparam, lang); 336 337 } 338 } 339 return service; 340 341 } 342 343 /** add in the level params to TextQuery */ 344 protected void addCustomQueryParams(Element param_list, String lang) 345 { 346 createParameter(LEVEL_PARAM, param_list, lang); 347 super.addCustomQueryParams(param_list, lang); 348 } 349 350 /** create a param and add to the list */ 351 protected void createParameter(String name, Element param_list, String lang) 352 { 353 Element param = null; 354 if (name.equals(LEVEL_PARAM)) 355 { 356 ArrayList level_ids = new ArrayList(); 357 ArrayList level_names = new ArrayList(); 358 getLevelData(level_ids, level_names, lang); 359 if (level_ids.size() > 1) 360 { 361 // the first one is the default 362 //param = GSXML.createParameterDescription2(this.doc, LEVEL_PARAM, getTextString("param."+LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)level_ids.get(0), level_ids, level_names); 363 param = GSXML.createParameterDescription2(this.doc, LEVEL_PARAM, getTextString("param." + LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, this.default_level, level_ids, level_names); 364 } 365 else 366 { 367 // we need to set the level, but hidden, in case there is an invalid level saved 368 //param = GSXML.createParameterDescription(this.doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, (String)level_ids.get(0), null, null); 369 param = GSXML.createParameterDescription(this.doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, this.default_level, null, null); 370 } 371 } 372 else if (name.equals(RANK_PARAM)) 373 { 374 String[] vals1 = { RANK_PARAM_RANK, RANK_PARAM_NONE }; 375 String[] vals1_texts = { getTextString("param." + RANK_PARAM + "." + RANK_PARAM_RANK, lang), getTextString("param." + RANK_PARAM + "." + RANK_PARAM_NONE, lang) }; 376 377 param = GSXML.createParameterDescription(this.doc, RANK_PARAM, getTextString("param." + RANK_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, RANK_PARAM_RANK, vals1, vals1_texts); 378 379 } 380 else if (name.equals(FIELD_QUERY_PARAM)) 381 { 382 param = GSXML.createParameterDescription(this.doc, FIELD_QUERY_PARAM, getTextString("param." + FIELD_QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null); 383 384 } 385 else if (name.equals(FIELD_CASE_PARAM) || name.equals(FIELD_STEM_PARAM) || name.equals(FIELD_ACCENT_PARAM)) 386 { 387 String[] bool_ops = { "0", "1" }; 388 String[] bool_texts = { getTextString("param.boolean.off", lang, "AbstractTextSearch"), getTextString("param.boolean.on", lang, "AbstractTextSearch") }; 389 param = GSXML.createParameterDescription(this.doc, name, getTextString("param." + name, lang), GSXML.PARAM_TYPE_BOOLEAN, BOOLEAN_PARAM_ON, bool_ops, bool_texts); 390 391 } 392 else if (name.equals(FIELD_FIELD_PARAM)) 393 { 394 ArrayList fields = new ArrayList(); 395 ArrayList field_names = new ArrayList(); 396 getIndexData(fields, field_names, lang); 397 // the field list - read from config file 398 399 // Fix for http://trac.greenstone.org/ticket/245 "java crash, index out of bounds" 400 // org.greenstone.gsdl3.service.AbstractGS2FieldSearch.createParameter(AbstractGS2FieldSearch.java:362) 401 // Changed from: 402 // param = GSXML.createParameterDescription2(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)fields.get(0), fields, field_names ); 403 String default_value = (fields.size() > 0) ? (String) fields.get(0) : null; 404 // don't want to access element 0 if fields.size()==0, and 405 // GSXML.createParameterDescription2 checks for default_value==null condition 406 param = GSXML.createParameterDescription2(this.doc, name, getTextString("param." + name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, default_value, fields, field_names); 407 408 } 409 else if (name.equals(FIELD_COMBINE_PARAM)) 410 { 411 412 String[] vals = { FIELD_COMBINE_PARAM_AND, FIELD_COMBINE_PARAM_OR, FIELD_COMBINE_PARAM_NOT }; 413 String[] val_texts = { getTextString("param." + FIELD_COMBINE_PARAM + "." + FIELD_COMBINE_PARAM_AND, lang), getTextString("param." + FIELD_COMBINE_PARAM + "." + FIELD_COMBINE_PARAM_OR, lang), getTextString("param." + FIELD_COMBINE_PARAM + "." + FIELD_COMBINE_PARAM_NOT, lang) }; 414 415 param = GSXML.createParameterDescription(this.doc, FIELD_COMBINE_PARAM, "", GSXML.PARAM_TYPE_ENUM_SINGLE, FIELD_COMBINE_PARAM_AND, vals, val_texts); 416 param.setAttribute(GSXML.PARAM_IGNORE_POS_ATT, "0"); 417 } 418 419 if (param != null) 420 { 421 param_list.appendChild(param); 422 } 423 else 424 { 425 super.createParameter(name, param_list, lang); 426 } 427 } 428 429 // should cache some of this 430 protected void getLevelData(ArrayList level_ids, ArrayList level_names, String lang) 431 { 432 Element level_list = (Element) GSXML.getChildByTagName(this.config_info, LEVEL_ELEM + GSXML.LIST_MODIFIER); 433 NodeList levels = level_list.getElementsByTagName(LEVEL_ELEM); 434 for (int i = 0; i < levels.getLength(); i++) 435 { 436 Element level = (Element) levels.item(i); 437 String shortname = level.getAttribute(GSXML.SHORTNAME_ATT); 438 if (shortname.equals("")) 439 { 440 continue; 441 } 442 level_ids.add(shortname); 443 String display_name = GSXML.getDisplayText(level, GSXML.DISPLAY_TEXT_NAME, lang, "en"); 444 if (display_name.equals("")) 445 { 446 // we'll use the name, and the dictionary 447 display_name = level.getAttribute(GSXML.NAME_ATT); 448 if (display_name.equals("")) 449 { 450 display_name = shortname; 451 } 452 else 453 { 454 display_name = getTextString("level." + display_name, lang); 455 } 456 } 457 level_names.add(display_name); 458 } 459 } 460 461 // the following three functions are needed so the base class can 462 // call the process+SERVICE_NAME methods 463 /** process a text query */ 464 protected Element processTextQuery(Element request) 465 { 466 return processAnyQuery(request, TEXT_QUERY); 467 } 468 469 /** process a field query */ 470 protected Element processFieldQuery(Element request) 471 { 472 return processAnyQuery(request, SIMPLE_QUERY); 473 } 474 475 /** process an advanced field query */ 476 protected Element processAdvancedFieldQuery(Element request) 477 { 478 return processAnyQuery(request, ADVANCED_QUERY); 479 } 480 481 /** process a query */ 482 protected Element processAnyQuery(Element request, int query_type) 483 { 484 String service_name = null; 485 String empty_query_test_param = null; 486 // set up the type specific bits 487 switch (query_type) 488 { 489 case TEXT_QUERY: 490 service_name = QUERY_SERVICE; 491 empty_query_test_param = QUERY_PARAM; 492 break; 493 case SIMPLE_QUERY: 494 service_name = FIELD_QUERY_SERVICE; 495 empty_query_test_param = FIELD_QUERY_PARAM; 496 break; 497 case ADVANCED_QUERY: 498 service_name = ADVANCED_FIELD_QUERY_SERVICE; 499 empty_query_test_param = FIELD_QUERY_PARAM; 500 break; 501 default: 502 // should never get here 503 logger.error("wrong query type!!"); 504 return null; 505 } 506 507 // Create a new (empty) result message 508 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM); 509 result.setAttribute(GSXML.FROM_ATT, service_name); 510 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS); 511 512 // Get the parameters of the request 513 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER); 514 if (param_list == null) 515 { 516 logger.error("TextQuery request had no paramList."); 517 return result; // Return the empty result 518 } 519 520 // Process the request parameters 521 HashMap params = GSXML.extractParams(param_list, false); 522 523 // Make sure a query has been specified 524 String query = (String) params.get(empty_query_test_param); 525 if (query == null || query.equals("")) 526 { 527 return result; // Return the empty result 528 } 529 530 // If a field hasn't been specified, use the default - for textQuery 531 String field = (String) params.get(INDEX_PARAM); 532 if (field == null) 533 { 534 field = default_index; 535 } 536 537 // set up the appropriate query system 538 if (!setUpQueryer(params)) 539 { 540 return result; 541 } 542 543 // if field search, create the query string 544 switch (query_type) 545 { 546 case TEXT_QUERY: 547 query = addFieldInfo(query, field); 548 break; 549 case SIMPLE_QUERY: 550 query = parseFieldQueryParams(params); 551 break; 552 case ADVANCED_QUERY: 553 query = parseAdvancedFieldQueryParams(params); 554 break; 555 } 556 557 // run the query 558 Object query_result = runQuery(query); 559 560 // build up the response 561 562 // Create a metadata list to store information about the query results 563 // should we be using metadataList? or something else? 564 Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER); 565 result.appendChild(metadata_list); 566 567 // Add a metadata element specifying the number of matching documents 568 long totalDocs = numDocsMatched(query_result); 569 570 GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", "" + totalDocs); 571 572 // Create a document list to store the matching documents, and add them 573 String[] docs = getDocIDs(query_result); 574 String[] doc_ranks = getDocRanks(query_result); 575 576 // add a metadata item to specify docs returned 577 int docs_returned = docs.length; 578 if (does_paging) 579 { 580 String maxdocs_str = (String) params.get(MAXDOCS_PARAM); 581 if (maxdocs_str != null) 582 { 583 int maxdocs = Integer.parseInt(maxdocs_str); 584 docs_returned = (maxdocs < (int) totalDocs ? maxdocs : (int) totalDocs); 585 } 586 } 587 GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", "" + docs_returned); 588 589 // add a metadata item to specify what actual query was done - eg if stuff was stripped out etc. and then we can use the query later, cos we don't know which parameter was the query 590 GSXML.addMetadata(this.doc, metadata_list, "query", query); 591 if (docs.length > 0) 592 { 593 Element document_list = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER); 594 result.appendChild(document_list); 595 for (int d = 0; d < docs.length; d++) 596 { 597 String doc_id = internalNum2OID(docs[d]); 598 Element doc_node = createDocNode(doc_id, doc_ranks[d]); 599 document_list.appendChild(doc_node); 600 } 601 } 602 603 // Create a term list to store the term information, and add it 604 Element term_list = this.doc.createElement(GSXML.TERM_ELEM + GSXML.LIST_MODIFIER); 605 result.appendChild(term_list); 606 addTermInfo(term_list, params, query_result); 607 608 return result; 609 610 } 611 612 /** methods to handle actually doing the query */ 613 /** do any initialisation of the query object */ 614 abstract protected boolean setUpQueryer(HashMap params); 615 616 /** do the query */ 617 abstract protected Object runQuery(String query); 618 619 /** get the total number of docs that match */ 620 abstract protected long numDocsMatched(Object query_result); 621 622 /** get the list of doc ids */ 623 abstract protected String[] getDocIDs(Object query_result); 624 625 /** get the list of doc ranks */ 626 abstract protected String[] getDocRanks(Object query_result); 627 628 /** add in term info if available */ 629 abstract protected boolean addTermInfo(Element term_list, HashMap params, Object query_result); 630 631 /** 632 * combines all the field params into a single query - for simple field 633 * query 634 */ 635 /** We assume the combination (AND/OR) is done by the match param */ 636 protected String parseFieldQueryParams(HashMap params) 637 { 638 639 StringBuffer final_query = new StringBuffer(256); 640 String text_line = (String) params.get(FIELD_QUERY_PARAM); 641 String[] texts = text_line.split(",", -1); 642 String field_line = (String) params.get(FIELD_FIELD_PARAM); 643 String[] fields = field_line.split(",", -1); 644 645 for (int i = 0; i < texts.length; i++) 646 { 647 String q = texts[i].trim(); 648 if (!q.equals("")) 649 { 650 final_query.append(" " + addFieldInfo(q, fields[i])); 651 } 652 } 653 654 return final_query.toString(); 655 } 656 657 abstract protected String addFieldInfo(String query, String field); 658 659 /** 660 * combines all the field params into a single query - for advanced field 661 * query 662 */ 663 protected String parseAdvancedFieldQueryParams(HashMap params) 664 { 665 666 StringBuffer final_query = new StringBuffer(256); 667 String text_line = (String) params.get(FIELD_QUERY_PARAM); 668 String[] texts = text_line.split(",", -1); 669 String field_line = (String) params.get(FIELD_FIELD_PARAM); 670 String[] fields = field_line.split(",", -1); 671 String[] cases = null; 672 String[] stems = null; 673 String[] accents = null; 674 if (does_case) 675 { 676 String case_line = (String) params.get(FIELD_CASE_PARAM); 677 if (case_line != null) 678 cases = case_line.split(",", -1); 679 } 680 if (does_stem) 681 { 682 String stem_line = (String) params.get(FIELD_STEM_PARAM); 683 if (stem_line != null) 684 stems = stem_line.split(",", -1); 685 } 686 if (does_accent) 687 { 688 String accent_line = (String) params.get(FIELD_ACCENT_PARAM); 689 if (accent_line != null) 690 accents = accent_line.split(",", -1); 691 } 692 String combine_line = (String) params.get(FIELD_COMBINE_PARAM); 693 String[] combines = combine_line.split(",", -1); 694 String combine = ""; 695 for (int i = 0; i < texts.length; i++) 696 { 697 if (i == 0) 698 {// assume first one is blank 699 combine = ""; 700 } 701 else 702 { 703 String x = combines[i]; 704 if (x.equals(FIELD_COMBINE_PARAM_AND)) 705 { 706 combine = AND_OPERATOR; 707 } 708 else if (x.equals(FIELD_COMBINE_PARAM_OR)) 709 { 710 combine = OR_OPERATOR; 711 } 712 else if (x.equals(FIELD_COMBINE_PARAM_NOT)) 713 { 714 combine = NOT_OPERATOR; 715 } 716 717 } 718 719 String q = texts[i].trim(); 720 boolean modified = false; 721 if (!q.equals("")) 722 { 723 String c = null; 724 String s = null; 725 String a = null; 726 if (does_case) 727 { 728 modified = true; 729 c = cases[i]; 730 } 731 if (does_stem) 732 { 733 modified = true; 734 s = stems[i]; 735 } 736 if (does_accent) 737 { 738 modified = true; 739 a = accents[i]; 740 } 741 if (modified) 742 { 743 q = addStemOptions(q, s, c, a); 744 } 745 addQueryElem(final_query, q, fields[i], combine); 746 } 747 } 748 return final_query.toString(); 749 } 750 751 abstract protected void addQueryElem(StringBuffer final_query, String query, String field, String combine); 752 753 abstract protected String addStemOptions(String query, String stem, String casef, String accent); 754 666 755 } 667 668
Note:
See TracChangeset
for help on using the changeset viewer.