1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.announce.service.announcesearch;
35
36 import java.io.IOException;
37 import java.nio.file.Paths;
38 import java.text.DecimalFormat;
39 import java.text.NumberFormat;
40 import java.util.ArrayList;
41 import java.util.Date;
42 import java.util.List;
43
44 import org.apache.commons.lang3.StringUtils;
45 import org.apache.lucene.analysis.Analyzer;
46 import org.apache.lucene.analysis.miscellaneous.LimitTokenCountAnalyzer;
47 import org.apache.lucene.index.DirectoryReader;
48 import org.apache.lucene.index.IndexReader;
49 import org.apache.lucene.index.IndexWriter;
50 import org.apache.lucene.index.IndexWriterConfig;
51 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
52 import org.apache.lucene.index.LogDocMergePolicy;
53 import org.apache.lucene.index.LogMergePolicy;
54 import org.apache.lucene.search.IndexSearcher;
55 import org.apache.lucene.store.Directory;
56 import org.apache.lucene.store.FSDirectory;
57
58 import fr.paris.lutece.plugins.announce.business.Announce;
59 import fr.paris.lutece.plugins.announce.business.AnnounceSearchFilter;
60 import fr.paris.lutece.plugins.announce.business.AnnounceSort;
61 import fr.paris.lutece.plugins.announce.business.IndexerAction;
62 import fr.paris.lutece.plugins.announce.business.IndexerActionFilter;
63 import fr.paris.lutece.plugins.announce.business.IndexerActionHome;
64 import fr.paris.lutece.plugins.announce.service.AnnouncePlugin;
65 import fr.paris.lutece.portal.service.plugin.Plugin;
66 import fr.paris.lutece.portal.service.plugin.PluginService;
67 import fr.paris.lutece.portal.service.search.SearchResult;
68 import fr.paris.lutece.portal.service.spring.SpringContextService;
69 import fr.paris.lutece.portal.service.util.AppException;
70 import fr.paris.lutece.portal.service.util.AppLogService;
71 import fr.paris.lutece.portal.service.util.AppPathService;
72 import fr.paris.lutece.portal.service.util.AppPropertiesService;
73
74
75
76
77 public final class AnnounceSearchService
78 {
79 private static final String BEAN_SEARCH_ENGINE = "announce.announceSearchEngine";
80 private static final String PATH_INDEX = "announce.internalIndexer.lucene.indexPath";
81 private static final String PROPERTY_WRITER_MERGE_FACTOR = "announce.internalIndexer.lucene.writer.mergeFactor";
82 private static final String PROPERTY_WRITER_MAX_FIELD_LENGTH = "announce.internalIndexer.lucene.writer.maxSectorLength";
83 private static final String PROPERTY_ANALYSER_CLASS_NAME = "announce.internalIndexer.lucene.analyser.className";
84 private static final String PROPERTY_INDEXER_PRICE_FORMAT = "announce.indexer.priceFormat";
85
86
87 private static final String CONSTANT_BLANK_SPACE = " ";
88 private static final String CONSTANT_COMA = ",";
89 private static final String CONSTANT_POINT = ".";
90 private static final String CONSTANT_EURO = "€";
91
92
93 private static final int DEFAULT_WRITER_MERGE_FACTOR = 20;
94 private static final int DEFAULT_WRITER_MAX_FIELD_LENGTH = 1000000;
95
96
97 private static volatile AnnounceSearchService _singleton;
98 private static String _strPriceFormat;
99 private volatile String _strIndex;
100 private Analyzer _analyzer;
101 private IAnnounceSearchIndexer _indexer;
102 private int _nWriterMergeFactor;
103 private int _nWriterMaxSectorLength;
104 private static volatile IndexWriter _indexWriterInstance;
105
106
107
108
109 private AnnounceSearchService( )
110 {
111
112 String strIndex = getIndex( );
113
114 if ( StringUtils.isEmpty( strIndex ) )
115 {
116 throw new AppException( "Lucene index path not found in announce.properties", null );
117 }
118
119 _nWriterMergeFactor = AppPropertiesService.getPropertyInt( PROPERTY_WRITER_MERGE_FACTOR, DEFAULT_WRITER_MERGE_FACTOR );
120 _nWriterMaxSectorLength = AppPropertiesService.getPropertyInt( PROPERTY_WRITER_MAX_FIELD_LENGTH, DEFAULT_WRITER_MAX_FIELD_LENGTH );
121
122 String strAnalyserClassName = AppPropertiesService.getProperty( PROPERTY_ANALYSER_CLASS_NAME );
123
124 if ( ( strAnalyserClassName == null ) || ( strAnalyserClassName.equals( "" ) ) )
125 {
126 throw new AppException( "Analyser class name not found in announce.properties", null );
127 }
128
129 _indexer = SpringContextService.getBean( "announce.announceIndexer" );
130
131 try
132 {
133 _analyzer = ( Analyzer ) Class.forName( strAnalyserClassName ).newInstance( );
134 }
135 catch( Exception e )
136 {
137 throw new AppException( "Failed to load Lucene Analyzer class", e );
138 }
139 }
140
141
142
143
144
145
146 public static AnnounceSearchService getInstance( )
147 {
148 if ( _singleton == null )
149 {
150 _singleton = new AnnounceSearchService( );
151 }
152
153 return _singleton;
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 public int getSearchResults( AnnounceSearchFilter filter, int nPageNumber, int nItemsPerPage, List<Integer> listIdAnnounces )
170 {
171 int nNbItems = 0;
172
173 try
174 {
175 IAnnounceSearchEngine engine = SpringContextService.getBean( BEAN_SEARCH_ENGINE );
176 List<SearchResult> listResults = new ArrayList<>( );
177 nNbItems = engine.getSearchResults( filter, PluginService.getPlugin( AnnouncePlugin.PLUGIN_NAME ), listResults, nPageNumber, nItemsPerPage );
178
179 for ( SearchResult searchResult : listResults )
180 {
181 if ( searchResult.getId( ) != null )
182 {
183 listIdAnnounces.add( Integer.parseInt( searchResult.getId( ) ) );
184 }
185 }
186 }
187 catch( Exception e )
188 {
189 AppLogService.error( e.getMessage( ), e );
190
191 listIdAnnounces.clear( );
192 }
193
194 return nNbItems;
195 }
196
197 public int getSearchResultsBis( AnnounceSearchFilter filter, int nPageNumber, int nItemsPerPage, List<Announce> listAnnouncesResults, AnnounceSort anSort )
198 {
199 int nNbItems = 0;
200
201 try
202 {
203 IAnnounceSearchEngine engine = SpringContextService.getBean( BEAN_SEARCH_ENGINE );
204 nNbItems = engine.getSearchResultsBis( filter, PluginService.getPlugin( AnnouncePlugin.PLUGIN_NAME ), listAnnouncesResults, nPageNumber,
205 nItemsPerPage, anSort );
206
207 }
208 catch( Exception e )
209 {
210 AppLogService.error( e.getMessage( ), e );
211
212 listAnnouncesResults.clear( );
213 }
214
215 return nNbItems;
216 }
217
218
219
220
221
222
223 public IndexSearcher getSearcher( )
224 {
225 IndexSearcher searcher = null;
226
227 try
228 {
229 IndexReader ir = DirectoryReader.open( FSDirectory.open( Paths.get( getIndex( ) ) ) );
230 searcher = new IndexSearcher( ir );
231 }
232 catch( IOException e )
233 {
234 AppLogService.error( e.getMessage( ), e );
235 }
236
237 return searcher;
238 }
239
240
241
242
243
244
245
246
247 public String processIndexing( boolean bCreate )
248 {
249 StringBuffer sbLogs = new StringBuffer( );
250 IndexWriter writer = null;
251 boolean bCreateIndex = bCreate;
252
253 try
254 {
255 sbLogs.append( "\r\nIndexing all contents ...\r\n" );
256
257 Directory dir = FSDirectory.open( Paths.get( getIndex( ) ) );
258 if ( !DirectoryReader.indexExists( dir ) )
259 {
260 bCreateIndex = true;
261 }
262
263 writer = getIndexWriterInstance( bCreateIndex );
264
265 Date start = new Date( );
266
267 sbLogs.append( "\r\n<strong>Indexer : " );
268 sbLogs.append( _indexer.getName( ) );
269 sbLogs.append( " - " );
270 sbLogs.append( _indexer.getDescription( ) );
271 sbLogs.append( "</strong>\r\n" );
272 _indexer.processIndexing( writer, bCreateIndex, sbLogs );
273
274 Date end = new Date( );
275
276 sbLogs.append( "Duration of the treatment : " );
277 sbLogs.append( end.getTime( ) - start.getTime( ) );
278 sbLogs.append( " milliseconds\r\n" );
279 }
280 catch( Exception e )
281 {
282 sbLogs.append( " caught a " );
283 sbLogs.append( e.getClass( ) );
284 sbLogs.append( "\n with message: " );
285 sbLogs.append( e.getMessage( ) );
286 sbLogs.append( "\r\n" );
287 AppLogService.error( "Indexing error : " + e.getMessage( ), e );
288 }
289 finally
290 {
291 try
292 {
293 closeIndexWriterInstance( );
294 }
295 catch( IOException e )
296 {
297 AppLogService.error( e.getMessage( ), e );
298 }
299 }
300
301 return sbLogs.toString( );
302 }
303
304
305
306
307
308
309
310
311
312
313
314 public void addIndexerAction( int nIdAnnounce, int nIdTask, Plugin plugin )
315 {
316 IndexerActionbusiness/IndexerAction.html#IndexerAction">IndexerAction indexerAction = new IndexerAction( );
317 indexerAction.setIdAnnounce( nIdAnnounce );
318 indexerAction.setIdTask( nIdTask );
319 IndexerActionHome.create( indexerAction );
320 }
321
322
323
324
325
326
327
328
329
330 public void removeIndexerAction( int nIdAction, Plugin plugin )
331 {
332 IndexerActionHome.remove( nIdAction );
333 }
334
335
336
337
338
339
340
341
342
343
344 public List<IndexerAction> getAllIndexerActionByTask( int nIdTask, Plugin plugin )
345 {
346 IndexerActionFilter/business/IndexerActionFilter.html#IndexerActionFilter">IndexerActionFilter filter = new IndexerActionFilter( );
347 filter.setIdTask( nIdTask );
348
349 return IndexerActionHome.getList( filter );
350 }
351
352
353
354
355
356
357 private String getIndex( )
358 {
359 if ( _strIndex == null )
360 {
361 _strIndex = AppPathService.getPath( PATH_INDEX );
362 }
363
364 return _strIndex;
365 }
366
367
368
369
370
371
372 public Analyzer getAnalyzer( )
373 {
374 return _analyzer;
375 }
376
377
378
379
380
381
382
383
384 public static String formatPriceForIndexer( double dPrice )
385 {
386 NumberFormat formatter = new DecimalFormat( getPriceFormat( ) );
387
388 return formatter.format( dPrice );
389 }
390
391
392
393
394
395
396
397
398 public static String getFormatedPriceString( String strPrice )
399 {
400 return strPrice.replace( CONSTANT_BLANK_SPACE, StringUtils.EMPTY ).replace( CONSTANT_COMA, CONSTANT_POINT ).replace( CONSTANT_EURO, StringUtils.EMPTY )
401 .trim( );
402 }
403
404
405
406
407
408
409
410
411 public static String formatPriceForIndexer( int nPrice )
412 {
413 NumberFormat formatter = new DecimalFormat( getPriceFormat( ) );
414
415 return formatter.format( nPrice );
416 }
417
418
419
420
421
422
423 private static String getPriceFormat( )
424 {
425 if ( _strPriceFormat == null )
426 {
427 _strPriceFormat = AppPropertiesService.getProperty( PROPERTY_INDEXER_PRICE_FORMAT, "#0000000000.00" );
428 }
429
430 return _strPriceFormat;
431 }
432
433 private synchronized IndexWriter getIndexWriterInstance( boolean bCreateIndex ) throws IOException
434 {
435 if ( _indexWriterInstance == null )
436 {
437 Directory dir = FSDirectory.open(Paths.get( getIndex( ) ) );
438 IndexWriterConfig conf = new IndexWriterConfig( new LimitTokenCountAnalyzer( _analyzer, _nWriterMaxSectorLength ) );
439 LogMergePolicy mergePolicy = new LogDocMergePolicy( );
440 mergePolicy.setMergeFactor( _nWriterMergeFactor );
441 conf.setMergePolicy(mergePolicy);
442 if (bCreateIndex)
443 {
444 conf.setOpenMode( OpenMode.CREATE );
445 }
446 else
447 {
448 conf.setOpenMode( OpenMode.APPEND );
449 }
450
451 _indexWriterInstance = new IndexWriter( dir, conf );
452 }
453 return _indexWriterInstance;
454 }
455
456 private synchronized void closeIndexWriterInstance( ) throws IOException
457 {
458 if ( _indexWriterInstance != null )
459 {
460 _indexWriterInstance.close( );
461 _indexWriterInstance = null;
462 }
463 }
464 }