source: main/trunk/greenstone2/common-src/indexers/lucene-gs/src/org/greenstone/LuceneWrapper3/GS2LuceneQuery.java@ 28031

Last change on this file since 28031 was 28031, checked in by kjdon, 11 years ago

changes for sorting search results. setReverseSort now takes a boolean param, otherwise can never unset it.

File size: 24.5 KB
Line 
1/**********************************************************************
2 *
3 * GS2LuceneQuery.java
4 *
5 * Copyright 2004 The New Zealand Digital Library Project
6 *
7 * A component of the Greenstone digital library software
8 * from the New Zealand Digital Library Project at the
9 * University of Waikato, New Zealand.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 *********************************************************************/
26package org.greenstone.LuceneWrapper3;
27
28
29import java.io.*;
30import java.util.*;
31import java.util.regex.*;
32
33import org.apache.lucene.analysis.Analyzer;
34import org.apache.lucene.analysis.standard.StandardAnalyzer;
35import org.apache.lucene.document.Document;
36import org.apache.lucene.index.IndexReader;
37import org.apache.lucene.index.Term;
38import org.apache.lucene.index.TermDocs;
39import org.apache.lucene.queryParser.ParseException;
40import org.apache.lucene.queryParser.QueryParser;
41import org.apache.lucene.search.BooleanQuery; // for the TooManyClauses exception
42import org.apache.lucene.search.Filter;
43import org.apache.lucene.search.IndexSearcher;
44import org.apache.lucene.search.MultiTermQuery;
45import org.apache.lucene.search.MultiTermQuery.ConstantScoreAutoRewrite;
46import org.apache.lucene.search.Query;
47import org.apache.lucene.search.TermRangeFilter;
48import org.apache.lucene.search.Searcher;
49import org.apache.lucene.search.ScoreDoc;
50import org.apache.lucene.search.Sort;
51import org.apache.lucene.search.SortField;
52import org.apache.lucene.search.TopFieldDocs;
53
54import org.apache.lucene.store.Directory;
55import org.apache.lucene.store.FSDirectory;
56import org.apache.lucene.util.Version;
57
58
59public class GS2LuceneQuery extends SharedSoleneQuery
60{
61 public static String SORT_RANK = "rank";
62 public static String SORT_NATURAL = "natural";
63
64 protected String full_indexdir="";
65
66 protected int sort_type = SortField.SCORE;
67 protected boolean reverse_sort = false;
68 protected Sort sorter=new Sort();
69 protected Filter filter = null;
70
71 protected static Version matchVersion = Version.LUCENE_24;
72
73 protected QueryParser query_parser = null;
74 protected QueryParser query_parser_no_stop_words = null;
75 protected Searcher searcher = null;
76 protected IndexReader reader = null;
77
78 public GS2LuceneQuery() {
79 super();
80
81 // Create one query parser with the standard set of stop words, and one with none
82
83 query_parser = new QueryParser(matchVersion, TEXTFIELD, new GS2Analyzer()); // uses built-in stop_words_set
84 query_parser_no_stop_words = new QueryParser(matchVersion, TEXTFIELD, new GS2Analyzer(new String[] { }));
85 }
86
87
88 public boolean initialise() {
89
90 if (!super.initialise()) {
91 return false;
92 }
93
94
95 if (full_indexdir==null || full_indexdir.length()==-1){
96 utf8out.println("Index directory is not indicated ");
97 utf8out.flush();
98 return false;
99 }
100
101 try {
102 Directory full_indexdir_dir = FSDirectory.open(new File(full_indexdir));
103 searcher = new IndexSearcher(full_indexdir_dir,true);
104 // need to set this to get it to compute ranks when sorting by fields
105 ((IndexSearcher)searcher).setDefaultFieldSortScoring(true,true);
106 reader = ((IndexSearcher) searcher).getIndexReader();
107
108
109 this.sorter = new Sort(new SortField(this.sort_field, this.sort_type, this.reverse_sort));
110 }
111 catch (IOException exception) {
112 exception.printStackTrace();
113 return false;
114 }
115 return true;
116
117 }
118
119 public void setIndexDir(String full_indexdir) {
120 this.full_indexdir = full_indexdir;
121 }
122
123 public void setSortField(String sort_field) {
124 if (sort_field.equals(SORT_RANK)) {
125 this.sort_field = null;
126 this.sort_type = SortField.SCORE;
127 } else if (sort_field.equals(SORT_NATURAL)) {
128 this.sort_field = null;
129 this.sort_type = SortField.DOC;
130 } else {
131 this.sort_field = sort_field;
132 this.sort_type = SortField.STRING; // for now. numeric??
133 }
134 }
135 public void setReverseSort(boolean reverse) {
136 this.reverse_sort = reverse;
137 }
138 public boolean getReverseSort() {
139 return this.reverse_sort;
140 }
141
142 public void setFilterString(String filter_string) {
143 super.setFilterString(filter_string);
144 this.filter = parseFilterString(filter_string);
145 }
146
147 public Filter getFilter() {
148 return this.filter;
149 }
150
151
152 public LuceneQueryResult runQuery(String query_string) {
153
154 if (query_string == null || query_string.equals("")) {
155 utf8out.println("The query word is not indicated ");
156 utf8out.flush();
157 return null;
158 }
159
160 LuceneQueryResult lucene_query_result=new LuceneQueryResult();
161 lucene_query_result.clear();
162
163 try {
164 Query query_including_stop_words = query_parser_no_stop_words.parse(query_string);
165 query_including_stop_words = query_including_stop_words.rewrite(reader);
166
167 // System.err.println("********* query_string " + query_string + "****");
168
169 Query query = parseQuery(reader, query_parser, query_string, fuzziness);
170
171 // GS2's LuceneWrapper uses lucene-2.3.2. GS3's LuceneWrapper3 works with lucene-3.3.0.
172 // This change in lucene core library for GS3 (present since after version 2.4.1) had the
173 // side-effect that searching on "econom*" didn't display what terms it was searching for,
174 // whereas it had done so in GS2.
175
176 // The details of this problem and its current solution are explained in the ticket
177 // http://trac.greenstone.org/ticket/845
178
179 // We need to change the settings for the rewriteMethod in order to get searches on wildcards
180 // to produce search terms again when the query gets rewritten.
181
182 // We try, in order:
183 // 1. RewriteMethod set to BooleanQuery, to get it working as in GS2 which uses lucene-2.3.2
184 // it will expand wildcard searches to its terms when searching at both section AND doc level.
185 // If that throws a TooManyClauses exception (like when searching for "a*" over lucene demo collection)
186 // 2. Then try a custom rewriteMethod which sets termCountCutoff=350 and docCountPercent cutoff=0.1%
187 // If that throws a TooManyClauses exception (could perhaps happen if the collection has a huge number of docs
188 // 3. Then try the default apache rewriteMethod with its optimum defaults of
189 // termCountCutoff=350 and docCountPercent cutoff=0.1%
190 // See http://lucene.apache.org/core/3_6_1/api/core/org/apache/lucene/search/MultiTermQuery.html
191
192 if(query instanceof MultiTermQuery) {
193 MultiTermQuery multiTermQuery = (MultiTermQuery)query;
194 multiTermQuery.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE);
195 // less CPU intensive than MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE)
196 }
197
198 try {
199 query = query.rewrite(reader);
200 }
201 catch(BooleanQuery.TooManyClauses clauseException) {
202 // Example test case: try searching the lucene demo collection for "a*"
203 // and you'll hit this exception
204
205 lucene_query_result.setError(LuceneQueryResult.TOO_MANY_CLAUSES_ERROR);
206
207 if(query instanceof MultiTermQuery) {
208
209 // CustomRewriteMethod: setting the docCountPercent cutoff to a custom 100%.
210 // This will at least expand the query to its terms when searching with wildcards at section-level
211 // (though it doesn't seem to work for doc-level searches, no matter what the cutoffs are set to).
212
213 MultiTermQuery.ConstantScoreAutoRewrite customRewriteMethod = new MultiTermQuery.ConstantScoreAutoRewrite();
214 customRewriteMethod.setDocCountPercent(100.0);
215 customRewriteMethod.setTermCountCutoff(350); // same as default
216
217 MultiTermQuery multiTermQuery = (MultiTermQuery)query;
218 multiTermQuery.setRewriteMethod(customRewriteMethod);
219 try {
220 query = query.rewrite(reader);
221 }
222 catch(BooleanQuery.TooManyClauses clauseExceptionAgain) {
223
224 // do what the code originally did: use the default rewriteMethod which
225 // uses a default docCountPercent=0.1 (%) and termCountCutoff=350
226
227 multiTermQuery.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT);
228 query = query.rewrite(reader);
229 }
230 }
231 }
232
233 // Get the list of expanded query terms and their frequencies
234 // num docs matching, and total frequency
235 HashSet terms = new HashSet();
236 query.extractTerms(terms);
237
238 HashMap doc_term_freq_map = new HashMap();
239
240 Iterator iter = terms.iterator();
241 while (iter.hasNext()) {
242
243 Term term = (Term) iter.next();
244
245 // Get the term frequency over all the documents
246 TermDocs term_docs = reader.termDocs(term);
247 int term_freq = 0;
248 int match_docs = 0;
249 while (term_docs.next())
250 {
251 if (term_docs.freq() != 0)
252 {
253 term_freq += term_docs.freq();
254 match_docs++;
255
256 // Calculate the document-level term frequency as well
257 Integer lucene_doc_num_obj = new Integer(term_docs.doc());
258 int doc_term_freq = 0;
259 if (doc_term_freq_map.containsKey(lucene_doc_num_obj))
260 {
261 doc_term_freq = ((Integer) doc_term_freq_map.get(lucene_doc_num_obj)).intValue();
262 }
263 doc_term_freq += term_docs.freq();
264
265 doc_term_freq_map.put(lucene_doc_num_obj, new Integer(doc_term_freq));
266 }
267 }
268
269 // Create a term
270 lucene_query_result.addTerm(term.text(), term.field(), match_docs, term_freq);
271 }
272
273 // Get the list of stop words removed from the query
274 HashSet terms_including_stop_words = new HashSet();
275 query_including_stop_words.extractTerms(terms_including_stop_words);
276 Iterator terms_including_stop_words_iter = terms_including_stop_words.iterator();
277 while (terms_including_stop_words_iter.hasNext()) {
278 Term term = (Term) terms_including_stop_words_iter.next();
279 if (!terms.contains(term)) {
280 lucene_query_result.addStopWord(term.text());
281 }
282 }
283
284 // do the query
285 // Simple case for getting all the matching documents
286 if (end_results == Integer.MAX_VALUE) {
287 // Perform the query (filter and sorter may be null)
288 TopFieldDocs hits = searcher.search(query, filter, end_results, sorter);
289 lucene_query_result.setTotalDocs(hits.totalHits);
290
291 // Output the matching documents
292 lucene_query_result.setStartResults(start_results);
293 lucene_query_result.setEndResults(hits.totalHits);
294
295 for (int i = start_results; i <= hits.totalHits; i++) {
296 int lucene_doc_num = hits.scoreDocs[i - 1].doc;
297 Document doc = reader.document(lucene_doc_num);
298 int doc_term_freq = 0;
299 Integer doc_term_freq_object = (Integer) doc_term_freq_map.get(new Integer(lucene_doc_num));
300 if (doc_term_freq_object != null)
301 {
302 doc_term_freq = doc_term_freq_object.intValue();
303 }
304 lucene_query_result.addDoc(doc.get("docOID").trim(), hits.scoreDocs[i-1].score, doc_term_freq);
305 }
306 }
307
308 // Slightly more complicated case for returning a subset of the matching documents
309 else {
310 // Perform the query (filter may be null)
311 TopFieldDocs hits = searcher.search(query, filter, end_results, sorter);
312 lucene_query_result.setTotalDocs(hits.totalHits);
313
314 lucene_query_result.setStartResults(start_results);
315 lucene_query_result.setEndResults(end_results < hits.scoreDocs.length ? end_results: hits.scoreDocs.length);
316
317 // Output the matching documents
318 for (int i = start_results; (i <= hits.scoreDocs.length && i <= end_results); i++) {
319 int lucene_doc_num = hits.scoreDocs[i - 1].doc;
320 Document doc = reader.document(lucene_doc_num);
321 int doc_term_freq = 0;
322 Integer doc_term_freq_object = (Integer) doc_term_freq_map.get(new Integer(lucene_doc_num));
323 if (doc_term_freq_object != null)
324 {
325 doc_term_freq = doc_term_freq_object.intValue();
326 }
327 lucene_query_result.addDoc(doc.get("docOID").trim(), hits.scoreDocs[i-1].score, doc_term_freq);
328 }
329 }
330 }
331
332 catch (ParseException parse_exception) {
333 lucene_query_result.setError(LuceneQueryResult.PARSE_ERROR);
334 }
335 catch (BooleanQuery.TooManyClauses too_many_clauses_exception) {
336 lucene_query_result.setError(LuceneQueryResult.TOO_MANY_CLAUSES_ERROR);
337 }
338 catch (IOException exception) {
339 lucene_query_result.setError(LuceneQueryResult.IO_ERROR);
340 exception.printStackTrace();
341 }
342 catch (Exception exception) {
343 lucene_query_result.setError(LuceneQueryResult.OTHER_ERROR);
344 exception.printStackTrace();
345 }
346 return lucene_query_result;
347 }
348
349 public void setDefaultConjunctionOperator(String default_conjunction_operator) {
350 super.setDefaultConjunctionOperator(default_conjunction_operator);
351
352 if (default_conjunction_operator.equals("AND")) {
353 query_parser.setDefaultOperator(query_parser.AND_OPERATOR);
354 query_parser_no_stop_words.setDefaultOperator(query_parser.AND_OPERATOR);
355 } else { // default is OR
356 query_parser.setDefaultOperator(query_parser.OR_OPERATOR);
357 query_parser_no_stop_words.setDefaultOperator(query_parser.OR_OPERATOR);
358 }
359 }
360
361
362 public void cleanUp() {
363 super.cleanUp();
364 try {
365 if (searcher != null) {
366 searcher.close();
367 }
368 } catch (IOException exception) {
369 exception.printStackTrace();
370 }
371 }
372
373
374 protected Query parseQuery(IndexReader reader, QueryParser query_parser, String query_string, String fuzziness)
375 throws java.io.IOException, org.apache.lucene.queryParser.ParseException
376 {
377 // Split query string into the search terms and the filter terms
378 // * The first +(...) term contains the search terms so count
379 // up '(' and stop when we finish matching ')'
380 int offset = 0;
381 int paren_count = 0;
382 boolean seen_paren = false;
383 while (offset < query_string.length() && (!seen_paren || paren_count > 0)) {
384 if (query_string.charAt(offset) == '(') {
385 paren_count++;
386 seen_paren = true;
387 }
388 if (query_string.charAt(offset) == ')') {
389 paren_count--;
390 }
391 offset++;
392 }
393 String query_prefix = query_string.substring(0, offset);
394 String query_suffix = query_string.substring(offset);
395
396 ///ystem.err.println("Prefix: " + query_prefix);
397 ///ystem.err.println("Suffix: " + query_suffix);
398
399 Query query = query_parser.parse(query_prefix);
400 query = query.rewrite(reader);
401
402 // If this is a fuzzy search, then we need to add the fuzzy
403 // flag to each of the query terms
404 if (fuzziness != null && query.toString().length() > 0) {
405
406 // Revert the query to a string
407 System.err.println("Rewritten query: " + query.toString());
408 // Search through the string for TX:<term> query terms
409 // and append the ~ operator. Note that this search will
410 // not change phrase searches (TX:"<term> <term>") as
411 // fuzzy searching is not possible for these entries.
412 // Yahoo! Time for a state machine!
413 StringBuffer mutable_query_string = new StringBuffer(query.toString());
414 int o = 0; // Offset
415 // 0 = BASE, 1 = SEEN_T, 2 = SEEN_TX, 3 = SEEN_TX:
416 int s = 0; // State
417 while(o < mutable_query_string.length()) {
418 char c = mutable_query_string.charAt(o);
419 if (s == 0 && c == TEXTFIELD.charAt(0)) {
420 ///ystem.err.println("Found T!");
421 s = 1;
422 }
423 else if (s == 1) {
424 if (c == TEXTFIELD.charAt(1)) {
425 ///ystem.err.println("Found X!");
426 s = 2;
427 }
428 else {
429 s = 0; // Reset
430 }
431 }
432 else if (s == 2) {
433 if (c == ':') {
434 ///ystem.err.println("Found TX:!");
435 s = 3;
436 }
437 else {
438 s = 0; // Reset
439 }
440 }
441 else if (s == 3) {
442 // Don't process phrases
443 if (c == '"') {
444 ///ystem.err.println("Stupid phrase...");
445 s = 0; // Reset
446 }
447 // Found the end of the term... add the
448 // fuzzy search indicator
449 // Nor outside the scope of parentheses
450 else if (Character.isWhitespace(c) || c == ')') {
451 ///ystem.err.println("Yahoo! Found fuzzy term.");
452 mutable_query_string.insert(o, '~' + fuzziness);
453 o++;
454 s = 0; // Reset
455 }
456 }
457 o++;
458 }
459 // If we were in the state of looking for the end of a
460 // term - then we just found it!
461 if (s == 3) {
462
463 mutable_query_string.append('~' + fuzziness);
464 }
465 // Reparse the query
466 ///ystem.err.println("Fuzzy query: " + mutable_query_string.toString() + query_suffix);
467 query = query_parser.parse(mutable_query_string.toString() + query_suffix);
468 }
469 else {
470 query = query_parser.parse(query_prefix + query_suffix);
471 }
472
473 return query;
474 }
475
476 protected Filter parseFilterString(String filter_string)
477 {
478 Filter result = null;
479 Pattern pattern = Pattern.compile("\\s*\\+(\\w+)\\:([\\{\\[])(\\d+)\\s+TO\\s+(\\d+)([\\}\\]])\\s*");
480 Matcher matcher = pattern.matcher(filter_string);
481 if (matcher.matches()) {
482 String field_name = matcher.group(1);
483 boolean include_lower = matcher.group(2).equals("[");
484 String lower_term = matcher.group(3);
485 String upper_term = matcher.group(4);
486 boolean include_upper = matcher.group(5).equals("]");
487 result = new TermRangeFilter(field_name, lower_term, upper_term, include_lower, include_upper);
488 }
489 else {
490 System.err.println("Error: Could not understand filter string \"" + filter_string + "\"");
491 }
492 return result;
493 }
494
495
496 /** command line program and auxiliary methods */
497
498 // Fairly self-explanatory I should hope
499 static protected boolean query_result_caching_enabled = false;
500
501
502 static public void main (String args[])
503 {
504 if (args.length == 0) {
505 System.out.println("Usage: GS2LuceneQuery <index directory> [-fuzziness value] [-filter filter_string] [-sort sort_field] [-reverse_sort][-dco AND|OR] [-startresults number -endresults number] [query]");
506 return;
507 }
508
509 try {
510 String index_directory = args[0];
511
512 GS2LuceneQuery queryer = new GS2LuceneQuery();
513 queryer.setIndexDir(index_directory);
514
515 // Prepare the index cache directory, if query result caching is enabled
516 if (query_result_caching_enabled) {
517 // Make the index cache directory if it doesn't already exist
518 File index_cache_directory = new File(index_directory, "cache");
519 if (!index_cache_directory.exists()) {
520 index_cache_directory.mkdir();
521 }
522
523 // Disable caching if the index cache directory isn't available
524 if (!index_cache_directory.exists() || !index_cache_directory.isDirectory()) {
525 query_result_caching_enabled = false;
526 }
527 }
528
529 String query_string = null;
530
531 // Parse the command-line arguments
532 for (int i = 1; i < args.length; i++) {
533 if (args[i].equals("-sort")) {
534 i++;
535 queryer.setSortField(args[i]);
536 }
537 else if (args[i].equals("-reverse_sort")) {
538 queryer.setReverseSort(true);
539 }
540 else if (args[i].equals("-filter")) {
541 i++;
542 queryer.setFilterString(args[i]);
543 }
544 else if (args[i].equals("-dco")) {
545 i++;
546 queryer.setDefaultConjunctionOperator(args[i]);
547 }
548 else if (args[i].equals("-fuzziness")) {
549 i++;
550 queryer.setFuzziness(args[i]);
551 }
552 else if (args[i].equals("-startresults")) {
553 i++;
554 if (args[i].matches("\\d+")) {
555 queryer.setStartResults(Integer.parseInt(args[i]));
556 }
557 }
558 else if (args[i].equals("-endresults")) {
559 i++;
560 if (args[i].matches("\\d+")) {
561 queryer.setEndResults(Integer.parseInt(args[i]));
562 }
563 }
564 else {
565 query_string = args[i];
566 }
567 }
568
569 if (!queryer.initialise()) {
570 return;
571 }
572
573 // The query string has been specified as a command-line argument
574 if (query_string != null) {
575 runQueryCaching(index_directory, queryer, query_string);
576 }
577
578 // Read queries from STDIN
579 else {
580 BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
581 while (true) {
582 // Read the query from STDIN
583 query_string = in.readLine();
584 if (query_string == null || query_string.length() == -1) {
585 break;
586 }
587
588 runQueryCaching(index_directory, queryer, query_string);
589
590 }
591 }
592 queryer.cleanUp();
593 }
594 catch (IOException exception) {
595 exception.printStackTrace();
596 }
597 }
598
599 protected static void runQueryCaching(String index_directory, GS2LuceneQuery queryer, String query_string)
600 throws IOException
601 {
602 StringBuffer query_results_xml = new StringBuffer();
603
604 // Check if this query result has been cached from a previous search (if it's enabled)
605 File query_result_cache_file = null;
606 if (query_result_caching_enabled) {
607 // Generate the cache file name from the query options
608 String query_result_cache_file_name = query_string + "-";
609 String fuzziness = queryer.getFuzziness();
610 query_result_cache_file_name += ((fuzziness != null) ? fuzziness : "") + "-";
611 String filter_string = queryer.getFilterString();
612 query_result_cache_file_name += ((filter_string != null) ? filter_string : "") + "-";
613 String sort_string = queryer.getSortField();
614 query_result_cache_file_name += ((sort_string != null) ? sort_string : "") + "-";
615 String reverse_sort_string = (queryer.getReverseSort() ? "1" : "0");
616 query_result_cache_file_name += reverse_sort_string + "-";
617 String default_conjunction_operator = queryer.getDefaultConjunctionOperator();
618 query_result_cache_file_name += default_conjunction_operator + "-";
619 int start_results = queryer.getStartResults();
620 int end_results = queryer.getEndResults();
621 query_result_cache_file_name += start_results + "-" + end_results;
622 query_result_cache_file_name = fileSafe(query_result_cache_file_name);
623
624 // If the query result cache file exists, just return its contents and we're done
625 File index_cache_directory = new File(index_directory, "cache");
626 query_result_cache_file = new File(index_cache_directory, query_result_cache_file_name);
627 if (query_result_cache_file.exists() && query_result_cache_file.isFile()) {
628 FileInputStream fis = new FileInputStream(query_result_cache_file);
629 InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
630 BufferedReader buffered_reader = new BufferedReader(isr);
631 String line = "";
632 while ((line = buffered_reader.readLine()) != null) {
633 query_results_xml.append(line + "\n");
634 }
635 String query_results_xml_string = query_results_xml.toString();
636 query_results_xml_string = query_results_xml_string.replaceFirst("cached=\"false\"", "cached=\"true\"");
637
638 utf8out.print(query_results_xml_string);
639 utf8out.flush();
640
641 return;
642 }
643 }
644
645 // not cached
646 query_results_xml.append("<ResultSet cached=\"false\">\n");
647 query_results_xml.append("<QueryString>" + LuceneQueryResult.xmlSafe(query_string) + "</QueryString>\n");
648 Filter filter = queryer.getFilter();
649 if (filter != null) {
650 query_results_xml.append("<FilterString>" + filter.toString() + "</FilterString>\n");
651 }
652
653 LuceneQueryResult query_result = queryer.runQuery(query_string);
654 if (query_result == null) {
655 System.err.println("Couldn't run the query");
656 return;
657 }
658
659 if (query_result.getError() != LuceneQueryResult.NO_ERROR) {
660 query_results_xml.append("<Error type=\""+query_result.getErrorString()+"\" />\n");
661 } else {
662 query_results_xml.append(query_result.getXMLString());
663 }
664 query_results_xml.append("</ResultSet>\n");
665
666 utf8out.print(query_results_xml);
667 utf8out.flush();
668
669 // Cache this query result, if desired
670 if (query_result_caching_enabled) {
671 // Catch any exceptions thrown trying to write the query result cache file and warn about them, but don't
672 // bother with the full stack trace. It won't affect the functionality if we can't write some cache
673 // files, it will just affect the speed of subsequent requests.
674 // Example exceptions are "permission denied" errors, or "filename too long" errors (the filter string
675 // can get very long in some collections)
676 try
677 {
678 FileWriter query_result_cache_file_writer = new FileWriter(query_result_cache_file);
679 query_result_cache_file_writer.write(query_results_xml.toString());
680 query_result_cache_file_writer.close();
681 }
682 catch (Exception exception)
683 {
684 System.err.println("Warning: Exception occurred trying to write query result cache file (" + exception + ")");
685 }
686 }
687 }
688
689 protected static String fileSafe(String text)
690 {
691 StringBuffer file_safe_text = new StringBuffer();
692 for (int i = 0; i < text.length(); i++) {
693 char character = text.charAt(i);
694 if ((character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || (character >= '0' && character <= '9') || character == '-') {
695 file_safe_text.append(character);
696 }
697 else {
698 file_safe_text.append('%');
699 file_safe_text.append((int) character);
700 }
701 }
702 return file_safe_text.toString();
703 }
704
705
706}
707
708
Note: See TracBrowser for help on using the repository browser.