001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.search;
016    
017    import com.liferay.portal.kernel.search.facet.Facet;
018    import com.liferay.portal.kernel.search.filter.BooleanFilter;
019    import com.liferay.portal.kernel.search.filter.Filter;
020    import com.liferay.portal.kernel.search.filter.TermsFilter;
021    import com.liferay.portal.kernel.search.generic.BooleanQueryImpl;
022    import com.liferay.portal.kernel.search.generic.MatchAllQuery;
023    import com.liferay.portal.kernel.util.ArrayUtil;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.ListUtil;
026    import com.liferay.portal.kernel.util.SetUtil;
027    import com.liferay.portal.kernel.util.UnicodeProperties;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.model.Group;
030    import com.liferay.portal.service.GroupLocalServiceUtil;
031    import com.liferay.portlet.expando.model.ExpandoBridge;
032    import com.liferay.portlet.expando.model.ExpandoColumnConstants;
033    import com.liferay.portlet.expando.util.ExpandoBridgeFactoryUtil;
034    
035    import java.util.List;
036    import java.util.Map;
037    import java.util.Set;
038    
039    /**
040     * @author Raymond Aug??
041     */
042    public class FacetedSearcher extends BaseSearcher {
043    
044            public static Indexer<?> getInstance() {
045                    return new FacetedSearcher();
046            }
047    
048            protected void addSearchExpandoKeywords(
049                            BooleanQuery searchQuery, SearchContext searchContext,
050                            String keywords, String className)
051                    throws Exception {
052    
053                    ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil.getExpandoBridge(
054                            searchContext.getCompanyId(), className);
055    
056                    Set<String> attributeNames = SetUtil.fromEnumeration(
057                            expandoBridge.getAttributeNames());
058    
059                    for (String attributeName : attributeNames) {
060                            UnicodeProperties properties = expandoBridge.getAttributeProperties(
061                                    attributeName);
062    
063                            int indexType = GetterUtil.getInteger(
064                                    properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
065    
066                            if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
067                                    String fieldName = getExpandoFieldName(
068                                            searchContext, expandoBridge, attributeName);
069    
070                                    if (searchContext.isAndSearch()) {
071                                            searchQuery.addRequiredTerm(fieldName, keywords);
072                                    }
073                                    else {
074                                            searchQuery.addTerm(fieldName, keywords);
075                                    }
076                            }
077                    }
078            }
079    
080            @Override
081            protected BooleanQuery createFullQuery(
082                            BooleanFilter fullQueryBooleanFilter, SearchContext searchContext)
083                    throws Exception {
084    
085                    BooleanQuery searchQuery = new BooleanQueryImpl();
086    
087                    String keywords = searchContext.getKeywords();
088    
089                    if (Validator.isNotNull(keywords)) {
090                            addSearchLocalizedTerm(
091                                    searchQuery, searchContext, Field.ASSET_CATEGORY_TITLES, false);
092    
093                            searchQuery.addExactTerm(Field.ASSET_TAG_NAMES, keywords);
094    
095                            int groupId = GetterUtil.getInteger(
096                                    searchContext.getAttribute(Field.GROUP_ID));
097    
098                            if (groupId == 0) {
099                                    fullQueryBooleanFilter.addTerm(
100                                            Field.STAGING_GROUP, "true", BooleanClauseOccur.MUST_NOT);
101                            }
102    
103                            searchQuery.addTerms(Field.KEYWORDS, keywords);
104                    }
105    
106                    List<Group> inactiveGroups = GroupLocalServiceUtil.getActiveGroups(
107                            searchContext.getCompanyId(), false);
108    
109                    if (ListUtil.isNotEmpty(inactiveGroups)) {
110                            TermsFilter groupIdTermsFilter = new TermsFilter(Field.GROUP_ID);
111    
112                            groupIdTermsFilter.addValues(
113                                    ArrayUtil.toStringArray(
114                                            ListUtil.toArray(inactiveGroups, Group.GROUP_ID_ACCESSOR)));
115    
116                            fullQueryBooleanFilter.add(
117                                    groupIdTermsFilter, BooleanClauseOccur.MUST_NOT);
118                    }
119    
120                    for (String entryClassName : searchContext.getEntryClassNames()) {
121                            Indexer<?> indexer = IndexerRegistryUtil.getIndexer(entryClassName);
122    
123                            if (indexer == null) {
124                                    continue;
125                            }
126    
127                            String searchEngineId = searchContext.getSearchEngineId();
128    
129                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
130                                    continue;
131                            }
132    
133                            if (Validator.isNotNull(keywords)) {
134                                    addSearchExpandoKeywords(
135                                            searchQuery, searchContext, keywords, entryClassName);
136                            }
137    
138                            indexer.postProcessSearchQuery(
139                                    searchQuery, fullQueryBooleanFilter, searchContext);
140    
141                            for (IndexerPostProcessor indexerPostProcessor :
142                                            indexer.getIndexerPostProcessors()) {
143    
144                                    indexerPostProcessor.postProcessSearchQuery(
145                                            searchQuery, fullQueryBooleanFilter, searchContext);
146                            }
147    
148                            doPostProcessSearchQuery(indexer, searchQuery, searchContext);
149                    }
150    
151                    Map<String, Facet> facets = searchContext.getFacets();
152    
153                    BooleanFilter facetBooleanFilter = new BooleanFilter();
154    
155                    for (Facet facet : facets.values()) {
156                            BooleanClause<Filter> facetClause =
157                                    facet.getFacetFilterBooleanClause();
158    
159                            if (facetClause != null) {
160                                    facetBooleanFilter.add(
161                                            facetClause.getClause(),
162                                            facetClause.getBooleanClauseOccur());
163                            }
164                    }
165    
166                    addFacetClause(searchContext, facetBooleanFilter, facets.values());
167    
168                    if (facetBooleanFilter.hasClauses()) {
169                            fullQueryBooleanFilter.add(
170                                    facetBooleanFilter, BooleanClauseOccur.MUST);
171                    }
172    
173                    BooleanQuery fullQuery = new BooleanQueryImpl();
174    
175                    if (fullQueryBooleanFilter.hasClauses()) {
176                            fullQuery.setPreBooleanFilter(fullQueryBooleanFilter);
177                    }
178    
179                    if (searchQuery.hasClauses()) {
180                            fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
181                    }
182    
183                    BooleanClause<Query>[] booleanClauses =
184                            searchContext.getBooleanClauses();
185    
186                    if (booleanClauses != null) {
187                            for (BooleanClause<Query> booleanClause : booleanClauses) {
188                                    fullQuery.add(
189                                            booleanClause.getClause(),
190                                            booleanClause.getBooleanClauseOccur());
191                            }
192                    }
193    
194                    for (String entryClassName : searchContext.getEntryClassNames()) {
195                            Indexer<?> indexer = IndexerRegistryUtil.getIndexer(entryClassName);
196    
197                            if (indexer == null) {
198                                    continue;
199                            }
200    
201                            String searchEngineId = searchContext.getSearchEngineId();
202    
203                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
204                                    continue;
205                            }
206    
207                            for (IndexerPostProcessor indexerPostProcessor :
208                                            indexer.getIndexerPostProcessors()) {
209    
210                                    indexerPostProcessor.postProcessFullQuery(
211                                            fullQuery, searchContext);
212                            }
213                    }
214    
215                    return fullQuery;
216            }
217    
218            @Override
219            protected Hits doSearch(SearchContext searchContext)
220                    throws SearchException {
221    
222                    try {
223                            searchContext.setSearchEngineId(getSearchEngineId());
224    
225                            BooleanFilter queryBooleanFilter = new BooleanFilter();
226    
227                            queryBooleanFilter.addRequiredTerm(
228                                    Field.COMPANY_ID, searchContext.getCompanyId());
229    
230                            Query fullQuery = createFullQuery(
231                                    queryBooleanFilter, searchContext);
232    
233                            if (!fullQuery.hasChildren()) {
234                                    BooleanFilter preBooleanFilter =
235                                            fullQuery.getPreBooleanFilter();
236    
237                                    fullQuery = new MatchAllQuery();
238    
239                                    fullQuery.setPreBooleanFilter(preBooleanFilter);
240                            }
241    
242                            QueryConfig queryConfig = searchContext.getQueryConfig();
243    
244                            fullQuery.setQueryConfig(queryConfig);
245    
246                            return IndexSearcherHelperUtil.search(searchContext, fullQuery);
247                    }
248                    catch (Exception e) {
249                            throw new SearchException(e);
250                    }
251            }
252    
253            @Override
254            protected boolean isUseSearchResultPermissionFilter(
255                    SearchContext searchContext) {
256    
257                    if (searchContext.getEntryClassNames() == null) {
258                            return super.isFilterSearch();
259                    }
260    
261                    for (String entryClassName : searchContext.getEntryClassNames()) {
262                            Indexer<?> indexer = IndexerRegistryUtil.getIndexer(entryClassName);
263    
264                            if (indexer == null) {
265                                    continue;
266                            }
267    
268                            if (indexer.isFilterSearch()) {
269                                    return true;
270                            }
271                    }
272    
273                    return super.isFilterSearch();
274            }
275    
276    }