From b83700b51e5ef2020ded30561c4c889fe2be3cb6 Mon Sep 17 00:00:00 2001 From: Mark Harwood Date: Sat, 27 Mar 2010 00:36:55 +0000 Subject: [PATCH] Lucene-2306: - Add NumericRangeQuery and NumericRangeFilter support to XMLQueryParser. Jingkei Ly via Mark Harwood git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@928114 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/contrib/CHANGES.txt | 2 + .../xml-query-parser/LuceneCoreQuery.dtd | 57 +- .../docs/LuceneContribQuery.dtd.entities.html | 6 +- .../docs/LuceneContribQuery.dtd.html | 221 ++++- .../docs/LuceneCoreQuery.dtd.entities.html | 6 +- .../docs/LuceneCoreQuery.dtd.html | 203 +++- .../docs/LuceneCoreQuery.dtd.org.html | 82 +- .../xml-query-parser/docs/elementsIndex.html | 7 +- lucene/contrib/xml-query-parser/docs/toc.html | 871 ++++++++++-------- .../apache/lucene/xmlparser/CoreParser.java | 3 +- .../builders/NumericRangeFilterBuilder.java | 165 ++++ .../builders/NumericRangeQueryBuilder.java | 127 +++ .../NumericRangeFilterBuilderTestCase.java | 216 +++++ .../NumericRangeQueryBuilderTestCase.java | 178 ++++ .../xmlparser/NumericRangeFilterQuery.xml | 21 + .../xmlparser/NumericRangeQueryQuery.xml | 15 + .../apache/lucene/xmlparser/TestParser.java | 16 + 17 files changed, 1731 insertions(+), 465 deletions(-) create mode 100644 lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeFilterBuilder.java create mode 100644 lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeQueryBuilder.java create mode 100644 lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeFilterBuilderTestCase.java create mode 100644 lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeQueryBuilderTestCase.java create mode 100644 lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeFilterQuery.xml create mode 100644 lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeQueryQuery.xml diff --git a/lucene/contrib/CHANGES.txt b/lucene/contrib/CHANGES.txt index 0f372ae9572..97a2fbfaac2 100644 --- a/lucene/contrib/CHANGES.txt +++ b/lucene/contrib/CHANGES.txt @@ -74,6 +74,8 @@ API Changes (Robert Muir, Uwe Schindler, Simon Willnauer) New features + * LUCENE-2306: Add NumericRangeFilter and NumericRangeQuery support to XMLQueryParser. + (Jingkei Ly, via Mark Harwood) * LUCENE-2102: Add a Turkish LowerCase Filter. TurkishLowerCaseFilter handles Turkish and Azeri unique casing behavior correctly. diff --git a/lucene/contrib/xml-query-parser/LuceneCoreQuery.dtd b/lucene/contrib/xml-query-parser/LuceneCoreQuery.dtd index 8cf7c36d38f..fdeaf6f7d35 100644 --- a/lucene/contrib/xml-query-parser/LuceneCoreQuery.dtd +++ b/lucene/contrib/xml-query-parser/LuceneCoreQuery.dtd @@ -54,8 +54,8 @@ - - + + @@ -283,7 +283,60 @@ Passes content directly through to the standard LuceneQuery parser see "Lucene Q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java index fa2f61738cb..c84b90a2981 100644 --- a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java +++ b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java @@ -70,13 +70,14 @@ public class CoreParser implements QueryBuilder this.parser=parser; filterFactory = new FilterBuilderFactory(); filterFactory.addBuilder("RangeFilter",new RangeFilterBuilder()); - + filterFactory.addBuilder("NumericRangeFilter",new NumericRangeFilterBuilder()); queryFactory = new QueryBuilderFactory(); queryFactory.addBuilder("TermQuery",new TermQueryBuilder()); queryFactory.addBuilder("TermsQuery",new TermsQueryBuilder(analyzer)); queryFactory.addBuilder("MatchAllDocsQuery",new MatchAllDocsQueryBuilder()); queryFactory.addBuilder("BooleanQuery",new BooleanQueryBuilder(queryFactory)); + queryFactory.addBuilder("NumericRangeQuery",new NumericRangeQueryBuilder()); if(parser!=null) { queryFactory.addBuilder("UserQuery",new UserInputQueryBuilder(parser)); diff --git a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeFilterBuilder.java b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeFilterBuilder.java new file mode 100644 index 00000000000..c834f8e4d98 --- /dev/null +++ b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeFilterBuilder.java @@ -0,0 +1,165 @@ +package org.apache.lucene.xmlparser.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +import java.io.IOException; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.DocIdSet; +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.NumericRangeFilter; +import org.apache.lucene.util.NumericUtils; +import org.apache.lucene.xmlparser.DOMUtils; +import org.apache.lucene.xmlparser.FilterBuilder; +import org.apache.lucene.xmlparser.ParserException; +import org.w3c.dom.Element; + +/** + * Creates a {@link NumericRangeFilter}. The table below specifies the required + * attributes and the defaults if optional attributes are omitted. For more + * detail on what each of the attributes actually do, consult the documentation + * for {@link NumericRangeFilter}: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Attribute nameValuesRequiredDefault
fieldNameStringYesN/A
lowerTermSpecified by typeYesN/A
upperTermSpecified by typeYesN/A
typeint, long, float, doubleNoint
includeLowertrue, falseNotrue
includeUppertrue, falseNotrue
precisionStepIntegerNo4
+ *

+ * If an error occurs parsing the supplied lowerTerm or + * upperTerm into the numeric type specified by type, then the + * error will be silently ignored and the resulting filter will not match any + * documents. + */ +public class NumericRangeFilterBuilder implements FilterBuilder { + private static final NoMatchFilter NO_MATCH_FILTER = new NoMatchFilter(); + + private boolean strictMode = false; + + /** + * Specifies how this {@link NumericRangeFilterBuilder} will handle errors. + *

+ * If this is set to true, {@link #getFilter(Element)} will throw a + * {@link ParserException} if it is unable to parse the lowerTerm or upperTerm + * into the appropriate numeric type. If this is set to false, then this + * exception will be silently ignored and the resulting filter will not match + * any documents. + *

+ * Defaults to false. + * + * @param strictMode + */ + public void setStrictMode(boolean strictMode) { + this.strictMode = strictMode; + } + + public Filter getFilter(Element e) throws ParserException { + String field = DOMUtils.getAttributeWithInheritanceOrFail(e, "fieldName"); + String lowerTerm = DOMUtils.getAttributeOrFail(e, "lowerTerm"); + String upperTerm = DOMUtils.getAttributeOrFail(e, "upperTerm"); + boolean lowerInclusive = DOMUtils.getAttribute(e, "includeLower", true); + boolean upperInclusive = DOMUtils.getAttribute(e, "includeUpper", true); + int precisionStep = DOMUtils.getAttribute(e, "precisionStep", NumericUtils.PRECISION_STEP_DEFAULT); + + String type = DOMUtils.getAttribute(e, "type", "int"); + try { + Filter filter; + if (type.equalsIgnoreCase("int")) { + filter = NumericRangeFilter.newIntRange(field, precisionStep, Integer + .valueOf(lowerTerm), Integer.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else if (type.equalsIgnoreCase("long")) { + filter = NumericRangeFilter.newLongRange(field, precisionStep, Long + .valueOf(lowerTerm), Long.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else if (type.equalsIgnoreCase("double")) { + filter = NumericRangeFilter.newDoubleRange(field, precisionStep, Double + .valueOf(lowerTerm), Double.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else if (type.equalsIgnoreCase("float")) { + filter = NumericRangeFilter.newFloatRange(field, precisionStep, Float + .valueOf(lowerTerm), Float.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else { + throw new ParserException( + "type attribute must be one of: [long, int, double, float]"); + } + return filter; + } catch (NumberFormatException nfe) { + if (strictMode) { + throw new ParserException( + "Could not parse lowerTerm or upperTerm into a number", nfe); + } + return NO_MATCH_FILTER; + } + } + + static class NoMatchFilter extends Filter { + private static final long serialVersionUID = 1L; + + @Override + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { + return null; + } + + } +} diff --git a/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeQueryBuilder.java b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeQueryBuilder.java new file mode 100644 index 00000000000..5cf129ab501 --- /dev/null +++ b/lucene/contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeQueryBuilder.java @@ -0,0 +1,127 @@ +package org.apache.lucene.xmlparser.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +import org.apache.lucene.search.NumericRangeQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.util.NumericUtils; +import org.apache.lucene.xmlparser.DOMUtils; +import org.apache.lucene.xmlparser.ParserException; +import org.apache.lucene.xmlparser.QueryBuilder; +import org.w3c.dom.Element; + +/** + * Creates a {@link NumericRangeQuery}. The table below specifies the required + * attributes and the defaults if optional attributes are omitted. For more + * detail on what each of the attributes actually do, consult the documentation + * for {@link NumericRangeQuery}: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Attribute nameValuesRequiredDefault
fieldNameStringYesN/A
lowerTermSpecified by typeYesN/A
upperTermSpecified by typeYesN/A
typeint, long, float, doubleNoint
includeLowertrue, falseNotrue
includeUppertrue, falseNotrue
precisionStepIntegerNo4
+ *

+ * A {@link ParserException} will be thrown if an error occurs parsing the + * supplied lowerTerm or upperTerm into the numeric type + * specified by type. + */ +public class NumericRangeQueryBuilder implements QueryBuilder { + + public Query getQuery(Element e) throws ParserException { + String field = DOMUtils.getAttributeWithInheritanceOrFail(e, "fieldName"); + String lowerTerm = DOMUtils.getAttributeOrFail(e, "lowerTerm"); + String upperTerm = DOMUtils.getAttributeOrFail(e, "upperTerm"); + boolean lowerInclusive = DOMUtils.getAttribute(e, "includeLower", true); + boolean upperInclusive = DOMUtils.getAttribute(e, "includeUpper", true); + int precisionStep = DOMUtils.getAttribute(e, "precisionStep", NumericUtils.PRECISION_STEP_DEFAULT); + + String type = DOMUtils.getAttribute(e, "type", "int"); + try { + Query filter; + if (type.equalsIgnoreCase("int")) { + filter = NumericRangeQuery.newIntRange(field, precisionStep, Integer + .valueOf(lowerTerm), Integer.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else if (type.equalsIgnoreCase("long")) { + filter = NumericRangeQuery.newLongRange(field, precisionStep, Long + .valueOf(lowerTerm), Long.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else if (type.equalsIgnoreCase("double")) { + filter = NumericRangeQuery.newDoubleRange(field, precisionStep, Double + .valueOf(lowerTerm), Double.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else if (type.equalsIgnoreCase("float")) { + filter = NumericRangeQuery.newFloatRange(field, precisionStep, Float + .valueOf(lowerTerm), Float.valueOf(upperTerm), lowerInclusive, + upperInclusive); + } else { + throw new ParserException( + "type attribute must be one of: [long, int, double, float]"); + } + return filter; + } catch (NumberFormatException nfe) { + throw new ParserException( + "Could not parse lowerTerm or upperTerm into a number", nfe); + } + } +} diff --git a/lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeFilterBuilderTestCase.java b/lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeFilterBuilderTestCase.java new file mode 100644 index 00000000000..8acf9227a03 --- /dev/null +++ b/lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeFilterBuilderTestCase.java @@ -0,0 +1,216 @@ +package com.apache.lucene.xmlparser.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import junit.framework.TestCase; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriter.MaxFieldLength; +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.NumericRangeFilter; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.xmlparser.ParserException; +import org.apache.lucene.xmlparser.builders.NumericRangeFilterBuilder; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public class NumericRangeFilterBuilderTestCase extends TestCase { + + public void testGetFilterHandleNumericParseErrorStrict() throws Exception { + NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder(); + filterBuilder.setStrictMode(true); + + String xml = ""; + Document doc = getDocumentFromString(xml); + try { + filterBuilder.getFilter(doc.getDocumentElement()); + } catch (ParserException e) { + return; + } + fail("Expected to throw " + ParserException.class); + } + + public void testGetFilterHandleNumericParseError() throws Exception { + NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder(); + filterBuilder.setStrictMode(false); + + String xml = ""; + Document doc = getDocumentFromString(xml); + Filter filter = filterBuilder.getFilter(doc.getDocumentElement()); + + RAMDirectory ramDir = new RAMDirectory(); + IndexWriter writer = new IndexWriter(ramDir, null, MaxFieldLength.UNLIMITED); + try + { + IndexReader reader = IndexReader.open(ramDir, true); + try + { + assertNull(filter.getDocIdSet(reader)); + } + finally + { + reader.close(); + } + } + finally + { + writer.commit(); + writer.close(); + } + } + + public void testGetFilterInt() throws Exception { + NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder(); + filterBuilder.setStrictMode(true); + + String xml = ""; + Document doc = getDocumentFromString(xml); + Filter filter = filterBuilder.getFilter(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter = (NumericRangeFilter) filter; + assertEquals(Integer.valueOf(-1), numRangeFilter.getMin()); + assertEquals(Integer.valueOf(10), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter2 = (NumericRangeFilter) filter2; + assertEquals(Integer.valueOf(-1), numRangeFilter2.getMin()); + assertEquals(Integer.valueOf(10), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + public void testGetFilterLong() throws Exception { + NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder(); + filterBuilder.setStrictMode(true); + + String xml = ""; + Document doc = getDocumentFromString(xml); + Filter filter = filterBuilder.getFilter(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter = (NumericRangeFilter) filter; + assertEquals(Long.valueOf(-2321L), numRangeFilter.getMin()); + assertEquals(Long.valueOf(60000000L), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter2 = (NumericRangeFilter) filter2; + assertEquals(Long.valueOf(-2321L), numRangeFilter2.getMin()); + assertEquals(Long.valueOf(60000000L), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + public void testGetFilterDouble() throws Exception { + NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder(); + filterBuilder.setStrictMode(true); + + String xml = ""; + Document doc = getDocumentFromString(xml); + + Filter filter = filterBuilder.getFilter(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter = (NumericRangeFilter) filter; + assertEquals(Double.valueOf(-23.21d), numRangeFilter.getMin()); + assertEquals(Double.valueOf(60000.00023d), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter2 = (NumericRangeFilter) filter2; + assertEquals(Double.valueOf(-23.21d), numRangeFilter2.getMin()); + assertEquals(Double.valueOf(60000.00023d), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + public void testGetFilterFloat() throws Exception { + NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder(); + filterBuilder.setStrictMode(true); + + String xml = ""; + Document doc = getDocumentFromString(xml); + + Filter filter = filterBuilder.getFilter(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter = (NumericRangeFilter) filter; + assertEquals(Float.valueOf(-2.321432f), numRangeFilter.getMin()); + assertEquals(Float.valueOf(32432.23f), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + + Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeFilter); + @SuppressWarnings("unchecked") + NumericRangeFilter numRangeFilter2 = (NumericRangeFilter) filter2; + assertEquals(Float.valueOf(-2.321432f), numRangeFilter2.getMin()); + assertEquals(Float.valueOf(32432.23f), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + private static Document getDocumentFromString(String str) + throws SAXException, IOException, ParserConfigurationException { + InputStream is = new ByteArrayInputStream(str.getBytes()); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(is); + is.close(); + return doc; + } + +} diff --git a/lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeQueryBuilderTestCase.java b/lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeQueryBuilderTestCase.java new file mode 100644 index 00000000000..1c9e81edd73 --- /dev/null +++ b/lucene/contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeQueryBuilderTestCase.java @@ -0,0 +1,178 @@ +package com.apache.lucene.xmlparser.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import junit.framework.TestCase; + +import org.apache.lucene.search.NumericRangeQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.xmlparser.ParserException; +import org.apache.lucene.xmlparser.builders.NumericRangeQueryBuilder; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +public class NumericRangeQueryBuilderTestCase extends TestCase { + + public void testGetFilterHandleNumericParseErrorStrict() throws Exception { + NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder(); + + String xml = ""; + Document doc = getDocumentFromString(xml); + try { + filterBuilder.getQuery(doc.getDocumentElement()); + } catch (ParserException e) { + return; + } + fail("Expected to throw " + ParserException.class); + } + + public void testGetFilterInt() throws Exception { + NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder(); + + String xml = ""; + Document doc = getDocumentFromString(xml); + Query filter = filterBuilder.getQuery(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter = (NumericRangeQuery) filter; + assertEquals(Integer.valueOf(-1), numRangeFilter.getMin()); + assertEquals(Integer.valueOf(10), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter2 = (NumericRangeQuery) filter2; + assertEquals(Integer.valueOf(-1), numRangeFilter2.getMin()); + assertEquals(Integer.valueOf(10), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + public void testGetFilterLong() throws Exception { + NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder(); + + String xml = ""; + Document doc = getDocumentFromString(xml); + Query filter = filterBuilder.getQuery(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter = (NumericRangeQuery) filter; + assertEquals(Long.valueOf(-2321L), numRangeFilter.getMin()); + assertEquals(Long.valueOf(60000000L), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter2 = (NumericRangeQuery) filter2; + assertEquals(Long.valueOf(-2321L), numRangeFilter2.getMin()); + assertEquals(Long.valueOf(60000000L), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + public void testGetFilterDouble() throws Exception { + NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder(); + + String xml = ""; + Document doc = getDocumentFromString(xml); + + Query filter = filterBuilder.getQuery(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter = (NumericRangeQuery) filter; + assertEquals(Double.valueOf(-23.21d), numRangeFilter.getMin()); + assertEquals(Double.valueOf(60000.00023d), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter2 = (NumericRangeQuery) filter2; + assertEquals(Double.valueOf(-23.21d), numRangeFilter2.getMin()); + assertEquals(Double.valueOf(60000.00023d), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + public void testGetFilterFloat() throws Exception { + NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder(); + + String xml = ""; + Document doc = getDocumentFromString(xml); + + Query filter = filterBuilder.getQuery(doc.getDocumentElement()); + assertTrue(filter instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter = (NumericRangeQuery) filter; + assertEquals(Float.valueOf(-2.321432f), numRangeFilter.getMin()); + assertEquals(Float.valueOf(32432.23f), numRangeFilter.getMax()); + assertEquals("AGE", numRangeFilter.getField()); + assertTrue(numRangeFilter.includesMin()); + assertTrue(numRangeFilter.includesMax()); + + String xml2 = ""; + Document doc2 = getDocumentFromString(xml2); + + Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement()); + assertTrue(filter2 instanceof NumericRangeQuery); + @SuppressWarnings("unchecked") + NumericRangeQuery numRangeFilter2 = (NumericRangeQuery) filter2; + assertEquals(Float.valueOf(-2.321432f), numRangeFilter2.getMin()); + assertEquals(Float.valueOf(32432.23f), numRangeFilter2.getMax()); + assertEquals("AGE", numRangeFilter2.getField()); + assertTrue(numRangeFilter2.includesMin()); + assertFalse(numRangeFilter2.includesMax()); + } + + private static Document getDocumentFromString(String str) + throws SAXException, IOException, ParserConfigurationException { + InputStream is = new ByteArrayInputStream(str.getBytes()); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(is); + is.close(); + return doc; + } + +} diff --git a/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeFilterQuery.xml b/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeFilterQuery.xml new file mode 100644 index 00000000000..aed33bc2e66 --- /dev/null +++ b/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeFilterQuery.xml @@ -0,0 +1,21 @@ + + + + + + merger + + + sumitomo + + + bank + + + + + + + + + diff --git a/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeQueryQuery.xml b/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeQueryQuery.xml new file mode 100644 index 00000000000..f3c976b93b8 --- /dev/null +++ b/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeQueryQuery.xml @@ -0,0 +1,15 @@ + + + + merger + + + sumitomo + + + bank + + + + + diff --git a/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java b/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java index 599dc50d096..eaa56f80938 100644 --- a/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java +++ b/lucene/contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java @@ -8,6 +8,7 @@ import java.io.InputStreamReader; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Field; +import org.apache.lucene.document.NumericField; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; @@ -70,6 +71,9 @@ public class TestParser extends LuceneTestCase { org.apache.lucene.document.Document doc =new org.apache.lucene.document.Document(); doc.add(new Field("date",date,Field.Store.YES,Field.Index.ANALYZED)); doc.add(new Field("contents",content,Field.Store.YES,Field.Index.ANALYZED)); + NumericField numericField = new NumericField("date2"); + numericField.setIntValue(Integer.valueOf(date)); + doc.add(numericField); writer.addDocument(doc); line=d.readLine(); } @@ -191,6 +195,18 @@ public class TestParser extends LuceneTestCase { assertEquals("DuplicateFilterQuery should produce 1 result ", 1,h); } + public void testNumericRangeFilterQueryXML() throws ParserException, IOException + { + Query q=parse("NumericRangeFilterQuery.xml"); + dumpResults("NumericRangeFilter", q, 5); + } + + public void testNumericRangeQueryQueryXML() throws ParserException, IOException + { + Query q=parse("NumericRangeQueryQuery.xml"); + dumpResults("NumericRangeQuery", q, 5); + } + //================= Helper methods ===================================