package com.epam.wilma.message.search.lucene.search; /*========================================================================== Copyright 2013-2017 EPAM Systems This file is part of Wilma. Wilma is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Wilma is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wilma. If not, see <http://www.gnu.org/licenses/>. ===========================================================================*/ import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.epam.wilma.message.search.domain.exception.QueryCannotBeParsedException; import com.epam.wilma.message.search.domain.exception.SystemException; import com.epam.wilma.message.search.lucene.search.helper.CurrentTimeProvider; import com.epam.wilma.message.search.lucene.search.helper.IndexReaderFactory; import com.epam.wilma.message.search.lucene.search.helper.IndexSearcherFactory; /** * Searches for 'Lucene' indexes which match the given pattern. * @author Tamas_Bihari * */ @Component public class LuceneSearchEngine { private static final String FIELD_PATH = "path"; private final Logger logger = LoggerFactory.getLogger(LuceneSearchEngine.class); @Value("#{topQueryHits}") private int topQueryHits; private IndexReader indexReader; private IndexSearcher indexSearcher; @Autowired private IndexReaderFactory readerFactory; @Autowired private QueryParser queryParser; @Autowired private IndexSearcherFactory searcherFactory; @Autowired private CurrentTimeProvider currentTimeProvider; /** * Sets {@link QueryParser} instance properties. */ @PostConstruct public void initQueryParserProperties() { queryParser.setLowercaseExpandedTerms(true); queryParser.setAllowLeadingWildcard(true); } /** * Searches for the given text in the index. * @param text which we search for * @return with the file names where the text matches found. If there is no match will return with empty list. */ public List<String> searchForText(final String text) { List<String> fileNames = new ArrayList<>(); getNewReaderAndSearcherUsingWriter(); Query query = createQuery(text); try { TopDocs queryResult = doSearch(query); fileNames = getFileNames(queryResult); closeIndexReader(); } catch (IOException e) { logger.error(" caught a " + e.getClass() + "\n with message: " + e.getMessage()); } return fileNames; } private TopDocs doSearch(final Query query) throws IOException { long start = currentTimeProvider.getCurrentTimeInMillis(); TopDocs queryResult = indexSearcher.search(query, topQueryHits); long end = currentTimeProvider.getCurrentTimeInMillis(); logger.info("search in millis:" + (end - start) + " hits:" + queryResult.totalHits); return queryResult; } private List<String> getFileNames(final TopDocs result) throws IOException { List<String> fileNames = new ArrayList<>(); ScoreDoc[] scoreDocs = result.scoreDocs; for (int i = 0; i < scoreDocs.length; ++i) { int docNumber = scoreDocs[i].doc; Document document = getDocument(docNumber); fileNames.add(document.get(FIELD_PATH)); } return fileNames; } private void getNewReaderAndSearcherUsingWriter() { try { indexReader = readerFactory.create(true); indexSearcher = searcherFactory.create(indexReader); } catch (IOException e) { throw new SystemException("Could not create index reader during search", e); } } private Query createQuery(final String query) { Query result = null; try { result = queryParser.parse(query); } catch (ParseException e) { throw new QueryCannotBeParsedException("Query " + query + "cannot be parsed. Reason:" + e.getMessage()); } return result; } Document getDocument(final int docNumber) throws IOException { return indexReader.document(docNumber); } void closeIndexReader() throws IOException { indexReader.close(); } }