You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/07/08 16:44:42 UTC
svn commit: r209797 - in /incubator/jackrabbit/trunk/core/src:
java/org/apache/jackrabbit/core/query/lucene/
test/org/apache/jackrabbit/core/query/
Author: mreutegg
Date: Fri Jul 8 07:44:41 2005
New Revision: 209797
URL: http://svn.apache.org/viewcvs?rev=209797&view=rev
Log:
JCR-111: org.apache.lucene.search.BooleanQuery$TooManyClauses when using '>' operator
Added:
incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java (with props)
incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/MassiveRangeTest.java (with props)
Modified:
incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/TestAll.java
Modified: incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java?rev=209797&r1=209796&r2=209797&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java Fri Jul 8 07:44:41 2005
@@ -47,7 +47,6 @@
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
-import org.apache.lucene.search.RangeQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.xerces.util.XMLChar;
Added: incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java?rev=209797&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java (added)
+++ incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java Fri Jul 8 07:44:41 2005
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.query.lucene;
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Similarity;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.index.TermDocs;
+
+import java.io.IOException;
+import java.util.BitSet;
+
+/**
+ * Implements a variant of the lucene class {@link org.apache.lucene.search.RangeQuery}.
+ * This class does not rewrite to basic {@link org.apache.lucene.search.TermQuery}
+ * but will calculate the matching documents itself. That way a
+ * <code>TooManyClauses</code> can be avoided.
+ */
+public class RangeQuery extends Query {
+
+ /**
+ * The lower term. May be <code>null</code> if <code>upperTerm</code> is not
+ * <code>null</code>.
+ */
+ private Term lowerTerm;
+
+ /**
+ * The upper term. May be <code>null</code> if <code>lowerTerm</code> is not
+ * <code>null</code>.
+ */
+ private Term upperTerm;
+
+ /**
+ * If <code>true</code> the range interval is inclusive.
+ */
+ private boolean inclusive;
+
+ /**
+ * Creates a new RangeQuery. The lower or the upper term may be
+ * <code>null</code>, but not both!
+ *
+ * @param lowerTerm the lower term of the interval, or <code>null</code>
+ * @param upperTerm the upper term of the interval, or <code>null</code>.
+ * @param inclusive if <code>true</code> the interval is inclusive.
+ */
+ public RangeQuery(Term lowerTerm, Term upperTerm, boolean inclusive) {
+ if (lowerTerm == null && upperTerm == null) {
+ throw new IllegalArgumentException("At least one term must be non-null");
+ }
+ if (lowerTerm != null && upperTerm != null && lowerTerm.field() != upperTerm.field()) {
+ throw new IllegalArgumentException("Both terms must be for the same field");
+ }
+
+ // if we have a lowerTerm, start there. otherwise, start at beginning
+ if (lowerTerm != null) {
+ this.lowerTerm = lowerTerm;
+ } else {
+ this.lowerTerm = new Term(upperTerm.field(), "");
+ }
+
+ this.upperTerm = upperTerm;
+ this.inclusive = inclusive;
+ }
+
+ /**
+ * Creates the <code>Weight</code> for this query.
+ *
+ * @param searcher the searcher to use for the <code>Weight</code>.
+ * @return the <code>Weigth</code> for this query.
+ */
+ protected Weight createWeight(Searcher searcher) {
+ return new RangeQueryWeight(searcher);
+ }
+
+ /**
+ * Returns a string representation of this query.
+ * @param field the field name for which to create a string representation.
+ * @return a string representation of this query.
+ */
+ public String toString(String field) {
+ StringBuffer buffer = new StringBuffer();
+ if (!getField().equals(field)) {
+ buffer.append(getField());
+ buffer.append(":");
+ }
+ buffer.append(inclusive ? "[" : "{");
+ buffer.append(lowerTerm != null ? lowerTerm.text() : "null");
+ buffer.append(" TO ");
+ buffer.append(upperTerm != null ? upperTerm.text() : "null");
+ buffer.append(inclusive ? "]" : "}");
+ if (getBoost() != 1.0f) {
+ buffer.append("^");
+ buffer.append(Float.toString(getBoost()));
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the field name for this query.
+ */
+ private String getField() {
+ return (lowerTerm != null ? lowerTerm.field() : upperTerm.field());
+ }
+
+ //--------------------------< RangeQueryWeight >----------------------------
+
+ /**
+ * The <code>Weight</code> implementation for this <code>RangeQuery</code>.
+ */
+ private class RangeQueryWeight implements Weight {
+
+ /**
+ * The searcher in use
+ */
+ private final Searcher searcher;
+
+ /**
+ * Creates a new <code>RangeQueryWeight</code> instance using
+ * <code>searcher</code>.
+ *
+ * @param searcher a <code>Searcher</code> instance.
+ */
+ RangeQueryWeight(Searcher searcher) {
+ this.searcher = searcher;
+ }
+
+ /**
+ * Returns this <code>RangeQuery</code>.
+ *
+ * @return this <code>RangeQuery</code>.
+ */
+ public Query getQuery() {
+ return RangeQuery.this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public float getValue() {
+ return 1.0f;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public float sumOfSquaredWeights() throws IOException {
+ return 1.0f;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void normalize(float norm) {
+ }
+
+ /**
+ * Creates a scorer for this <code>Rangequery</code>.
+ *
+ * @param reader a reader for accessing the index.
+ * @return a <code>RangeQueryScorer</code>.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public Scorer scorer(IndexReader reader) throws IOException {
+ return new RangeQueryScorer(searcher.getSimilarity(), reader);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Explanation explain(IndexReader reader, int doc) throws IOException {
+ return new Explanation();
+ }
+ }
+
+ //------------------------< RangeQueryScorer >------------------------------
+
+ /**
+ * Implements a <code>Scorer</code> for this <code>RangeQuery</code>.
+ */
+ private final class RangeQueryScorer extends Scorer {
+
+ /**
+ * The index reader to use for calculating the matching documents.
+ */
+ private final IndexReader reader;
+
+ /**
+ * The documents ids that match this range query.
+ */
+ private final BitSet hits;
+
+ /**
+ * Set to <code>true</code> when the hits have been calculated.
+ */
+ private boolean hitsCalculated = false;
+
+ /**
+ * The next document id to return
+ */
+ private int nextDoc = -1;
+
+ /**
+ * Creates a new RangeQueryScorer.
+ * @param similarity the similarity implementation.
+ * @param reader the index reader to use.
+ */
+ RangeQueryScorer(Similarity similarity, IndexReader reader) {
+ super(similarity);
+ this.reader = reader;
+ hits = new BitSet(reader.maxDoc());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean next() throws IOException {
+ calculateHits();
+ nextDoc = hits.nextSetBit(nextDoc + 1);
+ return nextDoc > -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int doc() {
+ return nextDoc;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public float score() {
+ return 1.0f;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean skipTo(int target) {
+ nextDoc = hits.nextSetBit(target);
+ return nextDoc > -1;
+ }
+
+ /**
+ * Returns an empty Explanation object.
+ * @return an empty Explanation object.
+ */
+ public Explanation explain(int doc) {
+ return new Explanation();
+ }
+
+ /**
+ * Calculates the ids of the documents matching this range query.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ private void calculateHits() throws IOException {
+ if (hitsCalculated) {
+ return;
+ }
+
+ TermEnum enumerator = reader.terms(lowerTerm);
+
+ try {
+ boolean checkLower = false;
+ if (!inclusive) {
+ // make adjustments to set to exclusive
+ checkLower = true;
+ }
+
+ String testField = getField();
+
+ do {
+ Term term = enumerator.term();
+ if (term != null && term.field() == testField) {
+ if (!checkLower || term.text().compareTo(lowerTerm.text()) > 0) {
+ checkLower = false;
+ if (upperTerm != null) {
+ int compare = upperTerm.text().compareTo(term.text());
+ // if beyond the upper term, or is exclusive and
+ // this is equal to the upper term, break out
+ if ((compare < 0) || (!inclusive && compare == 0)) {
+ break;
+ }
+ }
+
+ TermDocs td = reader.termDocs(term);
+ try {
+ while (td.next()) {
+ hits.set(td.doc());
+ }
+ } finally {
+ td.close();
+ }
+ }
+ } else {
+ break;
+ }
+ } while (enumerator.next());
+ } finally {
+ enumerator.close();
+ }
+ hitsCalculated = true;
+ }
+ }
+}
Propchange: incubator/jackrabbit/trunk/core/src/java/org/apache/jackrabbit/core/query/lucene/RangeQuery.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/MassiveRangeTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/MassiveRangeTest.java?rev=209797&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/MassiveRangeTest.java (added)
+++ incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/MassiveRangeTest.java Fri Jul 8 07:44:41 2005
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.query;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+
+/**
+ * Tests if a range query with a lot of results does not throw an error.
+ */
+public class MassiveRangeTest extends AbstractQueryTest {
+
+ /**
+ * Executes a range query covering 2'000 different property values.
+ */
+ public void testRangeQuery() throws RepositoryException {
+ int count = 0;
+ for (int i = 0; i < 20; i++) {
+ Node child = testRootNode.addNode("node" + i);
+ for (int j = 0; j < 100; j++) {
+ Node n = child.addNode("node" + j);
+ n.setProperty("foo", count++);
+ }
+ // save every 100 nodes
+ testRootNode.save();
+ }
+
+ QueryManager qm = superuser.getWorkspace().getQueryManager();
+ String stmt = testPath + "//*[@foo >= 0]";
+ QueryResult res = qm.createQuery(stmt, Query.XPATH).execute();
+ checkResult(res, 2000);
+ }
+}
Propchange: incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/MassiveRangeTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/TestAll.java?rev=209797&r1=209796&r2=209797&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/TestAll.java (original)
+++ incubator/jackrabbit/trunk/core/src/test/org/apache/jackrabbit/core/query/TestAll.java Fri Jul 8 07:44:41 2005
@@ -43,6 +43,7 @@
suite.addTestSuite(OrderByTest.class);
suite.addTestSuite(XPathAxisTest.class);
suite.addTestSuite(SkipDeletedNodesTest.class);
+ suite.addTestSuite(MassiveRangeTest.class);
return suite;
}