1 /*****************************************************************************
5 * Creation date 05.10.2012
8 *****************************************************************************/
10 package org.splat.service;
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
18 import org.apache.log4j.Logger;
19 import org.apache.lucene.index.Term;
20 import org.apache.lucene.search.BooleanClause;
21 import org.apache.lucene.search.BooleanFilter;
22 import org.apache.lucene.search.BooleanQuery;
23 import org.apache.lucene.search.FilterClause;
24 import org.apache.lucene.search.IndexSearcher;
25 import org.apache.lucene.search.ScoreDoc;
26 import org.apache.lucene.search.Sort;
27 import org.apache.lucene.search.SortField;
28 import org.apache.lucene.search.TermQuery;
29 import org.apache.lucene.search.TermsFilter;
30 import org.apache.lucene.search.TopFieldDocs;
31 import org.apache.lucene.store.Directory;
32 import org.apache.lucene.store.FSDirectory;
33 import org.splat.dal.bo.kernel.User;
34 import org.splat.dal.bo.som.KnowledgeElement;
35 import org.splat.dal.bo.som.KnowledgeElementType;
36 import org.splat.dal.bo.som.ProgressState;
37 import org.splat.dal.bo.som.Scenario;
38 import org.splat.dal.bo.som.SimulationContext;
39 import org.splat.dal.bo.som.Study;
40 import org.splat.dal.bo.som.Visibility;
41 import org.splat.dal.dao.som.StudyDAO;
42 import org.splat.service.dto.ImportedStudyDTO;
43 import org.splat.service.dto.Proxy;
44 import org.splat.service.technical.IndexService;
45 import org.splat.service.technical.IndexServiceImpl;
46 import org.splat.service.technical.RepositoryService;
47 import org.splat.util.BeanHelper;
48 import org.springframework.transaction.annotation.Transactional;
51 * Search service implementation.
53 * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
55 public class SearchServiceImpl implements SearchService {
60 public final static Logger LOG = Logger
61 .getLogger(org.splat.service.SearchServiceImpl.class);
64 * Injected repository service.
66 private RepositoryService _repositoryService;
68 * Injected index service.
70 private IndexService _indexService;
72 * Injected study service.
74 private StudyService _studyService;
78 private StudyDAO _studyDAO;
81 * Get a list of studies which are currently not presented in the lucene index.
82 * @return list of ImportedStudy DTO
84 @Transactional(readOnly=true)
85 public List<ImportedStudyDTO> selectStudies() {
86 List<ImportedStudyDTO> table = new ArrayList<ImportedStudyDTO>();
87 Study.Properties sprop = new Study.Properties();
88 List<Study> dbStudies = getStudyDAO().getAll();
90 for (Study aStudy : dbStudies) {
93 if (selectStudiesWhere(
94 sprop.setReference(aStudy.getReference())).size() != 0) {
95 // If this study was already indexed and found in the lucene index
96 // then skip it to avoid adding to the index it again.
99 } catch (Exception error) {
102 // Add the study to the list of studies which are
103 // currently not presented in the lucene index.
104 table.add(BeanHelper.copyBean(aStudy, ImportedStudyDTO.class));
110 * Refresh lucene index for studies.
113 * list of studies id's
115 @Transactional(readOnly = true)
116 public void reindexStudies(final String[] ridlist) {
117 for (int i = 0; i < ridlist.length; i++) {
118 long index = Long.valueOf(ridlist[i].trim());
119 Study study = getStudyService().selectStudy(index);
127 * @see org.splat.service.SearchService#selectKnowledgeElementsWhere(org.splat.dal.bo.som.KnowledgeElement.Properties[])
129 public List<Proxy> selectKnowledgeElementsWhere(
130 final KnowledgeElement.Properties... kprop) {
131 List<Proxy> result = new ArrayList<Proxy>();
135 // Creation of the Lucene query
136 File indir = getRepositoryService().getRepositoryIndexDirectory();
137 Directory index = FSDirectory.open(indir);
138 IndexSearcher searcher = new IndexSearcher(index, true);
139 BooleanQuery fulquery = new BooleanQuery();
141 for (int i = 0; i < kprop.length; i++) {
142 BooleanQuery query = new BooleanQuery();
143 Term input; // Supposed initialized below at least by the visibility
145 Visibility area = kprop[i].getVisibility(); // Visibility
147 input = new Term("area");
148 query.add(new TermQuery(input.createTerm(area.toString())),
149 BooleanClause.Occur.MUST);
151 ProgressState state = kprop[i].getProgressState(); // State
153 input = new Term("state");
155 new TermQuery(input.createTerm(state.toString())),
156 BooleanClause.Occur.MUST);
158 String refid = kprop[i].getReference(); // Reference
160 input = new Term("ref");
161 query.add(new TermQuery(input.createTerm(refid)),
162 BooleanClause.Occur.MUST);
164 KnowledgeElementType type = kprop[i].getType(); // Type
166 input = new Term("type");
167 query.add(new TermQuery(input.createTerm(type.getName())),
168 BooleanClause.Occur.MUST);
170 User manager = kprop[i].getAuthor(); // Author
171 if (manager != null) {
172 input = new Term("author");
173 query.add(new TermQuery(input
174 .createTerm(manager.toString())),
175 BooleanClause.Occur.MUST);
177 User actor = kprop[i].getActor(); // Contributor, Reviewer or Approver of the owner study
179 input = new Term("actor");
181 new TermQuery(input.createTerm(actor.toString())),
182 BooleanClause.Occur.MUST);
184 String title = kprop[i].getTitle(); // Title
186 input = new Term("contents");
187 BooleanQuery critext = new BooleanQuery();
188 String operator = "AND"; // Future user input
189 BooleanClause.Occur clause = BooleanClause.Occur.MUST;
190 if (operator.equals("OR")) {
191 clause = BooleanClause.Occur.SHOULD;
193 String[] word = title.split(" ");
194 for (int j = 0; j < word.length; j++) {
195 critext.add(new TermQuery(input.createTerm(word[j])),
198 query.add(critext, BooleanClause.Occur.MUST);
200 List<SimulationContext> context = kprop[i]
201 .getSimulationContexts();
202 if (context != null && context.size() > 0) {
203 BooleanQuery critext = new BooleanQuery();
204 for (Iterator<SimulationContext> j = context.iterator(); j
206 SimulationContext seltext = j.next();
207 input = new Term(String.valueOf(seltext.getType()
209 critext.add(new TermQuery(input.createTerm(seltext
210 .getValue())), BooleanClause.Occur.MUST);
212 query.add(critext, BooleanClause.Occur.MUST);
214 fulquery.add(query, BooleanClause.Occur.SHOULD);
216 if (LOG.isInfoEnabled()) {
217 LOG.info("Searching knowledges by Lucene query \""
218 + fulquery.toString() + "\".");
220 // Creation of the knowledge filter
221 BooleanFilter filter = new BooleanFilter();
222 TermsFilter select = new TermsFilter();
223 Term mytype = new Term("class");
224 select.addTerm(mytype.createTerm("KnowledgeElement"));
225 filter.add(new FilterClause(select, BooleanClause.Occur.SHOULD));
227 // Creation of the sort criteria
228 Sort sort = new Sort(new SortField("title", SortField.STRING));
231 TopFieldDocs found = searcher.search(fulquery, filter, hitsize,
234 if (found.totalHits < 1) {
235 return result; // No study found
238 // Construction of the result list
239 ScoreDoc[] hits = found.scoreDocs;
240 for (int i = 0; i < hits.length; i++) {
241 result.add(new IndexServiceImpl.ObjectProxy(searcher
245 } catch (Exception error) {
246 LOG.error("Error during Lucene search, reason:", error);
254 * @see org.splat.service.SearchService#selectStudiesWhere(org.splat.dal.bo.som.Study.Properties[])
256 public List<Proxy> selectStudiesWhere(final Study.Properties... sprop) {
257 List<Proxy> result = new ArrayList<Proxy>();
261 // Creation of the Lucene query
262 File indir = getRepositoryService().getRepositoryIndexDirectory();
263 Directory index = FSDirectory.open(indir);
264 IndexSearcher searcher = new IndexSearcher(index, true);
265 BooleanQuery fulquery = new BooleanQuery();
267 for (int i = 0; i < sprop.length; i++) {
268 BooleanQuery query = new BooleanQuery();
269 Term input; // Supposed initialized below at least by the visibility
271 Visibility area = sprop[i].getVisibility(); // Visibility
273 input = new Term("area");
274 query.add(new TermQuery(input.createTerm(area.toString())),
275 BooleanClause.Occur.MUST);
277 ProgressState state = sprop[i].getProgressState(); // State
279 input = new Term("state");
280 if (state == ProgressState.inPROGRESS) {
281 BooleanQuery cristate = new BooleanQuery();
282 cristate.add(new TermQuery(input.createTerm("inWORK")),
283 BooleanClause.Occur.SHOULD);
285 new TermQuery(input.createTerm("inDRAFT")),
286 BooleanClause.Occur.SHOULD);
288 new TermQuery(input.createTerm("inCHECK")),
289 BooleanClause.Occur.SHOULD);
290 query.add(cristate, BooleanClause.Occur.MUST);
292 query.add(new TermQuery(input.createTerm(state
293 .toString())), BooleanClause.Occur.MUST);
296 String refid = sprop[i].getReference(); // Reference
298 input = new Term("ref");
299 query.add(new TermQuery(input.createTerm(refid)),
300 BooleanClause.Occur.MUST);
302 User manager = sprop[i].getManager(); // Author
303 if (manager != null) {
304 input = new Term("author");
305 query.add(new TermQuery(input
306 .createTerm(manager.toString())),
307 BooleanClause.Occur.MUST);
309 User actor = sprop[i].getActor(); // Contributor, Reviewer or Approver
311 input = new Term("actor");
313 new TermQuery(input.createTerm(actor.toString())),
314 BooleanClause.Occur.MUST);
316 String title = sprop[i].getTitle(); // Title
318 input = new Term("contents");
319 BooleanQuery critext = new BooleanQuery();
320 String operator = "AND"; // Future user input
321 BooleanClause.Occur clause = BooleanClause.Occur.MUST;
322 if (operator.equals("OR")) {
323 clause = BooleanClause.Occur.SHOULD;
325 String[] word = title.split(" ");
326 for (int j = 0; j < word.length; j++) {
327 critext.add(new TermQuery(input.createTerm(word[j])),
330 query.add(critext, BooleanClause.Occur.MUST);
332 List<SimulationContext> context = sprop[i]
333 .getSimulationContexts();
334 if (context != null && context.size() > 0) {
335 BooleanQuery critext = new BooleanQuery();
336 for (Iterator<SimulationContext> j = context.iterator(); j
338 SimulationContext seltext = j.next();
339 input = new Term(String.valueOf(seltext.getType()
341 critext.add(new TermQuery(input.createTerm(seltext
342 .getValue())), BooleanClause.Occur.MUST);
344 query.add(critext, BooleanClause.Occur.MUST);
346 fulquery.add(query, BooleanClause.Occur.SHOULD);
348 if (LOG.isInfoEnabled()) {
349 LOG.info("Searching studies by Lucene query \""
350 + fulquery.toString() + "\".");
352 // Creation of the studies filter
353 BooleanFilter filter = new BooleanFilter();
354 TermsFilter select = new TermsFilter();
355 Term mytype = new Term("class");
356 select.addTerm(mytype.createTerm("Study"));
357 filter.add(new FilterClause(select, BooleanClause.Occur.SHOULD));
359 // Creation of the sort criteria
360 Sort sort = new Sort(new SortField("title", SortField.STRING));
363 TopFieldDocs found = searcher.search(fulquery, filter, hitsize,
366 if (found.totalHits < 1) {
367 return result; // No study found
370 // Construction of the result list
371 ScoreDoc[] hits = found.scoreDocs;
372 for (int i = 0; i < hits.length; i++) {
373 result.add(new IndexServiceImpl.ObjectProxy(searcher
377 } catch (Exception error) {
378 LOG.error("Error during Lucene search, reason:", error);
386 * @see org.splat.service.SearchService#indexStudy(org.splat.dal.bo.som.Study)
388 public void indexStudy(final Study study) {
389 LOG.debug("Index study: id=" + study.getRid() + "; reference="
390 + study.getReference());
392 Study.Properties sprop = new Study.Properties();
393 List<Proxy> index = selectStudiesWhere(sprop.setReference(study
396 if (index.size() != 0) {
397 LOG.debug("The given study is already indexed.");
398 return; // The given study is already indexed
401 IndexService lucin = getIndex();
402 Scenario[] scenes = study.getScenarii();
404 LOG.debug("Number of study " + study.getReference()
405 + " actors: " + study.getActor().size());
407 if (study.getProgressState() != ProgressState.inWORK) {
408 for (int i = 0; i < scenes.length; i++) {
409 List<KnowledgeElement> list = scenes[i]
410 .getAllKnowledgeElements();
411 for (Iterator<KnowledgeElement> j = list.iterator(); j
414 LOG.debug("Knowlegge added: id="
415 + j.next().getIndex());
419 } catch (Exception error) {
420 LOG.error("Unable to index the study '" + study.getIndex()
421 + "', reason:", error);
426 * Get lucene index handler. Create the index if it is not exist.
428 * @return IndexService
429 * @throws IOException
430 * if error when creating a new lucene index
432 private IndexService getIndex() throws IOException {
433 IndexService lucin = getIndexService();
434 if (!lucin.exists()) {
435 lucin.create(); // Happens when re-indexing all studies
441 * Get the repositoryService.
443 * @return the repositoryService
445 public RepositoryService getRepositoryService() {
446 return _repositoryService;
450 * Set the repositoryService.
452 * @param repositoryService
453 * the repositoryService to set
455 public void setRepositoryService(final RepositoryService repositoryService) {
456 _repositoryService = repositoryService;
460 * Get the indexService.
462 * @return the indexService
464 public IndexService getIndexService() {
465 return _indexService;
469 * Set the indexService.
471 * @param indexService
472 * the indexService to set
474 public void setIndexService(final IndexService indexService) {
475 _indexService = indexService;
479 * Get the studyService.
481 * @return the studyService
483 public StudyService getStudyService() {
484 return _studyService;
488 * Set the studyService.
490 * @param studyService
491 * the studyService to set
493 public void setStudyService(final StudyService studyService) {
494 _studyService = studyService;
500 * @return the studyDAO
502 public StudyDAO getStudyDAO() {
510 * the studyDAO to set
512 public void setStudyDAO(final StudyDAO studyDAO) {
513 _studyDAO = studyDAO;