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.portal.service.search;
35
36 import fr.paris.lutece.portal.business.page.Page;
37 import fr.paris.lutece.portal.service.security.LuteceUser;
38 import fr.paris.lutece.portal.service.security.SecurityService;
39 import fr.paris.lutece.portal.service.util.AppLogService;
40 import fr.paris.lutece.util.date.DateUtil;
41
42 import org.apache.commons.lang.StringUtils;
43
44 import org.apache.lucene.document.DateTools;
45 import org.apache.lucene.document.DateTools.Resolution;
46 import org.apache.lucene.document.Document;
47 import org.apache.lucene.index.DirectoryReader;
48 import org.apache.lucene.index.IndexReader;
49 import org.apache.lucene.index.Term;
50 import org.apache.lucene.queries.ChainedFilter;
51 import org.apache.lucene.queryparser.classic.QueryParser;
52 import org.apache.lucene.search.BooleanClause;
53 import org.apache.lucene.search.BooleanQuery;
54 import org.apache.lucene.search.CachingWrapperFilter;
55 import org.apache.lucene.search.Filter;
56 import org.apache.lucene.search.IndexSearcher;
57 import org.apache.lucene.search.Query;
58 import org.apache.lucene.search.QueryWrapperFilter;
59 import org.apache.lucene.search.ScoreDoc;
60 import org.apache.lucene.search.TermQuery;
61 import org.apache.lucene.search.TermRangeQuery;
62 import org.apache.lucene.search.TopDocs;
63 import org.apache.lucene.util.BytesRef;
64
65 import java.text.ParseException;
66
67 import java.util.ArrayList;
68 import java.util.Date;
69 import java.util.List;
70
71 import javax.servlet.http.HttpServletRequest;
72
73
74
75
76
77 public class LuceneSearchEngine implements SearchEngine
78 {
79 public static final int MAX_RESPONSES = 1000000;
80 private static final String PARAMETER_TYPE_FILTER = "type_filter";
81 private static final String PARAMETER_DATE_AFTER = "date_after";
82 private static final String PARAMETER_DATE_BEFORE = "date_before";
83 private static final String PARAMETER_TAG_FILTER = "tag_filter";
84 private static final String PARAMETER_DEFAULT_OPERATOR = "default_operator";
85 private static final String PARAMETER_OPERATOR_AND = "AND";
86
87
88
89
90
91
92
93
94 public List<SearchResult> getSearchResults( String strQuery, HttpServletRequest request )
95 {
96 ArrayList<SearchItem> listResults = new ArrayList<SearchItem>( );
97 ArrayList<Filter> listFilter = new ArrayList<Filter>( );
98 IndexSearcher searcher = null;
99 boolean bFilterResult = false;
100 LuteceUser user = null;
101 String[] typeFilter = request.getParameterValues( PARAMETER_TYPE_FILTER );
102 String strDateAfter = request.getParameter( PARAMETER_DATE_AFTER );
103 String strDateBefore = request.getParameter( PARAMETER_DATE_BEFORE );
104 boolean bDateAfter = false;
105 boolean bDateBefore = false;
106 Filter allFilter = null;
107 String strTagFilter = request.getParameter( PARAMETER_TAG_FILTER );
108
109 if ( SecurityService.isAuthenticationEnable( ) )
110 {
111 user = SecurityService.getInstance( ).getRegisteredUser( request );
112
113 Filter[] filtersRole = null;
114
115 if ( user != null )
116 {
117 String[] userRoles = SecurityService.getInstance( ).getRolesByUser( user );
118
119 if ( userRoles != null )
120 {
121 filtersRole = new Filter[userRoles.length + 1];
122
123 for ( int i = 0; i < userRoles.length; i++ )
124 {
125 Query queryRole = new TermQuery( new Term( SearchItem.FIELD_ROLE, userRoles[i] ) );
126 filtersRole[i] = new CachingWrapperFilter( new QueryWrapperFilter( queryRole ) );
127 }
128 }
129 else
130 {
131 bFilterResult = true;
132 }
133 }
134 else
135 {
136 filtersRole = new Filter[1];
137 }
138
139 if ( !bFilterResult )
140 {
141 Query queryRole = new TermQuery( new Term( SearchItem.FIELD_ROLE, Page.ROLE_NONE ) );
142 filtersRole[filtersRole.length - 1] = new CachingWrapperFilter( new QueryWrapperFilter( queryRole ) );
143 listFilter.add( new ChainedFilter( filtersRole, ChainedFilter.OR ) );
144 }
145 }
146
147 if ( StringUtils.isNotBlank( strDateAfter ) || StringUtils.isNotBlank( strDateBefore ) )
148 {
149 BytesRef strAfter = null;
150 BytesRef strBefore = null;
151
152 if ( StringUtils.isNotBlank( strDateAfter ) )
153 {
154 Date dateAfter = DateUtil.formatDate( strDateAfter, request.getLocale( ) );
155 strAfter = new BytesRef( DateTools.dateToString( dateAfter, Resolution.DAY ) );
156 bDateAfter = true;
157 }
158
159 if ( StringUtils.isNotBlank( strDateBefore ) )
160 {
161 Date dateBefore = DateUtil.formatDate( strDateBefore, request.getLocale( ) );
162 strBefore = new BytesRef( DateTools.dateToString( dateBefore, Resolution.DAY ) );
163 bDateBefore = true;
164 }
165
166 Query queryDate = new TermRangeQuery( SearchItem.FIELD_DATE, strAfter, strBefore, bDateAfter, bDateBefore );
167 listFilter.add( new CachingWrapperFilter( new QueryWrapperFilter( queryDate ) ) );
168 }
169
170 if ( ( typeFilter != null ) && ( typeFilter.length > 0 ) &&
171 !typeFilter[0].equals( SearchService.TYPE_FILTER_NONE ) )
172 {
173 Filter[] filtersType = new Filter[typeFilter.length];
174
175 for ( int i = 0; i < typeFilter.length; i++ )
176 {
177 Query queryType = new TermQuery( new Term( SearchItem.FIELD_TYPE, typeFilter[i] ) );
178 filtersType[i] = new CachingWrapperFilter( new QueryWrapperFilter( queryType ) );
179 }
180
181 listFilter.add( new ChainedFilter( filtersType, ChainedFilter.OR ) );
182 }
183
184 if ( !listFilter.isEmpty( ) )
185 {
186 allFilter = new ChainedFilter( listFilter.toArray( new Filter[1] ), ChainedFilter.AND );
187 }
188
189 try
190 {
191 IndexReader ir = DirectoryReader.open( IndexationService.getDirectoryIndex( ) );
192 searcher = new IndexSearcher( ir );
193
194 Query query = null;
195
196 if ( StringUtils.isNotBlank( strTagFilter ) )
197 {
198 BooleanQuery bQuery = new BooleanQuery( );
199 QueryParser parser = new QueryParser( IndexationService.LUCENE_INDEX_VERSION,
200 SearchItem.FIELD_METADATA, IndexationService.getAnalyser( ) );
201
202 Query queryMetaData = parser.parse( ( strQuery != null ) ? strQuery : "" );
203 bQuery.add( queryMetaData, BooleanClause.Occur.SHOULD );
204
205 parser = new QueryParser( IndexationService.LUCENE_INDEX_VERSION, SearchItem.FIELD_SUMMARY,
206 IndexationService.getAnalyser( ) );
207
208 Query querySummary = parser.parse( ( strQuery != null ) ? strQuery : "" );
209 bQuery.add( querySummary, BooleanClause.Occur.SHOULD );
210 query = bQuery;
211 }
212 else
213 {
214 QueryParser parser = new QueryParser( IndexationService.LUCENE_INDEX_VERSION,
215 SearchItem.FIELD_CONTENTS, IndexationService.getAnalyser( ) );
216
217 String operator = request.getParameter( PARAMETER_DEFAULT_OPERATOR );
218
219 if ( StringUtils.isNotEmpty( operator ) && operator.equals( PARAMETER_OPERATOR_AND ) )
220 {
221 parser.setDefaultOperator( QueryParser.AND_OPERATOR );
222 }
223
224 query = parser.parse( ( StringUtils.isNotBlank( strQuery ) ) ? strQuery : "" );
225 }
226
227
228 TopDocs topDocs = searcher.search( query, allFilter, MAX_RESPONSES );
229 ScoreDoc[] hits = topDocs.scoreDocs;
230
231 for ( int i = 0; i < hits.length; i++ )
232 {
233 int docId = hits[i].doc;
234 Document document = searcher.doc( docId );
235 SearchItem si = new SearchItem( document );
236
237 if ( ( !bFilterResult ) || ( si.getRole( ).equals( Page.ROLE_NONE ) ) ||
238 ( SecurityService.getInstance( ).isUserInRole( request, si.getRole( ) ) ) )
239 {
240 listResults.add( si );
241 }
242 }
243 }
244 catch ( Exception e )
245 {
246 AppLogService.error( e.getMessage( ), e );
247 }
248
249 return convertList( listResults );
250 }
251
252
253
254
255
256
257 private List<SearchResult> convertList( List<SearchItem> listSource )
258 {
259 List<SearchResult> listDest = new ArrayList<SearchResult>( );
260
261 for ( SearchItem item : listSource )
262 {
263 SearchResult result = new SearchResult( );
264 result.setId( item.getId( ) );
265
266 try
267 {
268 result.setDate( DateTools.stringToDate( item.getDate( ) ) );
269 }
270 catch ( ParseException e )
271 {
272 AppLogService.error( "Bad Date Format for indexed item \"" + item.getTitle( ) + "\" : " +
273 e.getMessage( ) );
274 }
275
276 result.setUrl( item.getUrl( ) );
277 result.setTitle( item.getTitle( ) );
278 result.setSummary( item.getSummary( ) );
279 result.setType( item.getType( ) );
280 listDest.add( result );
281 }
282
283 return listDest;
284 }
285 }