001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.core.lucene.engine;
018:
019: import java.io.IOException;
020: import java.util.ArrayList;
021:
022: import org.apache.lucene.index.Term;
023: import org.apache.lucene.search.BooleanClause;
024: import org.apache.lucene.search.BooleanQuery;
025: import org.apache.lucene.search.Filter;
026: import org.apache.lucene.search.Query;
027: import org.apache.lucene.search.Sort;
028: import org.apache.lucene.search.SortField;
029: import org.apache.lucene.search.TermQuery;
030: import org.apache.lucene.search.spans.SpanQuery;
031: import org.compass.core.CompassQuery.SortDirection;
032: import org.compass.core.CompassQuery.SortImplicitType;
033: import org.compass.core.CompassQuery.SortPropertyType;
034: import org.compass.core.engine.SearchEngineException;
035: import org.compass.core.engine.SearchEngineHits;
036: import org.compass.core.engine.SearchEngineQuery;
037: import org.compass.core.engine.SearchEngineQueryFilter;
038: import org.compass.core.lucene.engine.queryparser.QueryHolder;
039: import org.compass.core.lucene.search.CountHitCollector;
040:
041: /**
042: * @author kimchy
043: */
044: public class LuceneSearchEngineQuery implements SearchEngineQuery,
045: Cloneable {
046:
047: public static class LuceneSearchEngineSpanQuery extends
048: LuceneSearchEngineQuery implements SearchEngineSpanQuery {
049:
050: private SpanQuery spanQuery;
051:
052: public LuceneSearchEngineSpanQuery(
053: LuceneSearchEngine searchEngine, SpanQuery query) {
054: super (searchEngine, query);
055: this .spanQuery = query;
056: }
057:
058: public SpanQuery toSpanQuery() {
059: return spanQuery;
060: }
061: }
062:
063: private LuceneSearchEngine searchEngine;
064:
065: private ArrayList<SortField> sortFields = new ArrayList<SortField>();
066:
067: private String[] subIndexes;
068:
069: private String[] aliases;
070:
071: private LuceneSearchEngineQueryFilter filter;
072:
073: private Query origQuery;
074:
075: private Query query;
076:
077: private String defaultSearchProperty;
078:
079: private boolean rewrite;
080:
081: private boolean suggested;
082:
083: public LuceneSearchEngineQuery(LuceneSearchEngine searchEngine,
084: Query query) {
085: this (searchEngine, new QueryHolder(query), searchEngine
086: .getSearchEngineFactory().getLuceneSettings()
087: .getDefaultSearchPropery());
088: }
089:
090: public LuceneSearchEngineQuery(LuceneSearchEngine searchEngine,
091: QueryHolder query) {
092: this (searchEngine, query, searchEngine.getSearchEngineFactory()
093: .getLuceneSettings().getDefaultSearchPropery());
094: }
095:
096: public LuceneSearchEngineQuery(LuceneSearchEngine searchEngine,
097: QueryHolder query, String defualtSearchProperty) {
098: this .searchEngine = searchEngine;
099: this .query = query.getQuery();
100: this .origQuery = query.getQuery();
101: this .suggested = query.isSuggested();
102: this .defaultSearchProperty = defualtSearchProperty;
103: }
104:
105: public SearchEngineQuery addSort(String propertyName) {
106: sortFields.add(new SortField(propertyName));
107: return this ;
108: }
109:
110: public SearchEngineQuery addSort(String propertyName,
111: SortDirection direction) {
112: sortFields.add(new SortField(propertyName,
113: getSortReverse(direction)));
114: return this ;
115: }
116:
117: public SearchEngineQuery addSort(String propertyName,
118: SortPropertyType type) {
119: sortFields.add(new SortField(propertyName, getSortType(type)));
120: return this ;
121: }
122:
123: public SearchEngineQuery addSort(String propertyName,
124: SortPropertyType type, SortDirection direction) {
125: sortFields.add(new SortField(propertyName, getSortType(type),
126: getSortReverse(direction)));
127: return this ;
128: }
129:
130: public SearchEngineQuery addSort(SortImplicitType implicitType) {
131: sortFields.add(new SortField(null,
132: getImplicitSortField(implicitType)));
133: return this ;
134: }
135:
136: public SearchEngineQuery addSort(SortImplicitType implicitType,
137: SortDirection direction) {
138: sortFields.add(new SortField(null,
139: getImplicitSortField(implicitType),
140: getSortReverse(direction)));
141: return this ;
142: }
143:
144: public SearchEngineQuery addSort(SortField sortField) {
145: sortFields.add(sortField);
146: return this ;
147: }
148:
149: public Sort getSort() {
150: if (sortFields.size() == 0) {
151: return null;
152: }
153: SortField[] sortFieldsArr = sortFields
154: .toArray(new SortField[sortFields.size()]);
155: return new Sort(sortFieldsArr);
156: }
157:
158: private int getImplicitSortField(SortImplicitType implicitType) {
159: if (implicitType == SortImplicitType.DOC) {
160: return SortField.DOC;
161: }
162: if (implicitType == SortImplicitType.SCORE) {
163: return SortField.SCORE;
164: }
165: throw new IllegalArgumentException(
166: "Faile to create lucene implicit type for ["
167: + implicitType + "]");
168: }
169:
170: private boolean getSortReverse(SortDirection direction) {
171: return direction == SortDirection.REVERSE;
172: }
173:
174: private int getSortType(SortPropertyType type) {
175: if (type == SortPropertyType.AUTO) {
176: return SortField.AUTO;
177: }
178: if (type == SortPropertyType.FLOAT) {
179: return SortField.FLOAT;
180: }
181: if (type == SortPropertyType.INT) {
182: return SortField.INT;
183: }
184: if (type == SortPropertyType.STRING) {
185: return SortField.STRING;
186: }
187: throw new IllegalArgumentException(
188: "Faile to create lucene sort property type for ["
189: + type + "]");
190: }
191:
192: public long count() {
193: LuceneSearchEngineInternalSearch internalSearch = (LuceneSearchEngineInternalSearch) searchEngine
194: .internalSearch(getSubIndexes(), getAliases());
195: CountHitCollector countHitCollector = new CountHitCollector();
196: try {
197: internalSearch.getSearcher().search(getQuery(),
198: getLuceneFilter(), countHitCollector);
199: } catch (IOException e) {
200: throw new SearchEngineException("Failed to count query ["
201: + query + "]", e);
202: }
203: return countHitCollector.getTotalHits();
204: }
205:
206: public SearchEngineHits hits() {
207: return this .searchEngine.find(this );
208: }
209:
210: public SearchEngineQuery setBoost(float boost) {
211: query.setBoost(boost);
212: return this ;
213: }
214:
215: public SearchEngineQuery setSubIndexes(String[] subindexes) {
216: this .subIndexes = subindexes;
217: return this ;
218: }
219:
220: public String[] getSubIndexes() {
221: return this .subIndexes;
222: }
223:
224: public SearchEngineQuery setAliases(String[] aliases) {
225: if (aliases == null) {
226: query = origQuery;
227: return this ;
228: }
229:
230: String aliasProperty = searchEngine.getSearchEngineFactory()
231: .getLuceneSettings().getAliasProperty();
232: BooleanQuery boolQuery2 = new BooleanQuery();
233: for (String alias : aliases) {
234: boolQuery2.add(
235: new TermQuery(new Term(aliasProperty, alias)),
236: BooleanClause.Occur.SHOULD);
237: }
238:
239: BooleanQuery boolQuery = new BooleanQuery();
240: boolQuery.add(origQuery, BooleanClause.Occur.MUST);
241: boolQuery.add(boolQuery2, BooleanClause.Occur.MUST);
242: this .query = boolQuery;
243:
244: this .aliases = aliases;
245:
246: return this ;
247: }
248:
249: public String[] getAliases() {
250: return this .aliases;
251: }
252:
253: public SearchEngineQuery setFilter(SearchEngineQueryFilter filter) {
254: this .filter = (LuceneSearchEngineQueryFilter) filter;
255: return this ;
256: }
257:
258: public LuceneSearchEngineQueryFilter getFilter() {
259: return this .filter;
260: }
261:
262: public Filter getLuceneFilter() {
263: if (filter == null) {
264: return null;
265: }
266: return filter.getFilter();
267: }
268:
269: public SearchEngineQuery rewrite() {
270: this .rewrite = true;
271: return this ;
272: }
273:
274: public boolean isRewrite() {
275: return this .rewrite;
276: }
277:
278: public boolean isSuggested() {
279: return this .suggested;
280: }
281:
282: public Query getOriginalQuery() {
283: return this .origQuery;
284: }
285:
286: public Query getQuery() {
287: return this .query;
288: }
289:
290: public String toString() {
291: if (query == null) {
292: return "<null>";
293: }
294: // remove the "zzz-all:" prefix
295: return query.toString()
296: .replace(defaultSearchProperty + ":", "");
297: }
298:
299: public Object clone() throws CloneNotSupportedException {
300: return super .clone();
301: }
302:
303: // breaks encapsulation, but we need it
304:
305: public void setQuery(Query query) {
306: this .query = query;
307: this .origQuery = query;
308: }
309:
310: public void setSuggested(boolean suggested) {
311: this.suggested = suggested;
312: }
313: }
|