27
27
import java .io .FileNotFoundException ;
28
28
import java .io .IOException ;
29
29
import java .util .ArrayList ;
30
- import java .util .Arrays ;
31
30
import java .util .List ;
32
31
import java .util .Map ;
33
32
import java .util .Set ;
42
41
import org .apache .lucene .index .DirectoryReader ;
43
42
import org .apache .lucene .index .IndexReader ;
44
43
import org .apache .lucene .index .MultiReader ;
44
+ import org .apache .lucene .index .Term ;
45
45
import org .apache .lucene .queryparser .classic .ParseException ;
46
46
import org .apache .lucene .search .*;
47
- import org .apache .lucene .search .spell .SpellChecker ;
47
+ import org .apache .lucene .search .spell .DirectSpellChecker ;
48
+ import org .apache .lucene .search .spell .SuggestMode ;
49
+ import org .apache .lucene .search .spell .SuggestWord ;
48
50
import org .apache .lucene .store .FSDirectory ;
49
51
import org .opensolaris .opengrok .OpenGrokLogger ;
50
52
import org .opensolaris .opengrok .analysis .CompatibleAnalyser ;
64
66
*/
65
67
public class SearchHelper {
66
68
69
+ /**
70
+ * max number of words to suggest for spellcheck
71
+ */
72
+ public int SPELLCHECK_SUGGEST_WORD_COUNT =5 ;
67
73
/**
68
74
* opengrok's data root: used to find the search index file
69
75
*/
@@ -128,7 +134,7 @@ public class SearchHelper {
128
134
* the searcher used to open/search the index. Automatically set via
129
135
* {@link #prepareExec(SortedSet)}.
130
136
*/
131
- public IndexSearcher searcher ;
137
+ public IndexSearcher searcher ;
132
138
/**
133
139
* list of docs which result from the executing the query
134
140
*/
@@ -147,6 +153,10 @@ public class SearchHelper {
147
153
* {@link #prepareExec(SortedSet)}.
148
154
*/
149
155
protected Sort sort ;
156
+ /**
157
+ * the spellchecker object
158
+ */
159
+ protected DirectSpellChecker checker ;
150
160
/**
151
161
* projects to use to setup indexer searchers. Usually setup via
152
162
* {@link #prepareExec(SortedSet)}.
@@ -211,7 +221,8 @@ public class SearchHelper {
211
221
public static Set <Map .Entry <String , String >> getFileTypeDescirptions () {
212
222
return fileTypeDescription .entrySet ();
213
223
}
214
-
224
+
225
+ File indexDir ;
215
226
/**
216
227
* Create the searcher to use wrt. to currently set parameters and the given
217
228
* projects. Does not produce any {@link #redirect} link. It also does
@@ -235,13 +246,13 @@ public SearchHelper prepareExec(SortedSet<String> projects) {
235
246
}
236
247
// the Query created by the QueryBuilder
237
248
try {
249
+ indexDir =new File (dataRoot , "index" );
238
250
query = builder .build ();
239
251
if (projects == null ) {
240
252
errorMsg = "No project selected!" ;
241
253
return this ;
242
254
}
243
- this .projects = projects ;
244
- File indexDir = new File (dataRoot , "index" );
255
+ this .projects = projects ;
245
256
if (projects .isEmpty ()) {
246
257
//no project setup
247
258
FSDirectory dir = FSDirectory .open (indexDir );
@@ -285,6 +296,7 @@ public SearchHelper prepareExec(SortedSet<String> projects) {
285
296
sort = Sort .RELEVANCE ;
286
297
break ;
287
298
}
299
+ checker =new DirectSpellChecker ();
288
300
} catch (ParseException e ) {
289
301
errorMsg = PARSE_ERROR_MSG + e .getMessage ();
290
302
} catch (FileNotFoundException e ) {
@@ -357,17 +369,20 @@ public SearchHelper executeQuery() {
357
369
}
358
370
private static final Pattern TABSPACE = Pattern .compile ("[\t ]+" );
359
371
360
- private static void getSuggestion (String term , SpellChecker checker ,
372
+ private void getSuggestion (Term term , IndexReader ir ,
361
373
List <String > result ) throws IOException {
362
374
if (term == null ) {
363
375
return ;
364
376
}
365
- String [] toks = TABSPACE .split (term , 0 );
377
+ String [] toks = TABSPACE .split (term . text () , 0 );
366
378
for (int j = 0 ; j < toks .length ; j ++) {
367
- if (toks [j ].length () <= 3 ) {
368
- continue ;
369
- }
370
- result .addAll (Arrays .asList (checker .suggestSimilar (toks [j ].toLowerCase (), 5 )));
379
+ //TODO below seems to be case insensitive ... for refs/defs this is bad
380
+ SuggestWord [] words =checker .suggestSimilar (
381
+ new Term (term .field (),toks [j ]), SPELLCHECK_SUGGEST_WORD_COUNT , ir ,
382
+ SuggestMode .SUGGEST_ALWAYS );
383
+ for (SuggestWord w : words ) {
384
+ result .add (w .string );
385
+ }
371
386
}
372
387
}
373
388
@@ -379,74 +394,78 @@ private static void getSuggestion(String term, SpellChecker checker,
379
394
* <li>{@link #projects}</li> <li>{@link #dataRoot}</li>
380
395
* <li>{@link #builder}</li> </ul>
381
396
*
382
- * @return a possible empty list of sugeestions .
397
+ * @return a possible empty list of suggestions .
383
398
*/
384
399
public List <Suggestion > getSuggestions () {
385
400
if (projects == null ) {
386
- return new ArrayList <Suggestion >(0 );
401
+ return new ArrayList <>(0 );
387
402
}
388
- File [] spellIndex = null ;
403
+ String name [] ;
389
404
if (projects .isEmpty ()) {
390
- spellIndex = new File []{new File ( dataRoot , "spellIndex" ) };
405
+ name = new String []{"/" };
391
406
} else if (projects .size () == 1 ) {
392
- spellIndex = new File []{
393
- new File (dataRoot , "spellIndex/" + projects .first ())
394
- };
407
+ name =new String []{projects .first ()};
395
408
} else {
396
- spellIndex = new File [projects .size ()];
397
- int ii = 0 ;
398
- File indexDir = new File (dataRoot , "spellIndex" );
409
+ name = new String [projects .size ()];
410
+ int ii = 0 ;
399
411
for (String proj : projects ) {
400
- spellIndex [ii ++] = new File ( indexDir , proj ) ;
412
+ name [ii ++] = proj ;
401
413
}
402
414
}
403
- List <Suggestion > res = new ArrayList <Suggestion >();
404
- List <String > dummy = new ArrayList <String >();
405
- for (int idx = 0 ; idx < spellIndex .length ; idx ++) {
406
- if (!spellIndex [idx ].exists ()) {
407
- continue ;
408
- }
409
- FSDirectory spellDirectory = null ;
410
- SpellChecker checker = null ;
411
- Suggestion s = new Suggestion (spellIndex [idx ].getName ());
415
+ List <Suggestion > res = new ArrayList <>();
416
+ List <String > dummy = new ArrayList <>();
417
+ FSDirectory dir ;
418
+ IndexReader ir =null ;
419
+ Term t ;
420
+ for (int idx = 0 ; idx < name .length ; idx ++) {
421
+ Suggestion s = new Suggestion (name [idx ]);
412
422
try {
413
- spellDirectory = FSDirectory .open (spellIndex [idx ]);
414
- checker = new SpellChecker (spellDirectory );
415
- getSuggestion (builder .getFreetext (), checker , dummy );
423
+ dir = FSDirectory .open (new File (indexDir , name [idx ]));
424
+ ir = DirectoryReader .open (dir );
425
+ if (builder .getFreetext ()!=null &&
426
+ !builder .getFreetext ().isEmpty ()) {
427
+ t =new Term (QueryBuilder .FULL ,builder .getFreetext ());
428
+ getSuggestion (t , ir , dummy );
416
429
s .freetext = dummy .toArray (new String [dummy .size ()]);
417
430
dummy .clear ();
418
- getSuggestion (builder .getRefs (), checker , dummy );
431
+ }
432
+ if (builder .getRefs ()!=null && !builder .getRefs ().isEmpty ()) {
433
+ t =new Term (QueryBuilder .REFS ,builder .getRefs ());
434
+ getSuggestion (t , ir , dummy );
419
435
s .refs = dummy .toArray (new String [dummy .size ()]);
420
436
dummy .clear ();
421
- // TODO it seems the only true spellchecker is for
422
- // below field, see IndexDatabase
423
- // createspellingsuggestions ...
424
- getSuggestion (builder . getDefs (), checker , dummy );
437
+ }
438
+ if ( builder . getDefs ()!= null && ! builder . getDefs (). isEmpty ()) {
439
+ t = new Term ( QueryBuilder . DEFS , builder . getDefs ());
440
+ getSuggestion (t , ir , dummy );
425
441
s .defs = dummy .toArray (new String [dummy .size ()]);
426
442
dummy .clear ();
427
- if (s .freetext .length > 0 || s .defs .length > 0 || s .refs .length > 0 ) {
443
+ }
444
+ //TODO suggest also for path and history?
445
+ if ((s .freetext !=null && s .freetext .length > 0 ) ||
446
+ (s .defs !=null && s .defs .length > 0 ) ||
447
+ (s .refs !=null && s .refs .length > 0 ) ) {
428
448
res .add (s );
429
449
}
430
450
} catch (IOException e ) {
431
- log .log (Level .WARNING , "Got excption while getting spelling suggestions: " , e );
451
+ log .log (Level .WARNING , "Got exception while getting "
452
+ + "spelling suggestions: " , e );
432
453
} finally {
433
- if (spellDirectory != null ) {
434
- spellDirectory .close ();
435
- }
436
- if (checker != null ) {
437
- try {
438
- checker .close ();
439
- } catch (Exception x ) {
440
- log .log (Level .WARNING , "Got excption while closing spelling suggestions: " , x );
441
- }
442
- }
443
- }
444
- }
454
+ if (ir != null ) {
455
+ try {
456
+ ir .close ();
457
+ } catch (IOException ex ) {
458
+ log .log (Level .WARNING , "Got exception while "
459
+ + "getting spelling suggestions: " , ex );
460
+ }
461
+ }
462
+ }
463
+ }
445
464
return res ;
446
465
}
447
466
448
467
/**
449
- * Prepare the fields to support printing a fullblown summary. Does nothing
468
+ * Prepare the fields to support printing a full blown summary. Does nothing
450
469
* if {@link #redirect} or {@link #errorMsg} have a none-{@code null} value.
451
470
*
452
471
* <p> Parameters which should be populated/set at this time: <ul>
0 commit comments