001: /*
002: * $Header$
003: * $Revision: 7067 $
004: * $Date: 2007-07-09 02:45:41 -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 org.apache.lucene.index.Term;
026: import org.apache.lucene.search.BooleanClause;
027: import org.apache.lucene.search.BooleanQuery;
028: import org.apache.lucene.search.Query;
029: import org.apache.lucene.search.RangeQuery;
030: import org.apache.lucene.search.TermQuery;
031:
032: import org.apache.slide.index.lucene.Index;
033: import org.apache.slide.index.lucene.IndexConfiguration;
034: import org.apache.slide.search.BadQueryException;
035: import org.jdom.Element;
036:
037: /**
038: * Implements a slide specific <code>between</code> and
039: * <code>between-inclusive</code> operators.
040: *
041: * <p>
042: * With lucene <code>(between prop val1 val2)</code> will be more efficient
043: * than <code>(and (gt prop1 val1) (lt prop val2))</code>.
044: * <br>
045: * In the {@link org.apache.slide.index.lucene.expressions.MergeExpression}
046: * such an optimization is implemented.
047: *
048: * <p>Usage:
049: * <pre>
050: * <searchrequest xmlns:D="DAV:" xmlns:S="http://jakarta.apache.org/slide/">
051: * <S:between>
052: * <D:prop><D:getlastmodified/></D:prop>
053: * <D:literal>Fri, 14 Oct 2004 10:00:00 GMT</D:literal>
054: * <D:literal>Fri, 15 Oct 2004 10:00:00 GMT</D:literal>
055: * </S:between>
056: * </pre>
057: */
058: public class BetweenExpression extends AbstractLuceneExpression {
059:
060: public BetweenExpression(Index index, Element element,
061: boolean inclusive, boolean negated)
062: throws BadQueryException {
063: super (index);
064:
065: IndexConfiguration config = index.getConfiguration();
066: Element prop = getPropertyElement(element);
067: String field = IndexConfiguration.generateFieldName(prop
068: .getNamespaceURI(), prop.getName());
069: Element literal1 = getLiteralElement(element);
070: Element literal2 = getLiteral2Element(element);
071:
072: String value1;
073: String value2;
074: if (index.getConfiguration().isDateProperty(
075: prop.getNamespaceURI(), prop.getName())) {
076: value1 = config.dateToIndexString(IndexConfiguration
077: .getDateValue(literal1.getTextTrim()));
078: value2 = config.dateToIndexString(IndexConfiguration
079: .getDateValue(literal2.getTextTrim()));
080: } else if (index.getConfiguration().isIntProperty(
081: prop.getNamespaceURI(), prop.getName())) {
082: value1 = config.intToIndexString(Long.parseLong(literal1
083: .getTextTrim()));
084: value2 = config.intToIndexString(Long.parseLong(literal2
085: .getTextTrim()));
086: } else {
087: value1 = literal1.getTextTrim();
088: value2 = literal2.getTextTrim();
089:
090: if (!index.getConfiguration().isCaseSensitive()) {
091: value1 = value1.toLowerCase();
092: value2 = value2.toLowerCase();
093: }
094: }
095:
096: if (negated) {
097: setQuery(createQuery(field, value1, value2, !inclusive));
098: negateQuery(field);
099: } else {
100: setQuery(createQuery(field, value1, value2, inclusive));
101: }
102: }
103:
104: public BetweenExpression(Index index, String field,
105: String lowerValue, String upperValue, boolean incluseLower,
106: boolean incluseUpper, boolean negated) {
107: super (index);
108: if (incluseLower == incluseUpper) {
109: if (negated) {
110: setQuery(createQuery(field, lowerValue, upperValue,
111: !incluseLower));
112: negateQuery(field);
113: } else {
114: setQuery(createQuery(field, lowerValue, upperValue,
115: incluseLower));
116: }
117: } else {
118: // TODO what about negative integer values (predecessor,successor
119: // does not work with this)
120: if (incluseLower) {
121: setQuery(createQuery(field, lowerValue, index
122: .getConfiguration().predecessor(field,
123: upperValue), true));
124: } else {
125: setQuery(createQuery(field, index.getConfiguration()
126: .successor(field, lowerValue), upperValue, true));
127: }
128: }
129: }
130:
131: private void negateQuery(String field) {
132: BooleanQuery booleanQuery = new BooleanQuery();
133: booleanQuery.add(new TermQuery(new Term(
134: Index.IS_DEFINED_FIELD_NAME, field)),
135: BooleanClause.Occur.MUST); // required
136: booleanQuery.add(getQuery(), BooleanClause.Occur.MUST_NOT); // prohibited
137: setQuery(booleanQuery);
138: }
139:
140: private Query createQuery(String field, String value1,
141: String value2, boolean inclusive) {
142: int comp = value1.compareTo(value2);
143:
144: if (comp == 0) {
145: // value1 == value2
146: return new TermQuery(new Term(field, value1));
147: } else if (comp < 0) {
148: // value1 < value2
149: return new RangeQuery(new Term(field, value1), new Term(
150: field, value2), inclusive); // inclusive or not
151: } else {
152: // value1 > value2
153: return new RangeQuery(new Term(field, value2), new Term(
154: field, value1), inclusive); // inclusive or not
155: }
156: }
157:
158: }
|