001: /*
002: * $Header$
003: * $Revision: 1749 $
004: * $Date: 2006-04-04 08:41:40 -0700 $
005: *
006: * ====================================================================
007: *
008: * Copyright 1999-2004 The Apache Software Foundation
009: *
010: * Licensed under the Apache License, Version 2.0 (the "License");
011: * you may not use this file except in compliance with the License.
012: * You may obtain a copy of the License at
013: *
014: * http://www.apache.org/licenses/LICENSE-2.0
015: *
016: * Unless required by applicable law or agreed to in writing, software
017: * distributed under the License is distributed on an "AS IS" BASIS,
018: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019: * See the License for the specific language governing permissions and
020: * limitations under the License.
021: *
022: */
023: package org.apache.slide.index.lucene.expressions;
024:
025: import java.util.ArrayList;
026: import java.util.Collection;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.Map;
031:
032: import org.apache.lucene.search.BooleanClause;
033: import org.apache.lucene.search.BooleanQuery;
034: import org.apache.lucene.search.Query;
035:
036: import org.apache.slide.index.lucene.Index;
037:
038: /**
039: * Implements <code>and</code> and <code>or</code>.
040: */
041: public class MergeExpression extends AbstractLuceneExpression {
042: /**
043: * Constructor.
044: * @param index The index to be searched.
045: * @param and <code>true</code> if AND or <code>false</code> if OR
046: * @param expressions list of expressions (must all be derived from
047: * {@link AbstractLuceneExpression}, i.e. must all be lucene executable)
048: */
049: public MergeExpression(Index index, boolean and,
050: Collection expressions) {
051: super (index);
052:
053: expressions = optimizeRanges(and, expressions);
054:
055: if (expressions.size() == 1) {
056: AbstractLuceneExpression expression = (AbstractLuceneExpression) expressions
057: .iterator().next();
058: setQuery(expression.getQuery());
059:
060: } else {
061: BooleanQuery booleanQuery = new BooleanQuery();
062:
063: for (Iterator i = expressions.iterator(); i.hasNext();) {
064: Object e = i.next();
065: AbstractLuceneExpression expression = (AbstractLuceneExpression) e;
066: Query q = expression.getQuery();
067:
068: if (and)
069: booleanQuery.add(q, BooleanClause.Occur.MUST);
070: else
071: booleanQuery.add(q, BooleanClause.Occur.SHOULD);
072: }
073: setQuery(booleanQuery);
074: }
075: }
076:
077: private Collection optimizeRanges(boolean and,
078: Collection expressions) {
079: Map fields = new HashMap();
080: List result = new ArrayList(expressions.size());
081:
082: // search for comparision operators that work on same field
083:
084: for (Iterator i = expressions.iterator(); i.hasNext();) {
085: Object o = i.next();
086: if (o instanceof RangeOperator) {
087: RangeOperator op = (RangeOperator) o;
088:
089: List ops = (List) fields.get(op.getField());
090: if (ops == null) {
091: ops = new ArrayList();
092: fields.put(op.getField(), ops);
093: }
094: ops.add(op);
095: } else {
096: result.add(o);
097: }
098: }
099:
100: for (Iterator i = fields.entrySet().iterator(); i.hasNext();) {
101: Map.Entry e = (Map.Entry) i.next();
102: List ops = (List) e.getValue();
103:
104: if (ops.size() == 2) {
105: AbstractLuceneExpression expr = optBetween(
106: (RangeOperator) ops.get(0), (RangeOperator) ops
107: .get(1), and);
108: if (expr != null) {
109: result.add(expr);
110: }
111: } else {
112: result.addAll(ops);
113: }
114: }
115:
116: return result;
117: }
118:
119: private AbstractLuceneExpression optBetween(RangeOperator o1,
120: RangeOperator o2, boolean and) {
121: if (o1 instanceof GtExpression) {
122: if (o2 instanceof LtExpression) {
123: if (and) {
124: if (o1.getValue().compareTo(o2.getValue()) <= 0) {
125: // ------o1>++++++<o2------
126: return new BetweenExpression(this .index, o1
127: .getField(), o1.getValue(), o2
128: .getValue(), o1.inclusive(), o2
129: .inclusive(), false);
130: } else {
131: // ------<o2------o1>------
132: return null;
133: }
134: } else {
135: if (o1.getValue().compareTo(o2.getValue()) >= 0) {
136: // ++++++<o2------o1>++++++
137: return new BetweenExpression(this .index, o1
138: .getField(), o2.getValue(), o1
139: .getValue(), o2.inclusive(), o1
140: .inclusive(), true); // negated
141: } else {
142: // ++++++o1>+++++<o2+++++++
143: return new IsDefinedExpression(this .index, o1
144: .getField(), false);
145: }
146: }
147: }
148: if (o2 instanceof GtExpression) {
149: if (and) {
150: if (o1.getValue().compareTo(o2.getValue()) <= 0) {
151: // -----o1>-----o2>++++++
152: return (AbstractLuceneExpression) o2;
153: } else {
154: // -----o2>-----o1>++++++
155: return (AbstractLuceneExpression) o1;
156: }
157: } else {
158: if (o1.getValue().compareTo(o2.getValue()) <= 0) {
159: // -----o1>+++++o2>++++++
160: return (AbstractLuceneExpression) o1;
161: } else {
162: // -----o2>+++++o1>++++++
163: return (AbstractLuceneExpression) o2;
164: }
165: }
166: }
167: throw new RuntimeException();
168: }
169: if (o1 instanceof LtExpression) {
170: if (o2 instanceof GtExpression) {
171: if (and) {
172: if (o1.getValue().compareTo(o2.getValue()) <= 0) {
173: // ------<o1------o2>------
174: return null;
175: } else {
176: // ------o2>++++++<o1------
177: return new BetweenExpression(this .index, o1
178: .getField(), o2.getValue(), o1
179: .getValue(), o2.inclusive(), o1
180: .inclusive(), false);
181: }
182: } else {
183: if (o1.getValue().compareTo(o2.getValue()) >= 0) {
184: // ++++++o2>+++++<o1++++++
185: return new IsDefinedExpression(this .index, o1
186: .getField(), false);
187: } else {
188: // ++++++<o1-----o2>+++++++
189: return new BetweenExpression(this .index, o1
190: .getField(), o1.getValue(), o2
191: .getValue(), o1.inclusive(), o2
192: .inclusive(), true); // negated
193: }
194: }
195: }
196: if (o2 instanceof LtExpression) {
197: if (and) {
198: if (o1.getValue().compareTo(o2.getValue()) <= 0) {
199: // +++++<o1-----<o2------
200: return (AbstractLuceneExpression) o1;
201: } else {
202: // +++++<o2-----<o1------
203: return (AbstractLuceneExpression) o2;
204: }
205: } else {
206: if (o1.getValue().compareTo(o2.getValue()) <= 0) {
207: // +++++<o1+++++<o2------
208: return (AbstractLuceneExpression) o2;
209: } else {
210: // +++++<o2+++++<o1------
211: return (AbstractLuceneExpression) o1;
212: }
213: }
214: }
215: throw new RuntimeException();
216: }
217: throw new RuntimeException();
218: }
219: }
|