dnaber 2004/12/12 07:27:49 Modified: src/java/org/apache/lucene/queryParser MultiFieldQueryParser.java Added: src/test/org/apache/lucene/queryParser TestMultiFieldQueryParser.java Log: Deprecate the old constructors and the main parse(...) method. The new one now generates a query that works as expected for both AND and OR mode. Also do better argument checking in the static methods and throw IllegalArgumentException if something is wrong. Revision Changes Path 1.7 +123 -18 jakarta-lucene/src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java Index: MultiFieldQueryParser.java =================================================================== RCS file: /home/cvs/jakarta-lucene/src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- MultiFieldQueryParser.java 27 Aug 2004 21:50:17 -0000 1.6 +++ MultiFieldQueryParser.java 12 Dec 2004 15:27:49 -0000 1.7 @@ -16,11 +16,9 @@ * limitations under the License. */ +import java.util.Vector; + import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.queryParser.CharStream; -import org.apache.lucene.queryParser.ParseException; -import org.apache.lucene.queryParser.QueryParser; -import org.apache.lucene.queryParser.QueryParserTokenManager; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; @@ -33,20 +31,121 @@ */ public class MultiFieldQueryParser extends QueryParser { + + private String[] fields; + + /** + * <p>Creates a MultiFieldQueryParser that will, when parse(String query) + * is called, construct a query like this (assuming the query consists of + * two terms and you specify the two fields <code>title</code> and <code>body</code>):</p> + * + * <code> + * (title:term1 body:term1) (title:term2 body:term2) + * </code> + * + * <p>When setDefaultOperator(AND_OPERATOR) is set, the result will be:</p> + * + * <code> + * +(title:term1 body:term1) +(title:term2 body:term2) + * </code> + * + * <p>In other words, all the query's terms must appear, but it doesn't matter in + * what fields they appear.</p> + */ + public MultiFieldQueryParser(String[] fields, Analyzer analyzer) { + super(null, analyzer); + this.fields = fields; + } + + protected Query getFieldQuery(String field, Analyzer analyzer, String queryText) + throws ParseException { + if (field == null) { + Vector clauses = new Vector(); + for (int i = 0; i < fields.length; i++) + clauses.add(new BooleanClause(super.getFieldQuery(fields[i], queryText), + BooleanClause.Occur.SHOULD)); + return getBooleanQuery(clauses); + } + return super.getFieldQuery(field, queryText); + } + + /** + * @deprecated use [EMAIL PROTECTED] #getFuzzyQuery(String, String, float)} + */ + protected Query getFuzzyQuery(String field, String termStr) throws ParseException { + return getFuzzyQuery(field, termStr, fuzzyMinSim); + } + + protected Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException + { + if (field == null) { + Vector clauses = new Vector(); + for (int i = 0; i < fields.length; i++) { + clauses.add(new BooleanClause(super.getFuzzyQuery(fields[i], termStr, minSimilarity), + BooleanClause.Occur.SHOULD)); + } + return getBooleanQuery(clauses); + } + return super.getFuzzyQuery(field, termStr, minSimilarity); + } + + protected Query getPrefixQuery(String field, String termStr) throws ParseException + { + if (field == null) { + Vector clauses = new Vector(); + for (int i = 0; i < fields.length; i++) { + clauses.add(new BooleanClause(super.getPrefixQuery(fields[i], termStr), + BooleanClause.Occur.SHOULD)); + } + return getBooleanQuery(clauses); + } + return super.getPrefixQuery(field, termStr); + } + + /** @throws ParseException + * @deprecated use [EMAIL PROTECTED] #getRangeQuery(String, String, String, boolean)} + */ + protected Query getRangeQuery(String field, Analyzer analyzer, + String part1, String part2, boolean inclusive) throws ParseException { + return getRangeQuery(field, part1, part2, inclusive); + } + + protected Query getRangeQuery(String field, String part1, String part2, boolean inclusive) throws ParseException { + if (field == null) { + Vector clauses = new Vector(); + for (int i = 0; i < fields.length; i++) { + clauses.add(new BooleanClause(super.getRangeQuery(fields[i], part1, part2, inclusive), + BooleanClause.Occur.SHOULD)); + } + return getBooleanQuery(clauses); + } + return super.getRangeQuery(field, part1, part2, inclusive); + } + + public static final int NORMAL_FIELD = 0; public static final int REQUIRED_FIELD = 1; public static final int PROHIBITED_FIELD = 2; + /** + * @deprecated use [EMAIL PROTECTED] #MultiFieldQueryParser(String[], Analyzer)} instead + */ public MultiFieldQueryParser(QueryParserTokenManager tm) { super(tm); } + /** + * @deprecated use [EMAIL PROTECTED] #MultiFieldQueryParser(String[], Analyzer)} instead + */ public MultiFieldQueryParser(CharStream stream) { super(stream); } + /** + * @deprecated use [EMAIL PROTECTED] #MultiFieldQueryParser(String[], Analyzer)} instead + */ public MultiFieldQueryParser(String f, Analyzer a) { super(f, a); @@ -68,6 +167,7 @@ * @param analyzer Analyzer to use * @throws ParseException if query parsing fails * @throws TokenMgrError if query parsing fails + * @deprecated use [EMAIL PROTECTED] #parse(String)} instead */ public static Query parse(String query, String[] fields, Analyzer analyzer) throws ParseException @@ -96,13 +196,14 @@ * @param analyzer Analyzer to use * @throws ParseException if query parsing fails * @throws TokenMgrError if query parsing fails + * @throws IllegalArgumentException if the length of the queries array differs + * from the length of the fields array */ public static Query parse(String[] queries, String[] fields, Analyzer analyzer) throws ParseException { if (queries.length != fields.length) - // TODO Exception handling - throw new ParseException("queries.length != fields.length"); + throw new IllegalArgumentException("queries.length != fields.length"); BooleanQuery bQuery = new BooleanQuery(); for (int i = 0; i < fields.length; i++) { @@ -121,9 +222,9 @@ * Usage: * <code> * String[] fields = {"filename", "contents", "description"}; - * int[] flags = {MultiFieldQueryParser.NORMAL FIELD, - * MultiFieldQueryParser.REQUIRED FIELD, - * MultiFieldQueryParser.PROHIBITED FIELD,}; + * int[] flags = {MultiFieldQueryParser.NORMAL_FIELD, + * MultiFieldQueryParser.REQUIRED_FIELD, + * MultiFieldQueryParser.PROHIBITED_FIELD,}; * parse(query, fields, flags, analyzer); * </code> * </pre> @@ -141,11 +242,14 @@ * @param analyzer Analyzer to use * @throws ParseException if query parsing fails * @throws TokenMgrError if query parsing fails + * @throws IllegalArgumentException if the length of the fields array differs + * from the length of the flags array */ public static Query parse(String query, String[] fields, int[] flags, - Analyzer analyzer) - throws ParseException + Analyzer analyzer) throws ParseException { + if (fields.length != flags.length) + throw new IllegalArgumentException("fields.length != flags.length"); BooleanQuery bQuery = new BooleanQuery(); for (int i = 0; i < fields.length; i++) { @@ -176,9 +280,9 @@ * Usage: * <code> * String[] fields = {"filename", "contents", "description"}; - * int[] flags = {MultiFieldQueryParser.NORMAL FIELD, - * MultiFieldQueryParser.REQUIRED FIELD, - * MultiFieldQueryParser.PROHIBITED FIELD,}; + * int[] flags = {MultiFieldQueryParser.NORMAL_FIELD, + * MultiFieldQueryParser.REQUIRED_FIELD, + * MultiFieldQueryParser.PROHIBITED_FIELD,}; * parse(query, fields, flags, analyzer); * </code> * </pre> @@ -196,13 +300,14 @@ * @param analyzer Analyzer to use * @throws ParseException if query parsing fails * @throws TokenMgrError if query parsing fails + * @throws IllegalArgumentException if the length of the queries, fields, + * and flags array differ */ public static Query parse(String[] queries, String[] fields, int[] flags, Analyzer analyzer) throws ParseException { - if (queries.length != fields.length) - // TODO Exception handling - throw new ParseException("queries.length != fields.length"); + if (!(queries.length == fields.length && queries.length == flags.length)) + throw new IllegalArgumentException("queries, fields, and flags array have have different length"); BooleanQuery bQuery = new BooleanQuery(); for (int i = 0; i < fields.length; i++) { 1.1 jakarta-lucene/src/test/org/apache/lucene/queryParser/TestMultiFieldQueryParser.java Index: TestMultiFieldQueryParser.java =================================================================== package org.apache.lucene.queryParser; /** * Copyright 2004 The Apache Software Foundation * * 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. */ import junit.framework.TestCase; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.search.Query; /** * Tests QueryParser. * @author Daniel Naber */ public class TestMultiFieldQueryParser extends TestCase { public void testSimple() throws Exception { String[] fields = {"b", "t"}; MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields, new StandardAnalyzer()); Query q = mfqp.parse("one"); assertEquals("b:one t:one", q.toString()); q = mfqp.parse("one two"); assertEquals("(b:one t:one) (b:two t:two)", q.toString()); q = mfqp.parse("+one +two"); assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); q = mfqp.parse("+one -two -three)"); assertEquals("+(b:one t:one) -(b:two t:two) -(b:three t:three)", q.toString()); q = mfqp.parse("one^2 two"); assertEquals("((b:one t:one)^2.0) (b:two t:two)", q.toString()); q = mfqp.parse("one~ two"); assertEquals("(b:one~0.5 t:one~0.5) (b:two t:two)", q.toString()); q = mfqp.parse("one~0.8 two^2"); assertEquals("(b:one~0.8 t:one~0.8) ((b:two t:two)^2.0)", q.toString()); q = mfqp.parse("one* two*"); assertEquals("(b:one* t:one*) (b:two* t:two*)", q.toString()); q = mfqp.parse("[a TO c] two"); assertEquals("(b:[a TO c] t:[a TO c]) (b:two t:two)", q.toString()); // make sure that terms which have a field are not touched: q = mfqp.parse("one f:two"); assertEquals("(b:one t:one) f:two", q.toString()); // AND mode: mfqp.setDefaultOperator(QueryParser.AND_OPERATOR); q = mfqp.parse("one two"); assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); } // TODO: remove this for Lucene 2.0 public void testOldMethods() throws ParseException { // testing the old static calls that are now deprecated: assertQueryEquals("b:one t:one", "one"); assertQueryEquals("(b:one b:two) (t:one t:two)", "one two"); assertQueryEquals("(b:one -b:two) (t:one -t:two)", "one -two"); assertQueryEquals("(b:one -(b:two b:three)) (t:one -(t:two t:three))", "one -(two three)"); assertQueryEquals("(+b:one +b:two) (+t:one +t:two)", "+one +two"); } // TODO: remove this for Lucene 2.0 private void assertQueryEquals(String expected, String query) throws ParseException { String[] fields = {"b", "t"}; Query q = MultiFieldQueryParser.parse(query, fields, new StandardAnalyzer()); String s = q.toString(); assertEquals(expected, s); } public void testStaticMethod1() throws ParseException { String[] fields = {"b", "t"}; String[] queries = {"one", "two"}; Query q = MultiFieldQueryParser.parse(queries, fields, new StandardAnalyzer()); assertEquals("b:one t:two", q.toString()); String[] queries2 = {"+one", "+two"}; q = MultiFieldQueryParser.parse(queries2, fields, new StandardAnalyzer()); assertEquals("(+b:one) (+t:two)", q.toString()); String[] queries3 = {"one", "+two"}; q = MultiFieldQueryParser.parse(queries3, fields, new StandardAnalyzer()); assertEquals("b:one (+t:two)", q.toString()); String[] queries4 = {"one +more", "+two"}; q = MultiFieldQueryParser.parse(queries4, fields, new StandardAnalyzer()); assertEquals("(b:one +b:more) (+t:two)", q.toString()); String[] queries5 = {"blah"}; try { q = MultiFieldQueryParser.parse(queries5, fields, new StandardAnalyzer()); fail(); } catch(IllegalArgumentException e) { // expected exception, array length differs } } public void testStaticMethod2() throws ParseException { String[] fields = {"b", "t"}; int[] flags = {MultiFieldQueryParser.REQUIRED_FIELD, MultiFieldQueryParser.PROHIBITED_FIELD}; Query q = MultiFieldQueryParser.parse("one", fields, flags, new StandardAnalyzer()); assertEquals("+b:one -t:one", q.toString()); q = MultiFieldQueryParser.parse("one two", fields, flags, new StandardAnalyzer()); assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); try { int[] flags2 = {MultiFieldQueryParser.REQUIRED_FIELD}; q = MultiFieldQueryParser.parse("blah", fields, flags2, new StandardAnalyzer()); fail(); } catch(IllegalArgumentException e) { // expected exception, array length differs } } public void testStaticMethod3() throws ParseException { String[] queries = {"one", "two"}; String[] fields = {"b", "t"}; int[] flags = {MultiFieldQueryParser.REQUIRED_FIELD, MultiFieldQueryParser.PROHIBITED_FIELD}; Query q = MultiFieldQueryParser.parse(queries, fields, flags, new StandardAnalyzer()); assertEquals("+b:one -t:two", q.toString()); try { int[] flags2 = {MultiFieldQueryParser.REQUIRED_FIELD}; q = MultiFieldQueryParser.parse(queries, fields, flags2, new StandardAnalyzer()); fail(); } catch(IllegalArgumentException e) { // expected exception, array length differs } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]