fr.paris.lutece.portal.service.search.LuceneSearchEngine.java Source code

Java tutorial

Introduction

Here is the source code for fr.paris.lutece.portal.service.search.LuceneSearchEngine.java

Source

/*
 * Copyright (c) 2002-2013, Mairie de Paris
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice
 *     and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright notice
 *     and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *
 *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * License 1.0
 */
package fr.paris.lutece.portal.service.search;

import fr.paris.lutece.portal.business.page.Page;
import fr.paris.lutece.portal.service.security.LuteceUser;
import fr.paris.lutece.portal.service.security.SecurityService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.util.date.DateUtil;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.DateTools.Resolution;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.misc.ChainedFilter;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.CachingWrapperFilter;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryWrapperFilter;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;

/**
 * LuceneSearchEngine
 */
public class LuceneSearchEngine implements SearchEngine {
    public static final int MAX_RESPONSES = 1000000;
    private static final String PARAMETER_TYPE_FILTER = "type_filter";
    private static final String PARAMETER_DATE_AFTER = "date_after";
    private static final String PARAMETER_DATE_BEFORE = "date_before";
    private static final String PARAMETER_TAG_FILTER = "tag_filter";
    private static final String PARAMETER_DEFAULT_OPERATOR = "default_operator";
    private static final String PARAMETER_OPERATOR_AND = "AND";

    /**
     * Return search results
     * 
     * @param strQuery The search query
     * @param request The HTTP request
     * @return Results as a collection of SearchResult
     */
    public List<SearchResult> getSearchResults(String strQuery, HttpServletRequest request) {
        ArrayList<SearchItem> listResults = new ArrayList<SearchItem>();
        ArrayList<Filter> listFilter = new ArrayList<Filter>();
        Searcher searcher = null;
        boolean bFilterResult = false;
        LuteceUser user = null;
        String[] typeFilter = request.getParameterValues(PARAMETER_TYPE_FILTER);
        String strDateAfter = request.getParameter(PARAMETER_DATE_AFTER);
        String strDateBefore = request.getParameter(PARAMETER_DATE_BEFORE);
        boolean bDateAfter = false;
        boolean bDateBefore = false;
        Filter allFilter = null;
        String strTagFilter = request.getParameter(PARAMETER_TAG_FILTER);

        if (SecurityService.isAuthenticationEnable()) {
            user = SecurityService.getInstance().getRegisteredUser(request);

            Filter[] filtersRole = null;

            if (user != null) {
                String[] userRoles = SecurityService.getInstance().getRolesByUser(user);

                if (userRoles != null) {
                    filtersRole = new Filter[userRoles.length + 1];

                    for (int i = 0; i < userRoles.length; i++) {
                        Query queryRole = new TermQuery(new Term(SearchItem.FIELD_ROLE, userRoles[i]));
                        filtersRole[i] = new CachingWrapperFilter(new QueryWrapperFilter(queryRole));
                    }
                } else {
                    bFilterResult = true;
                }
            } else {
                filtersRole = new Filter[1];
            }

            if (!bFilterResult) {
                Query queryRole = new TermQuery(new Term(SearchItem.FIELD_ROLE, Page.ROLE_NONE));
                filtersRole[filtersRole.length - 1] = new CachingWrapperFilter(new QueryWrapperFilter(queryRole));
                listFilter.add(new ChainedFilter(filtersRole, ChainedFilter.OR));
            }
        }

        if (StringUtils.isNotBlank(strDateAfter) || StringUtils.isNotBlank(strDateBefore)) {
            String strAfter = null;
            String strBefore = null;

            if (StringUtils.isNotBlank(strDateAfter)) {
                Date dateAfter = DateUtil.formatDate(strDateAfter, request.getLocale());
                strAfter = DateTools.dateToString(dateAfter, Resolution.DAY);
                bDateAfter = true;
            }

            if (StringUtils.isNotBlank(strDateBefore)) {
                Date dateBefore = DateUtil.formatDate(strDateBefore, request.getLocale());
                strBefore = DateTools.dateToString(dateBefore, Resolution.DAY);
                bDateBefore = true;
            }

            Query queryDate = new TermRangeQuery(SearchItem.FIELD_DATE, strAfter, strBefore, bDateAfter,
                    bDateBefore);
            listFilter.add(new CachingWrapperFilter(new QueryWrapperFilter(queryDate)));
        }

        if ((typeFilter != null) && (typeFilter.length > 0)
                && !typeFilter[0].equals(SearchService.TYPE_FILTER_NONE)) {
            Filter[] filtersType = new Filter[typeFilter.length];

            for (int i = 0; i < typeFilter.length; i++) {
                Query queryType = new TermQuery(new Term(SearchItem.FIELD_TYPE, typeFilter[i]));
                filtersType[i] = new CachingWrapperFilter(new QueryWrapperFilter(queryType));
            }

            listFilter.add(new ChainedFilter(filtersType, ChainedFilter.OR));
        }

        if (!listFilter.isEmpty()) {
            allFilter = new ChainedFilter(listFilter.toArray(new Filter[1]), ChainedFilter.AND);
        }

        try {
            searcher = new IndexSearcher(IndexationService.getDirectoryIndex(), true);

            Query query = null;

            if (StringUtils.isNotBlank(strTagFilter)) {
                BooleanQuery bQuery = new BooleanQuery();
                QueryParser parser = new QueryParser(IndexationService.LUCENE_INDEX_VERSION,
                        SearchItem.FIELD_METADATA, IndexationService.getAnalyser());

                Query queryMetaData = parser.parse((strQuery != null) ? strQuery : "");
                bQuery.add(queryMetaData, BooleanClause.Occur.SHOULD);

                parser = new QueryParser(IndexationService.LUCENE_INDEX_VERSION, SearchItem.FIELD_SUMMARY,
                        IndexationService.getAnalyser());

                Query querySummary = parser.parse((strQuery != null) ? strQuery : "");
                bQuery.add(querySummary, BooleanClause.Occur.SHOULD);
                query = bQuery;
            } else {
                QueryParser parser = new QueryParser(IndexationService.LUCENE_INDEX_VERSION,
                        SearchItem.FIELD_CONTENTS, IndexationService.getAnalyser());

                String operator = request.getParameter(PARAMETER_DEFAULT_OPERATOR);

                if (StringUtils.isNotEmpty(operator) && operator.equals(PARAMETER_OPERATOR_AND)) {
                    parser.setDefaultOperator(QueryParser.AND_OPERATOR);
                }

                query = parser.parse((strQuery != null) ? strQuery : "");
            }

            // Get results documents
            TopDocs topDocs = searcher.search(query, allFilter, MAX_RESPONSES);
            ScoreDoc[] hits = topDocs.scoreDocs;

            for (int i = 0; i < hits.length; i++) {
                int docId = hits[i].doc;
                Document document = searcher.doc(docId);
                SearchItem si = new SearchItem(document);

                if ((!bFilterResult) || (si.getRole().equals(Page.ROLE_NONE))
                        || (SecurityService.getInstance().isUserInRole(request, si.getRole()))) {
                    listResults.add(si);
                }
            }

            searcher.close();
        } catch (Exception e) {
            AppLogService.error(e.getMessage(), e);
        }

        return convertList(listResults);
    }

    /**
     * Convert a list of Lucene items into a list of generic search items
     * @param listSource The list of Lucene items
     * @return A list of generic search items
     */
    private List<SearchResult> convertList(List<SearchItem> listSource) {
        List<SearchResult> listDest = new ArrayList<SearchResult>();

        for (SearchItem item : listSource) {
            SearchResult result = new SearchResult();
            result.setId(item.getId());

            try {
                result.setDate(DateTools.stringToDate(item.getDate()));
            } catch (ParseException e) {
                AppLogService
                        .error("Bad Date Format for indexed item \"" + item.getTitle() + "\" : " + e.getMessage());
            }

            result.setUrl(item.getUrl());
            result.setTitle(item.getTitle());
            result.setSummary(item.getSummary());
            result.setType(item.getType());
            listDest.add(result);
        }

        return listDest;
    }
}