Index: src/demo/org/apache/lucene/demo/html/HTMLParser.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/demo/org/apache/lucene/demo/html/HTMLParser.java,v retrieving revision 1.9 diff -u -r1.9 HTMLParser.java --- src/demo/org/apache/lucene/demo/html/HTMLParser.java 6 Sep 2004 21:33:37 -0000 1.9 +++ src/demo/org/apache/lucene/demo/html/HTMLParser.java 8 Feb 2005 19:26:56 -0000 @@ -453,18 +453,18 @@ finally { jj_save(1, xla); } } - final private boolean jj_3_2() { - if (jj_scan_token(ArgQuote2)) return true; - if (jj_scan_token(CloseQuote2)) return true; - return false; - } - final private boolean jj_3_1() { if (jj_scan_token(ArgQuote1)) return true; if (jj_scan_token(CloseQuote1)) return true; return false; } + final private boolean jj_3_2() { + if (jj_scan_token(ArgQuote2)) return true; + if (jj_scan_token(CloseQuote2)) return true; + return false; + } + public HTMLParserTokenManager token_source; SimpleCharStream jj_input_stream; public Token token, jj_nt; Index: src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java,v retrieving revision 1.8 diff -u -r1.8 MultiFieldQueryParser.java --- src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java 12 Dec 2004 15:36:33 -0000 1.8 +++ src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java 8 Feb 2005 19:26:56 -0000 @@ -16,12 +16,15 @@ * limitations under the License. */ -import java.util.Vector; +import java.util.ArrayList; +import java.util.Collection; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryFactory; +import org.apache.lucene.search.queryfactory.MultiFieldQueryFactory; /** * A QueryParser which constructs queries to search multiple fields. @@ -29,11 +32,7 @@ * @author Kelvin Tan * @version $Revision: 1.8 $ */ -public class MultiFieldQueryParser extends QueryParser -{ - - private String[] fields; - +public class MultiFieldQueryParser extends QueryParser { /** *

Creates a MultiFieldQueryParser that will, when parse(String query) * is called, construct a query like this (assuming the query consists of @@ -52,106 +51,15 @@ *

In other words, all the query's terms must appear, but it doesn't matter in * what fields they appear.

*/ - 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 {@link #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 {@link #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 MultiFieldQueryParser(String[] fields, Analyzer analyzer, QueryFactory factory) { + super(null, analyzer, new MultiFieldQueryFactory(fields, factory)); } - public static final int NORMAL_FIELD = 0; public static final int REQUIRED_FIELD = 1; public static final int PROHIBITED_FIELD = 2; /** - * @deprecated use {@link #MultiFieldQueryParser(String[], Analyzer)} instead - */ - public MultiFieldQueryParser(QueryParserTokenManager tm) - { - super(tm); - } - - /** - * @deprecated use {@link #MultiFieldQueryParser(String[], Analyzer)} instead - */ - public MultiFieldQueryParser(CharStream stream) - { - super(stream); - } - - /** - * @deprecated use {@link #MultiFieldQueryParser(String[], Analyzer)} instead - */ - public MultiFieldQueryParser(String f, Analyzer a) - { - super(f, a); - } - - /** *

Parses a query which searches on the fields specified. * If x fields are specified, this effectively constructs:

* Index: src/java/org/apache/lucene/queryParser/QueryParser.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/java/org/apache/lucene/queryParser/QueryParser.java,v retrieving revision 1.23 diff -u -r1.23 QueryParser.java --- src/java/org/apache/lucene/queryParser/QueryParser.java 14 Dec 2004 23:02:53 -0000 1.23 +++ src/java/org/apache/lucene/queryParser/QueryParser.java 8 Feb 2005 19:26:57 -0000 @@ -9,6 +9,7 @@ import org.apache.lucene.analysis.*; import org.apache.lucene.document.*; import org.apache.lucene.search.*; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; import org.apache.lucene.util.Parameter; /** @@ -75,11 +76,11 @@ boolean lowercaseExpandedTerms = true; + QueryFactory queryFactory; Analyzer analyzer; String field; int phraseSlop = 0; float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity; - int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength; Locale locale = Locale.getDefault(); static final class Operator extends Parameter { @@ -98,16 +99,30 @@ */ static public Query parse(String query, String field, Analyzer analyzer) throws ParseException { - QueryParser parser = new QueryParser(field, analyzer); + return parse(query, field, analyzer, new QueryFactoryImpl()); + } + + /** Parses a query string, returning a {@link org.apache.lucene.search.Query}. + * @param query the query string to be parsed. + * @param field the default field for query terms. + * @param analyzer used to find terms in the query text. + * @param factory the {@link QueryFactory} instance to use + * @throws ParseException if the parsing fails + */ + static public Query parse(String query, String field, Analyzer analyzer, QueryFactory factory) + throws ParseException { + QueryParser parser = new QueryParser(field, analyzer, factory); return parser.parse(query); } /** Constructs a query parser. * @param f the default field for query terms. * @param a used to find terms in the query text. + * @param factory the {@link QueryFactory} instance to use */ - public QueryParser(String f, Analyzer a) { + public QueryParser(String f, Analyzer a, QueryFactory factory) { this(new FastCharStream(new StringReader(""))); + queryFactory = factory; analyzer = a; field = f; } @@ -158,22 +173,6 @@ this.fuzzyMinSim = fuzzyMinSim; } - /** - * Get the prefix length for fuzzy queries. - * @return Returns the fuzzyPrefixLength. - */ - public int getFuzzyPrefixLength() { - return fuzzyPrefixLength; - } - - /** - * Set the prefix length for fuzzy queries. Default is 0. - * @param fuzzyPrefixLength The fuzzyPrefixLength to set. - */ - public void setFuzzyPrefixLength(int fuzzyPrefixLength) { - this.fuzzyPrefixLength = fuzzyPrefixLength; - } - /** * Sets the default slop for phrases. If zero, then exact phrase matches * are required. Default value is zero. @@ -337,289 +336,6 @@ } /** - * Note that parameter analyzer is ignored. Calls inside the parser always - * use class member analyzer. - * - * @exception ParseException throw in overridden method to disallow - * @deprecated use {@link #getFieldQuery(String, String)} - */ - protected Query getFieldQuery(String field, - Analyzer analyzer, - String queryText) throws ParseException { - return getFieldQuery(field, queryText); - } - - /** - * @exception ParseException throw in overridden method to disallow - */ - protected Query getFieldQuery(String field, String queryText) throws ParseException { - // Use the analyzer to get all the tokens, and then build a TermQuery, - // PhraseQuery, or nothing based on the term count - - TokenStream source = analyzer.tokenStream(field, new StringReader(queryText)); - Vector v = new Vector(); - org.apache.lucene.analysis.Token t; - int positionCount = 0; - boolean severalTokensAtSamePosition = false; - - while (true) { - try { - t = source.next(); - } - catch (IOException e) { - t = null; - } - if (t == null) - break; - v.addElement(t); - if (t.getPositionIncrement() == 1) - positionCount++; - else - severalTokensAtSamePosition = true; - } - try { - source.close(); - } - catch (IOException e) { - // ignore - } - - if (v.size() == 0) - return null; - else if (v.size() == 1) { - t = (org.apache.lucene.analysis.Token) v.elementAt(0); - return new TermQuery(new Term(field, t.termText())); - } else { - if (severalTokensAtSamePosition) { - if (positionCount == 1) { - // no phrase query: - BooleanQuery q = new BooleanQuery(); - for (int i = 0; i < v.size(); i++) { - t = (org.apache.lucene.analysis.Token) v.elementAt(i); - TermQuery currentQuery = new TermQuery( - new Term(field, t.termText())); - q.add(currentQuery, BooleanClause.Occur.SHOULD); - } - return q; - } - else { - // phrase query: - MultiPhraseQuery mpq = new MultiPhraseQuery(); - List multiTerms = new ArrayList(); - for (int i = 0; i < v.size(); i++) { - t = (org.apache.lucene.analysis.Token) v.elementAt(i); - if (t.getPositionIncrement() == 1 && multiTerms.size() > 0) { - mpq.add((Term[])multiTerms.toArray(new Term[0])); - multiTerms.clear(); - } - multiTerms.add(new Term(field, t.termText())); - } - mpq.add((Term[])multiTerms.toArray(new Term[0])); - return mpq; - } - } - else { - PhraseQuery q = new PhraseQuery(); - q.setSlop(phraseSlop); - for (int i = 0; i < v.size(); i++) { - q.add(new Term(field, ((org.apache.lucene.analysis.Token) - v.elementAt(i)).termText())); - - } - return q; - } - } - } - - /** - * Note that parameter analyzer is ignored. Calls inside the parser always - * use class member analyzer. - * - * @exception ParseException throw in overridden method to disallow - * @deprecated use {@link #getFieldQuery(String, String, int)} - */ - protected Query getFieldQuery(String field, - Analyzer analyzer, - String queryText, - int slop) throws ParseException { - return getFieldQuery(field, queryText, slop); - } - - /** - * Base implementation delegates to {@link #getFieldQuery(String,String)}. - * This method may be overridden, for example, to return - * a SpanNearQuery instead of a PhraseQuery. - * - * @exception ParseException throw in overridden method to disallow - */ - protected Query getFieldQuery(String field, String queryText, int slop) - throws ParseException { - Query query = getFieldQuery(field, queryText); - - if (query instanceof PhraseQuery) { - ((PhraseQuery) query).setSlop(slop); - } - if (query instanceof MultiPhraseQuery) { - ((MultiPhraseQuery) query).setSlop(slop); - } - - return query; - } - - /** - * Note that parameter analyzer is ignored. Calls inside the parser always - * use class member analyzer. - * - * @exception ParseException throw in overridden method to disallow - * @deprecated use {@link #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); - } - - /** - * @exception ParseException throw in overridden method to disallow - */ - protected Query getRangeQuery(String field, - String part1, - String part2, - boolean inclusive) throws ParseException - { - if (lowercaseExpandedTerms) { - part1 = part1.toLowerCase(); - part2 = part2.toLowerCase(); - } - try { - DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); - df.setLenient(true); - Date d1 = df.parse(part1); - Date d2 = df.parse(part2); - part1 = DateField.dateToString(d1); - part2 = DateField.dateToString(d2); - } - catch (Exception e) { } - - return new RangeQuery(new Term(field, part1), - new Term(field, part2), - inclusive); - } - - /** - * Factory method for generating query, given a set of clauses. - * By default creates a boolean query composed of clauses passed in. - * - * Can be overridden by extending classes, to modify query being - * returned. - * - * @param clauses Vector that contains {@link BooleanClause} instances - * to join. - * - * @return Resulting {@link Query} object. - * @exception ParseException throw in overridden method to disallow - */ - protected Query getBooleanQuery(Vector clauses) throws ParseException - { - BooleanQuery query = new BooleanQuery(); - for (int i = 0; i < clauses.size(); i++) { - query.add((BooleanClause)clauses.elementAt(i)); - } - return query; - } - - /** - * Factory method for generating a query. Called when parser - * parses an input term token that contains one or more wildcard - * characters (? and *), but is not a prefix term token (one - * that has just a single * character at the end) - *

- * Depending on settings, prefix term may be lower-cased - * automatically. It will not go through the default Analyzer, - * however, since normal Analyzers are unlikely to work properly - * with wildcard templates. - *

- * Can be overridden by extending classes, to provide custom handling for - * wildcard queries, which may be necessary due to missing analyzer calls. - * - * @param field Name of the field query will use. - * @param termStr Term token that contains one or more wild card - * characters (? or *), but is not simple prefix term - * - * @return Resulting {@link Query} built for the term - * @exception ParseException throw in overridden method to disallow - */ - protected Query getWildcardQuery(String field, String termStr) throws ParseException - { - if (lowercaseExpandedTerms) { - termStr = termStr.toLowerCase(); - } - Term t = new Term(field, termStr); - return new WildcardQuery(t); - } - - /** - * Factory method for generating a query (similar to - * {@link #getWildcardQuery}). Called when parser parses an input term - * token that uses prefix notation; that is, contains a single '*' wildcard - * character as its last character. Since this is a special case - * of generic wildcard term, and such a query can be optimized easily, - * this usually results in a different query object. - *

- * Depending on settings, a prefix term may be lower-cased - * automatically. It will not go through the default Analyzer, - * however, since normal Analyzers are unlikely to work properly - * with wildcard templates. - *

- * Can be overridden by extending classes, to provide custom handling for - * wild card queries, which may be necessary due to missing analyzer calls. - * - * @param field Name of the field query will use. - * @param termStr Term token to use for building term for the query - * (without trailing '*' character!) - * - * @return Resulting {@link Query} built for the term - * @exception ParseException throw in overridden method to disallow - */ - protected Query getPrefixQuery(String field, String termStr) throws ParseException - { - if (lowercaseExpandedTerms) { - termStr = termStr.toLowerCase(); - } - Term t = new Term(field, termStr); - return new PrefixQuery(t); - } - - /** - * @deprecated use {@link #getFuzzyQuery(String, String, float)} - */ - protected Query getFuzzyQuery(String field, String termStr) throws ParseException { - return getFuzzyQuery(field, termStr, fuzzyMinSim); - } - - /** - * Factory method for generating a query (similar to - * {@link #getWildcardQuery}). Called when parser parses - * an input term token that has the fuzzy suffix (~) appended. - * - * @param field Name of the field query will use. - * @param termStr Term token to use for building term for the query - * - * @return Resulting {@link Query} built for the term - * @exception ParseException throw in overridden method to disallow - */ - protected Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException - { - if (lowercaseExpandedTerms) { - termStr = termStr.toLowerCase(); - } - Term t = new Term(field, termStr); - return new FuzzyQuery(t, minSimilarity, fuzzyPrefixLength); - } - - /** * Returns a String where the escape char has been * removed, or kept only once if there was a double escape. */ @@ -664,8 +380,11 @@ System.out.println("Usage: java org.apache.lucene.queryParser.QueryParser "); System.exit(0); } - QueryParser qp = new QueryParser("field", - new org.apache.lucene.analysis.SimpleAnalyzer()); + QueryParser qp = + new QueryParser( + "field", + new org.apache.lucene.analysis.SimpleAnalyzer(), + new QueryFactoryImpl()); Query q = qp.parse(args[0]); System.out.println(q.toString("field")); } @@ -772,7 +491,7 @@ if (clauses.size() == 1 && firstQuery != null) {if (true) return firstQuery;} else { - {if (true) return getBooleanQuery(clauses);} + {if (true) return queryFactory.getBooleanQuery(clauses);} } throw new Error("Missing return statement in function"); } @@ -888,9 +607,9 @@ } String termImage=discardEscapeChar(term.image); if (wildcard) { - q = getWildcardQuery(field, termImage); + q = queryFactory.getWildcardQuery(field, termImage); } else if (prefix) { - q = getPrefixQuery(field, + q = queryFactory.getPrefixQuery(field, discardEscapeChar(term.image.substring (0, term.image.length()-1))); } else if (fuzzy) { @@ -901,12 +620,9 @@ if(fms < 0.0f || fms > 1.0f){ {if (true) throw new ParseException("Minimum similarity for a FuzzyQuery has to be between 0.0f and 1.0f !");} } - if(fms == fuzzyMinSim) - q = getFuzzyQuery(field, termImage); - else - q = getFuzzyQuery(field, termImage, fms); + q = queryFactory.getFuzzyQuery(field, termImage, fms); } else { - q = getFieldQuery(field, analyzer, termImage); + q = queryFactory.getFieldQuery(field, analyzer, termImage, 0); } break; case RANGEIN_START: @@ -963,7 +679,7 @@ } else { goop2.image = discardEscapeChar(goop2.image); } - q = getRangeQuery(field, analyzer, goop1.image, goop2.image, true); + q = queryFactory.getRangeQuery(field, goop1.image, goop2.image, true); break; case RANGEEX_START: jj_consume_token(RANGEEX_START); @@ -1020,7 +736,7 @@ goop2.image = discardEscapeChar(goop2.image); } - q = getRangeQuery(field, analyzer, goop1.image, goop2.image, false); + q = queryFactory.getRangeQuery(field, goop1.image, goop2.image, false); break; case QUOTED: term = jj_consume_token(QUOTED); @@ -1049,7 +765,7 @@ } catch (Exception ignored) { } } - q = getFieldQuery(field, analyzer, term.image.substring(1, term.image.length()-1), s); + q = queryFactory.getFieldQuery(field, analyzer, term.image.substring(1, term.image.length()-1), s); break; default: jj_la1[21] = jj_gen; Index: src/java/org/apache/lucene/queryParser/QueryParser.jj =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/java/org/apache/lucene/queryParser/QueryParser.jj,v retrieving revision 1.57 diff -u -r1.57 QueryParser.jj --- src/java/org/apache/lucene/queryParser/QueryParser.jj 14 Dec 2004 23:02:53 -0000 1.57 +++ src/java/org/apache/lucene/queryParser/QueryParser.jj 8 Feb 2005 19:26:57 -0000 @@ -32,6 +32,7 @@ import org.apache.lucene.analysis.*; import org.apache.lucene.document.*; import org.apache.lucene.search.*; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; import org.apache.lucene.util.Parameter; /** @@ -98,11 +99,11 @@ boolean lowercaseExpandedTerms = true; + QueryFactory queryFactory; Analyzer analyzer; String field; int phraseSlop = 0; float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity; - int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength; Locale locale = Locale.getDefault(); static final class Operator extends Parameter { @@ -112,7 +113,7 @@ static final Operator OR = new Operator("OR"); static final Operator AND = new Operator("AND"); } - + /** Parses a query string, returning a {@link org.apache.lucene.search.Query}. * @param query the query string to be parsed. * @param field the default field for query terms. @@ -121,16 +122,30 @@ */ static public Query parse(String query, String field, Analyzer analyzer) throws ParseException { - QueryParser parser = new QueryParser(field, analyzer); + return parse(query, field, analyzer, new QueryFactoryImpl()); + } + + /** Parses a query string, returning a {@link org.apache.lucene.search.Query}. + * @param query the query string to be parsed. + * @param field the default field for query terms. + * @param analyzer used to find terms in the query text. + * @param factory the {@link QueryFactory} instance to use + * @throws ParseException if the parsing fails + */ + static public Query parse(String query, String field, Analyzer analyzer, QueryFactory factory) + throws ParseException { + QueryParser parser = new QueryParser(field, analyzer, factory); return parser.parse(query); } /** Constructs a query parser. * @param f the default field for query terms. * @param a used to find terms in the query text. + * @param factory the {@link QueryFactory} instance to use */ - public QueryParser(String f, Analyzer a) { + public QueryParser(String f, Analyzer a, QueryFactory factory) { this(new FastCharStream(new StringReader(""))); + queryFactory = factory; analyzer = a; field = f; } @@ -180,22 +195,6 @@ public void setFuzzyMinSim(float fuzzyMinSim) { this.fuzzyMinSim = fuzzyMinSim; } - - /** - * Get the prefix length for fuzzy queries. - * @return Returns the fuzzyPrefixLength. - */ - public int getFuzzyPrefixLength() { - return fuzzyPrefixLength; - } - - /** - * Set the prefix length for fuzzy queries. Default is 0. - * @param fuzzyPrefixLength The fuzzyPrefixLength to set. - */ - public void setFuzzyPrefixLength(int fuzzyPrefixLength) { - this.fuzzyPrefixLength = fuzzyPrefixLength; - } /** * Sets the default slop for phrases. If zero, then exact phrase matches @@ -358,289 +357,6 @@ else throw new RuntimeException("Clause cannot be both required and prohibited"); } - - /** - * Note that parameter analyzer is ignored. Calls inside the parser always - * use class member analyzer. - * - * @exception ParseException throw in overridden method to disallow - * @deprecated use {@link #getFieldQuery(String, String)} - */ - protected Query getFieldQuery(String field, - Analyzer analyzer, - String queryText) throws ParseException { - return getFieldQuery(field, queryText); - } - - /** - * @exception ParseException throw in overridden method to disallow - */ - protected Query getFieldQuery(String field, String queryText) throws ParseException { - // Use the analyzer to get all the tokens, and then build a TermQuery, - // PhraseQuery, or nothing based on the term count - - TokenStream source = analyzer.tokenStream(field, new StringReader(queryText)); - Vector v = new Vector(); - org.apache.lucene.analysis.Token t; - int positionCount = 0; - boolean severalTokensAtSamePosition = false; - - while (true) { - try { - t = source.next(); - } - catch (IOException e) { - t = null; - } - if (t == null) - break; - v.addElement(t); - if (t.getPositionIncrement() == 1) - positionCount++; - else - severalTokensAtSamePosition = true; - } - try { - source.close(); - } - catch (IOException e) { - // ignore - } - - if (v.size() == 0) - return null; - else if (v.size() == 1) { - t = (org.apache.lucene.analysis.Token) v.elementAt(0); - return new TermQuery(new Term(field, t.termText())); - } else { - if (severalTokensAtSamePosition) { - if (positionCount == 1) { - // no phrase query: - BooleanQuery q = new BooleanQuery(); - for (int i = 0; i < v.size(); i++) { - t = (org.apache.lucene.analysis.Token) v.elementAt(i); - TermQuery currentQuery = new TermQuery( - new Term(field, t.termText())); - q.add(currentQuery, BooleanClause.Occur.SHOULD); - } - return q; - } - else { - // phrase query: - MultiPhraseQuery mpq = new MultiPhraseQuery(); - List multiTerms = new ArrayList(); - for (int i = 0; i < v.size(); i++) { - t = (org.apache.lucene.analysis.Token) v.elementAt(i); - if (t.getPositionIncrement() == 1 && multiTerms.size() > 0) { - mpq.add((Term[])multiTerms.toArray(new Term[0])); - multiTerms.clear(); - } - multiTerms.add(new Term(field, t.termText())); - } - mpq.add((Term[])multiTerms.toArray(new Term[0])); - return mpq; - } - } - else { - PhraseQuery q = new PhraseQuery(); - q.setSlop(phraseSlop); - for (int i = 0; i < v.size(); i++) { - q.add(new Term(field, ((org.apache.lucene.analysis.Token) - v.elementAt(i)).termText())); - - } - return q; - } - } - } - - /** - * Note that parameter analyzer is ignored. Calls inside the parser always - * use class member analyzer. - * - * @exception ParseException throw in overridden method to disallow - * @deprecated use {@link #getFieldQuery(String, String, int)} - */ - protected Query getFieldQuery(String field, - Analyzer analyzer, - String queryText, - int slop) throws ParseException { - return getFieldQuery(field, queryText, slop); - } - - /** - * Base implementation delegates to {@link #getFieldQuery(String,String)}. - * This method may be overridden, for example, to return - * a SpanNearQuery instead of a PhraseQuery. - * - * @exception ParseException throw in overridden method to disallow - */ - protected Query getFieldQuery(String field, String queryText, int slop) - throws ParseException { - Query query = getFieldQuery(field, queryText); - - if (query instanceof PhraseQuery) { - ((PhraseQuery) query).setSlop(slop); - } - if (query instanceof MultiPhraseQuery) { - ((MultiPhraseQuery) query).setSlop(slop); - } - - return query; - } - - /** - * Note that parameter analyzer is ignored. Calls inside the parser always - * use class member analyzer. - * - * @exception ParseException throw in overridden method to disallow - * @deprecated use {@link #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); - } - - /** - * @exception ParseException throw in overridden method to disallow - */ - protected Query getRangeQuery(String field, - String part1, - String part2, - boolean inclusive) throws ParseException - { - if (lowercaseExpandedTerms) { - part1 = part1.toLowerCase(); - part2 = part2.toLowerCase(); - } - try { - DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); - df.setLenient(true); - Date d1 = df.parse(part1); - Date d2 = df.parse(part2); - part1 = DateField.dateToString(d1); - part2 = DateField.dateToString(d2); - } - catch (Exception e) { } - - return new RangeQuery(new Term(field, part1), - new Term(field, part2), - inclusive); - } - - /** - * Factory method for generating query, given a set of clauses. - * By default creates a boolean query composed of clauses passed in. - * - * Can be overridden by extending classes, to modify query being - * returned. - * - * @param clauses Vector that contains {@link BooleanClause} instances - * to join. - * - * @return Resulting {@link Query} object. - * @exception ParseException throw in overridden method to disallow - */ - protected Query getBooleanQuery(Vector clauses) throws ParseException - { - BooleanQuery query = new BooleanQuery(); - for (int i = 0; i < clauses.size(); i++) { - query.add((BooleanClause)clauses.elementAt(i)); - } - return query; - } - - /** - * Factory method for generating a query. Called when parser - * parses an input term token that contains one or more wildcard - * characters (? and *), but is not a prefix term token (one - * that has just a single * character at the end) - *

- * Depending on settings, prefix term may be lower-cased - * automatically. It will not go through the default Analyzer, - * however, since normal Analyzers are unlikely to work properly - * with wildcard templates. - *

- * Can be overridden by extending classes, to provide custom handling for - * wildcard queries, which may be necessary due to missing analyzer calls. - * - * @param field Name of the field query will use. - * @param termStr Term token that contains one or more wild card - * characters (? or *), but is not simple prefix term - * - * @return Resulting {@link Query} built for the term - * @exception ParseException throw in overridden method to disallow - */ - protected Query getWildcardQuery(String field, String termStr) throws ParseException - { - if (lowercaseExpandedTerms) { - termStr = termStr.toLowerCase(); - } - Term t = new Term(field, termStr); - return new WildcardQuery(t); - } - - /** - * Factory method for generating a query (similar to - * {@link #getWildcardQuery}). Called when parser parses an input term - * token that uses prefix notation; that is, contains a single '*' wildcard - * character as its last character. Since this is a special case - * of generic wildcard term, and such a query can be optimized easily, - * this usually results in a different query object. - *

- * Depending on settings, a prefix term may be lower-cased - * automatically. It will not go through the default Analyzer, - * however, since normal Analyzers are unlikely to work properly - * with wildcard templates. - *

- * Can be overridden by extending classes, to provide custom handling for - * wild card queries, which may be necessary due to missing analyzer calls. - * - * @param field Name of the field query will use. - * @param termStr Term token to use for building term for the query - * (without trailing '*' character!) - * - * @return Resulting {@link Query} built for the term - * @exception ParseException throw in overridden method to disallow - */ - protected Query getPrefixQuery(String field, String termStr) throws ParseException - { - if (lowercaseExpandedTerms) { - termStr = termStr.toLowerCase(); - } - Term t = new Term(field, termStr); - return new PrefixQuery(t); - } - - /** - * @deprecated use {@link #getFuzzyQuery(String, String, float)} - */ - protected Query getFuzzyQuery(String field, String termStr) throws ParseException { - return getFuzzyQuery(field, termStr, fuzzyMinSim); - } - - /** - * Factory method for generating a query (similar to - * {@link #getWildcardQuery}). Called when parser parses - * an input term token that has the fuzzy suffix (~) appended. - * - * @param field Name of the field query will use. - * @param termStr Term token to use for building term for the query - * - * @return Resulting {@link Query} built for the term - * @exception ParseException throw in overridden method to disallow - */ - protected Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException - { - if (lowercaseExpandedTerms) { - termStr = termStr.toLowerCase(); - } - Term t = new Term(field, termStr); - return new FuzzyQuery(t, minSimilarity, fuzzyPrefixLength); - } /** * Returns a String where the escape char has been @@ -687,8 +403,11 @@ System.out.println("Usage: java org.apache.lucene.queryParser.QueryParser "); System.exit(0); } - QueryParser qp = new QueryParser("field", - new org.apache.lucene.analysis.SimpleAnalyzer()); + QueryParser qp = + new QueryParser( + "field", + new org.apache.lucene.analysis.SimpleAnalyzer(), + new QueryFactoryImpl()); Query q = qp.parse(args[0]); System.out.println(q.toString("field")); } @@ -810,7 +529,7 @@ if (clauses.size() == 1 && firstQuery != null) return firstQuery; else { - return getBooleanQuery(clauses); + return queryFactory.getBooleanQuery(clauses); } } } @@ -866,9 +585,9 @@ { String termImage=discardEscapeChar(term.image); if (wildcard) { - q = getWildcardQuery(field, termImage); + q = queryFactory.getWildcardQuery(field, termImage); } else if (prefix) { - q = getPrefixQuery(field, + q = queryFactory.getPrefixQuery(field, discardEscapeChar(term.image.substring (0, term.image.length()-1))); } else if (fuzzy) { @@ -879,12 +598,9 @@ if(fms < 0.0f || fms > 1.0f){ throw new ParseException("Minimum similarity for a FuzzyQuery has to be between 0.0f and 1.0f !"); } - if(fms == fuzzyMinSim) - q = getFuzzyQuery(field, termImage); - else - q = getFuzzyQuery(field, termImage, fms); + q = queryFactory.getFuzzyQuery(field, termImage, fms); } else { - q = getFieldQuery(field, analyzer, termImage); + q = queryFactory.getFieldQuery(field, analyzer, termImage, 0); } } | ( ( goop1=|goop1= ) @@ -902,7 +618,7 @@ } else { goop2.image = discardEscapeChar(goop2.image); } - q = getRangeQuery(field, analyzer, goop1.image, goop2.image, true); + q = queryFactory.getRangeQuery(field, goop1.image, goop2.image, true); } | ( ( goop1=|goop1= ) [ ] ( goop2=|goop2= ) @@ -920,7 +636,7 @@ goop2.image = discardEscapeChar(goop2.image); } - q = getRangeQuery(field, analyzer, goop1.image, goop2.image, false); + q = queryFactory.getRangeQuery(field, goop1.image, goop2.image, false); } | term= [ fuzzySlop= ] @@ -934,7 +650,7 @@ } catch (Exception ignored) { } } - q = getFieldQuery(field, analyzer, term.image.substring(1, term.image.length()-1), s); + q = queryFactory.getFieldQuery(field, analyzer, term.image.substring(1, term.image.length()-1), s); } ) { Index: src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java,v retrieving revision 1.4 diff -u -r1.4 QueryParserTokenManager.java --- src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java 14 Sep 2004 13:45:15 -0000 1.4 +++ src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java 8 Feb 2005 19:26:57 -0000 @@ -8,6 +8,8 @@ import org.apache.lucene.analysis.*; import org.apache.lucene.document.*; import org.apache.lucene.search.*; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; +import org.apache.lucene.util.Parameter; public class QueryParserTokenManager implements QueryParserConstants { Index: src/test/org/apache/lucene/SearchTest.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/SearchTest.java,v retrieving revision 1.7 diff -u -r1.7 SearchTest.java --- src/test/org/apache/lucene/SearchTest.java 6 Sep 2004 22:29:22 -0000 1.7 +++ src/test/org/apache/lucene/SearchTest.java 8 Feb 2005 19:26:57 -0000 @@ -23,6 +23,7 @@ import org.apache.lucene.analysis.*; import org.apache.lucene.index.*; import org.apache.lucene.search.*; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; import org.apache.lucene.queryParser.*; class SearchTest { @@ -60,7 +61,7 @@ }; Hits hits = null; - QueryParser parser = new QueryParser("contents", analyzer); + QueryParser parser = new QueryParser("contents", analyzer, new QueryFactoryImpl()); parser.setPhraseSlop(4); for (int j = 0; j < queries.length; j++) { Query query = parser.parse(queries[j]); Index: src/test/org/apache/lucene/SearchTestForDuplicates.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/SearchTestForDuplicates.java,v retrieving revision 1.7 diff -u -r1.7 SearchTestForDuplicates.java --- src/test/org/apache/lucene/SearchTestForDuplicates.java 6 Sep 2004 22:29:22 -0000 1.7 +++ src/test/org/apache/lucene/SearchTestForDuplicates.java 8 Feb 2005 19:26:57 -0000 @@ -23,6 +23,7 @@ import org.apache.lucene.analysis.*; import org.apache.lucene.index.*; import org.apache.lucene.search.*; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; import org.apache.lucene.queryParser.*; class SearchTestForDuplicates { @@ -53,7 +54,11 @@ Searcher searcher = new IndexSearcher(directory); Hits hits = null; - QueryParser parser = new QueryParser(PRIORITY_FIELD, analyzer); + QueryParser parser = + new QueryParser( + PRIORITY_FIELD, + analyzer, + new QueryFactoryImpl()); Query query = parser.parse(HIGH_PRIORITY); System.out.println("Query: " + query.toString(PRIORITY_FIELD)); @@ -67,7 +72,11 @@ searcher = new IndexSearcher(directory); hits = null; - parser = new QueryParser(PRIORITY_FIELD, analyzer); + parser = + new QueryParser( + PRIORITY_FIELD, + analyzer, + new QueryFactoryImpl()); query = parser.parse(HIGH_PRIORITY + " OR " + MED_PRIORITY); System.out.println("Query: " + query.toString(PRIORITY_FIELD)); Index: src/test/org/apache/lucene/TestSearch.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/TestSearch.java,v retrieving revision 1.4 diff -u -r1.4 TestSearch.java --- src/test/org/apache/lucene/TestSearch.java 6 Sep 2004 22:29:22 -0000 1.4 +++ src/test/org/apache/lucene/TestSearch.java 8 Feb 2005 19:26:57 -0000 @@ -29,6 +29,7 @@ import org.apache.lucene.analysis.*; import org.apache.lucene.index.*; import org.apache.lucene.search.*; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; import org.apache.lucene.queryParser.*; /** JUnit adaptation of an older test case SearchTest. @@ -108,7 +109,7 @@ }; Hits hits = null; - QueryParser parser = new QueryParser("contents", analyzer); + QueryParser parser = new QueryParser("contents", analyzer, new QueryFactoryImpl()); parser.setPhraseSlop(4); for (int j = 0; j < queries.length; j++) { Query query = parser.parse(queries[j]); Index: src/test/org/apache/lucene/TestSearchForDuplicates.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/TestSearchForDuplicates.java,v retrieving revision 1.4 diff -u -r1.4 TestSearchForDuplicates.java --- src/test/org/apache/lucene/TestSearchForDuplicates.java 6 Sep 2004 22:29:22 -0000 1.4 +++ src/test/org/apache/lucene/TestSearchForDuplicates.java 8 Feb 2005 19:26:57 -0000 @@ -25,6 +25,7 @@ import org.apache.lucene.analysis.*; import org.apache.lucene.index.*; import org.apache.lucene.search.*; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; import org.apache.lucene.queryParser.*; import junit.framework.TestCase; @@ -101,7 +102,7 @@ Searcher searcher = new IndexSearcher(directory); Hits hits = null; - QueryParser parser = new QueryParser(PRIORITY_FIELD, analyzer); + QueryParser parser = new QueryParser(PRIORITY_FIELD, analyzer, new QueryFactoryImpl()); Query query = parser.parse(HIGH_PRIORITY); out.println("Query: " + query.toString(PRIORITY_FIELD)); @@ -116,7 +117,7 @@ searcher = new IndexSearcher(directory); hits = null; - parser = new QueryParser(PRIORITY_FIELD, analyzer); + parser = new QueryParser(PRIORITY_FIELD, analyzer, new QueryFactoryImpl()); query = parser.parse(HIGH_PRIORITY + " OR " + MED_PRIORITY); out.println("Query: " + query.toString(PRIORITY_FIELD)); Index: src/test/org/apache/lucene/queryParser/TestMultiAnalyzer.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/queryParser/TestMultiAnalyzer.java,v retrieving revision 1.2 diff -u -r1.2 TestMultiAnalyzer.java --- src/test/org/apache/lucene/queryParser/TestMultiAnalyzer.java 3 Jan 2005 17:05:31 -0000 1.2 +++ src/test/org/apache/lucene/queryParser/TestMultiAnalyzer.java 8 Feb 2005 19:26:58 -0000 @@ -25,6 +25,7 @@ import org.apache.lucene.analysis.TokenFilter; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.standard.StandardTokenizer; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; /** * Test QueryParser's ability to deal with Analyzers that return more @@ -38,7 +39,7 @@ public void testAnalyzer() throws ParseException { - QueryParser qp = new QueryParser("", new TestAnalyzer()); + QueryParser qp = new QueryParser("", new TestAnalyzer(), new QueryFactoryImpl()); // trivial, no multiple tokens: assertEquals("foo", qp.parse("foo").toString()); Index: src/test/org/apache/lucene/queryParser/TestMultiFieldQueryParser.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/queryParser/TestMultiFieldQueryParser.java,v retrieving revision 1.1 diff -u -r1.1 TestMultiFieldQueryParser.java --- src/test/org/apache/lucene/queryParser/TestMultiFieldQueryParser.java 12 Dec 2004 15:27:49 -0000 1.1 +++ src/test/org/apache/lucene/queryParser/TestMultiFieldQueryParser.java 8 Feb 2005 19:26:58 -0000 @@ -20,6 +20,7 @@ import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.search.Query; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; /** * Tests QueryParser. @@ -29,7 +30,7 @@ public void testSimple() throws Exception { String[] fields = {"b", "t"}; - MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields, new StandardAnalyzer()); + MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields, new StandardAnalyzer(), new QueryFactoryImpl()); Query q = mfqp.parse("one"); assertEquals("b:one t:one", q.toString()); Index: src/test/org/apache/lucene/queryParser/TestQueryParser.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/queryParser/TestQueryParser.java,v retrieving revision 1.34 diff -u -r1.34 TestQueryParser.java --- src/test/org/apache/lucene/queryParser/TestQueryParser.java 14 Dec 2004 23:02:53 -0000 1.34 +++ src/test/org/apache/lucene/queryParser/TestQueryParser.java 8 Feb 2005 19:26:58 -0000 @@ -34,6 +34,8 @@ import org.apache.lucene.search.RangeQuery; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.WildcardQuery; +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; + import java.io.IOException; import java.io.Reader; import java.text.DateFormat; @@ -84,20 +86,6 @@ } } - public static class QPTestParser extends QueryParser { - public QPTestParser(String f, Analyzer a) { - super(f, a); - } - - protected Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException { - throw new ParseException("Fuzzy queries not allowed"); - } - - protected Query getWildcardQuery(String field, String termStr) throws ParseException { - throw new ParseException("Wildcard queries not allowed"); - } - } - private int originalMaxClauses; public void setUp() { @@ -107,7 +95,7 @@ public QueryParser getParser(Analyzer a) throws Exception { if (a == null) a = new SimpleAnalyzer(); - QueryParser qp = new QueryParser("field", a); + QueryParser qp = new QueryParser("field", a, new QueryFactoryImpl()); qp.setDefaultOperator(QueryParser.OR_OPERATOR); return qp; } @@ -126,18 +114,6 @@ } } - public void assertWildcardQueryEquals(String query, boolean lowercase, String result) - throws Exception { - QueryParser qp = getParser(null); - qp.setLowercaseExpandedTerms(lowercase); - Query q = qp.parse(query); - String s = q.toString("field"); - if (!s.equals(result)) { - fail("WildcardQuery /" + query + "/ yielded /" + s - + "/, expecting /" + result + "/"); - } - } - public void assertWildcardQueryEquals(String query, String result) throws Exception { QueryParser qp = getParser(null); Query q = qp.parse(query); @@ -152,7 +128,7 @@ throws Exception { if (a == null) a = new SimpleAnalyzer(); - QueryParser qp = new QueryParser("field", a); + QueryParser qp = new QueryParser("field", a, new QueryFactoryImpl()); qp.setDefaultOperator(QueryParser.AND_OPERATOR); return qp.parse(query); } @@ -214,7 +190,7 @@ assertQueryEquals("+title:(dog OR cat) -author:\"bob dole\"", null, "+(title:dog title:cat) -author:\"bob dole\""); - QueryParser qp = new QueryParser("field", new StandardAnalyzer()); + QueryParser qp = new QueryParser("field", new StandardAnalyzer(), new QueryFactoryImpl()); // make sure OR is the default: assertEquals(QueryParser.OR_OPERATOR, qp.getDefaultOperator()); qp.setDefaultOperator(QueryParser.AND_OPERATOR); @@ -280,39 +256,25 @@ /* Tests to see that wild card terms are (or are not) properly * lower-cased with propery parser configuration + * + * NOTE[MD]: I've removed the lower-casing here because this is down to the + * LowerCaseQueryFactory, i.e. you pass this in at construction time. */ // First prefix queries: - // by default, convert to lowercase: - assertWildcardQueryEquals("Term*", true, "term*"); - // explicitly set lowercase: - assertWildcardQueryEquals("term*", true, "term*"); - assertWildcardQueryEquals("Term*", true, "term*"); - assertWildcardQueryEquals("TERM*", true, "term*"); - // explicitly disable lowercase conversion: - assertWildcardQueryEquals("term*", false, "term*"); - assertWildcardQueryEquals("Term*", false, "Term*"); - assertWildcardQueryEquals("TERM*", false, "TERM*"); + assertWildcardQueryEquals("term*", "term*"); + assertWildcardQueryEquals("term*", "term*"); + assertWildcardQueryEquals("Term*", "Term*"); + assertWildcardQueryEquals("TERM*", "TERM*"); // Then 'full' wildcard queries: - // by default, convert to lowercase: - assertWildcardQueryEquals("Te?m", "te?m"); - // explicitly set lowercase: - assertWildcardQueryEquals("te?m", true, "te?m"); - assertWildcardQueryEquals("Te?m", true, "te?m"); - assertWildcardQueryEquals("TE?M", true, "te?m"); - assertWildcardQueryEquals("Te?m*gerM", true, "te?m*germ"); - // explicitly disable lowercase conversion: - assertWildcardQueryEquals("te?m", false, "te?m"); - assertWildcardQueryEquals("Te?m", false, "Te?m"); - assertWildcardQueryEquals("TE?M", false, "TE?M"); - assertWildcardQueryEquals("Te?m*gerM", false, "Te?m*gerM"); + assertWildcardQueryEquals("te?m", "te?m"); + assertWildcardQueryEquals("te?m", "te?m"); + assertWildcardQueryEquals("Te?m", "Te?m"); + assertWildcardQueryEquals("TE?M", "TE?M"); + assertWildcardQueryEquals("Te?m*gerM", "Te?m*gerM"); // Fuzzy queries: - assertWildcardQueryEquals("Term~", "term~0.5"); - assertWildcardQueryEquals("Term~", true, "term~0.5"); - assertWildcardQueryEquals("Term~", false, "Term~0.5"); + assertWildcardQueryEquals("Term~", "Term~0.5"); // Range queries: - assertWildcardQueryEquals("[A TO C]", "[a TO c]"); - assertWildcardQueryEquals("[A TO C]", true, "[a TO c]"); - assertWildcardQueryEquals("[A TO C]", false, "[A TO C]"); + assertWildcardQueryEquals("[A TO C]", "[A TO C]"); } public void testQPA() throws Exception { @@ -470,7 +432,7 @@ public void testBoost() throws Exception { StandardAnalyzer oneStopAnalyzer = new StandardAnalyzer(new String[]{"on"}); - QueryParser qp = new QueryParser("field", oneStopAnalyzer); + QueryParser qp = new QueryParser("field", oneStopAnalyzer, new QueryFactoryImpl()); Query q = qp.parse("on^1.0"); assertNotNull(q); q = qp.parse("\"hello\"^2.0"); @@ -494,24 +456,6 @@ } } - public void testCustomQueryParserWildcard() { - try { - new QPTestParser("contents", new WhitespaceAnalyzer()).parse("a?t"); - } catch (ParseException expected) { - return; - } - fail("Wildcard queries should not be allowed"); - } - - public void testCustomQueryParserFuzzy() throws Exception { - try { - new QPTestParser("contents", new WhitespaceAnalyzer()).parse("xunit~"); - } catch (ParseException expected) { - return; - } - fail("Fuzzy queries should not be allowed"); - } - public void testBooleanQuery() throws Exception { BooleanQuery.setMaxClauseCount(2); try { Index: src/test/org/apache/lucene/search/TestBoolean2.java =================================================================== RCS file: /home/cvspublic/jakarta-lucene/src/test/org/apache/lucene/search/TestBoolean2.java,v retrieving revision 1.1 diff -u -r1.1 TestBoolean2.java --- src/test/org/apache/lucene/search/TestBoolean2.java 24 Jan 2005 19:21:01 -0000 1.1 +++ src/test/org/apache/lucene/search/TestBoolean2.java 8 Feb 2005 19:26:58 -0000 @@ -17,6 +17,7 @@ */ +import org.apache.lucene.search.queryfactory.QueryFactoryImpl; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.index.IndexWriter; @@ -59,7 +60,7 @@ }; public Query makeQuery(String queryText) throws ParseException { - return (new QueryParser(field, new WhitespaceAnalyzer())).parse(queryText); + return (new QueryParser(field, new WhitespaceAnalyzer(), new QueryFactoryImpl())).parse(queryText); } public void queriesTest(String queryText, int[] expDocNrs) throws Exception { Index: src/java/org/apache/lucene/search/QueryFactory.java =================================================================== RCS file: src/java/org/apache/lucene/search/QueryFactory.java diff -N src/java/org/apache/lucene/search/QueryFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/java/org/apache/lucene/search/QueryFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,95 @@ + +/** + * Copyright 2002-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. + */ +package org.apache.lucene.search; + +import java.util.Collection; +import java.util.Locale; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.queryParser.ParseException; + +/** + * Classes implementing this interface are capable of creating + * {@link org.apache.lucene.search.Query} instances. + * + *

The primary reason for adding this interface is that, in the original + * code, you had to override {@link org.apache.lucene.queryParser.QueryParser} + * to add your own implementation of this functionality. By refactoring this + * out we get the ability to use any + * {@link org.apache.lucene.queryParser.QueryParser} and provide a separate + * implementation instance of this interface.

+ * + * @author Matthew Denner + * @version $Revision$ + */ +public interface QueryFactory { + /** + * @return the {@link Locale} for the instance + */ + Locale getLocale(); + + /** + * @param clauses a {@link Collection} of {@link BooleanClause} instances + * @return the {@link Query} instance to be used + */ + Query getBooleanQuery(Collection clauses); + + /** + * @param field the field for which we are creating the instance + * @param analyzer the {@link Analyzer} instance to use + * @param queryText the query text + * @param slop the slop for the field + * @return the {@link Query} instance to be used + * @throws ParseException if there is a problem with the parameters + */ + Query getFieldQuery(String field, Analyzer analyzer, String queryText, int slop) throws ParseException; + + /** + * @param field the field for which we are creating the instance + * @param termStr the term we are to look for + * @param minSimilarity the minimum similarity for the comparison + * @return the {@link Query} instance to be used + * @throws ParseException if there is a problem with the parameters + */ + Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException; + + /** + * @param field the field for which we are creating the instance + * @param termStr the term we are to look for + * @return the {@link Query} instance to be used + * @throws ParseException if there is a problem with the parameters + */ + Query getPrefixQuery(String field, String termStr) throws ParseException; + + /** + * @param field the field for which we are creating the instance + * @param lower the lower bound of the range + * @param upper the upper bound of the range + * @param inclusive true if lower and upper are to be included, otherwise false + * @return the {@link Query} instance to be used + * @throws ParseException if there is a problem with the parameters + */ + Query getRangeQuery(String field, String lower, String upper, boolean inclusive) throws ParseException; + + /** + * @param field the field for which we are creating the instance + * @param termStr the term we are to look for + * @return the {@link Query} instance to be used + * @throws ParseException if there is a problem with the parameters + */ + Query getWildcardQuery(String field, String termStr) throws ParseException; +} Index: src/java/org/apache/lucene/search/queryfactory/LowerCaseQueryFactory.java =================================================================== RCS file: src/java/org/apache/lucene/search/queryfactory/LowerCaseQueryFactory.java diff -N src/java/org/apache/lucene/search/queryfactory/LowerCaseQueryFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/java/org/apache/lucene/search/queryfactory/LowerCaseQueryFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,109 @@ +/** + * Copyright 2002-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. + */ +package org.apache.lucene.search.queryfactory; + +import java.util.Collection; +import java.util.Locale; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryFactory; + +/** + * This class is a decorator for another {@link org.apache.lucene.search.QueryFactory} + * instance that will convert any query terms to lower case before passing the + * call to the delegate. + * + * @author Matthew Denner + * @version $Revision$ + */ +public class LowerCaseQueryFactory implements QueryFactory { + /** + * @param delegate the {@link QueryFactory} instance to decorate + */ + public LowerCaseQueryFactory(final QueryFactory delegate) { + if (delegate == null) { + throw new IllegalArgumentException("Delegate cannot be null"); + } + m_delegate = delegate; + } + + /** + * @see org.apache.lucene.search.QueryFactory#getLocale() + */ + public Locale getLocale() { + return m_delegate.getLocale(); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getBooleanQuery(java.util.Collection) + */ + public Query getBooleanQuery(final Collection clauses) { + return m_delegate.getBooleanQuery(clauses); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getFieldQuery(java.lang.String, org.apache.lucene.analysis.Analyzer, java.lang.String, int) + */ + public Query getFieldQuery(final String field, final Analyzer analyzer, final String queryText, final int slop) + throws ParseException + { + return m_delegate.getFieldQuery(field, analyzer, toLowerCase(queryText), slop); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getFuzzyQuery(java.lang.String, java.lang.String, float) + */ + public Query getFuzzyQuery(final String field, final String termStr, final float minSimilarity) + throws ParseException + { + return m_delegate.getFuzzyQuery(field, toLowerCase(termStr), minSimilarity); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getPrefixQuery(java.lang.String, java.lang.String) + */ + public Query getPrefixQuery(final String field, final String termStr) + throws ParseException + { + return m_delegate.getPrefixQuery(field, toLowerCase(termStr)); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getRangeQuery(java.lang.String, java.lang.String, java.lang.String, boolean) + */ + public Query getRangeQuery(final String field, final String lower, final String upper, final boolean inclusive) + throws ParseException + { + return m_delegate.getRangeQuery(field, toLowerCase(lower), toLowerCase(upper), inclusive); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getWildcardQuery(java.lang.String, java.lang.String) + */ + public Query getWildcardQuery(final String field, final String termStr) + throws ParseException + { + return m_delegate.getWildcardQuery(field, termStr); + } + + private String toLowerCase(final String text) { + return text.toLowerCase(getLocale()); + } + + private final QueryFactory m_delegate; +} Index: src/java/org/apache/lucene/search/queryfactory/MultiFieldQueryFactory.java =================================================================== RCS file: src/java/org/apache/lucene/search/queryfactory/MultiFieldQueryFactory.java diff -N src/java/org/apache/lucene/search/queryfactory/MultiFieldQueryFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/java/org/apache/lucene/search/queryfactory/MultiFieldQueryFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,173 @@ +/** + * Copyright 2002-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. + */ +package org.apache.lucene.search.queryfactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Locale; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.queryParser.MultiFieldQueryParser; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryFactory; + +/** + * This is a decorator implementation of the + * {@link org.apache.lucene.search.QueryFactory} interface that should enable + * the {@link org.apache.lucene.queryParser.QueryParser} class to handle + * multi-field searches. + * + *

The original code for this class was refactored from the + * {@link org.apache.lucene.queryParser.MultiFieldQueryParser} class (written + * by Kelvin Tan).

+ * + * @author Kelvin Tan + * @author Matthew Denner + * @version $Revision$ + */ +public final class MultiFieldQueryFactory implements QueryFactory { + /** + * @param fields the fields that are to be searched + * @param factory the {@link QueryFactory} instance to actually delegate to + */ + public MultiFieldQueryFactory(final String[] fields, final QueryFactory factory) { + if ((fields == null) || (fields.length == 0)) { + throw new IllegalArgumentException("Fields cannot be null or empty"); + } + if (factory == null) { + throw new IllegalArgumentException("Delegate QueryFactory cannot be null"); + } + m_fields = fields; + m_factory = factory; + } + + /** + * @see org.apache.lucene.search.QueryFactory#getLocale() + */ + public Locale getLocale() { + return m_factory.getLocale(); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getBooleanQuery(java.util.Collection) + */ + public Query getBooleanQuery(final Collection clauses) { + return m_factory.getBooleanQuery(clauses); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getWildcardQuery(java.lang.String, java.lang.String) + */ + public Query getWildcardQuery(final String field, final String termStr) throws ParseException { + return getBooleanQuery(field, new Handler() { + public Query getQuery(final String field) throws ParseException { + return m_factory.getWildcardQuery(field, termStr); + } + }); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getFieldQuery(java.lang.String, org.apache.lucene.analysis.Analyzer, java.lang.String, int) + */ + public Query getFieldQuery(final String field, final Analyzer analyzer, final String queryText, final int slop) throws ParseException { + return getBooleanQuery(field, new Handler() { + public Query getQuery(final String field) throws ParseException { + return m_factory.getFieldQuery(field, analyzer, queryText, slop); + } + }); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getFuzzyQuery(java.lang.String, java.lang.String, float) + */ + public Query getFuzzyQuery(final String field, final String termStr, final float minSimilarity) throws ParseException { + return getBooleanQuery(field, new Handler() { + public Query getQuery(final String field) throws ParseException { + return m_factory.getFuzzyQuery(field, termStr, minSimilarity); + } + }); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getPrefixQuery(java.lang.String, java.lang.String) + */ + public Query getPrefixQuery(final String field, final String termStr) throws ParseException { + return getBooleanQuery(field, new Handler() { + public Query getQuery(final String field) throws ParseException { + return m_factory.getPrefixQuery(field, termStr); + } + }); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getRangeQuery(java.lang.String, java.lang.String, java.lang.String, boolean) + */ + public Query getRangeQuery(final String field, final String lower, final String upper, final boolean inclusive) throws ParseException { + return getBooleanQuery(field, new Handler() { + public Query getQuery(final String field) throws ParseException { + return m_factory.getRangeQuery(field, lower, upper, inclusive); + } + }); + } + + /** + * Convenience method to handle common logic for all the other methods that + * deal with multiple field assignment. If the passed field + * parameter is not null then the returned {@link Query} is based on + * calling {@link Handler#getQuery(String)} with field. Otherwise + * we build collection of {@link BooleanClause} instances using the + * {@link Handler#getQuery(String)} with the values in {@link #m_fields}. + * + * @param field the field we are creating the query for, can be null + * @param handler the {@link Handler} instance to use for creating queries + * @return the {@link Query} instance to use + * @throws ParseException if there is a problem with the query + */ + Query getBooleanQuery(final String field, final Handler handler) throws ParseException { + if (field != null) { + return handler.getQuery(field); + } + final ArrayList clauses = new ArrayList(); + for (int i = 0; i < m_fields.length; ++i) { + clauses.add( + new BooleanClause( + handler.getQuery(m_fields[ i ]), + BooleanClause.Occur.SHOULD)); + } + return getBooleanQuery(clauses); + } + + private final String[] m_fields; + private final QueryFactory m_factory; + + /** + * Simple callback interface so that the code in the methods of the + * {@link MultiFieldQueryFactory} can be very simple to understand. + * + * @author Matthew Denner + * @version $Revision$ + */ + static interface Handler { + /** + * @param field the field we are creating the query for + * @return the {@link Query} instance to use + * @throws ParseException if there is a problem + */ + Query getQuery(String field) throws ParseException; + } +} Index: src/java/org/apache/lucene/search/queryfactory/QueryFactoryImpl.java =================================================================== RCS file: src/java/org/apache/lucene/search/queryfactory/QueryFactoryImpl.java diff -N src/java/org/apache/lucene/search/queryfactory/QueryFactoryImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/java/org/apache/lucene/search/queryfactory/QueryFactoryImpl.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,224 @@ +/** + * Copyright 2002-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. + */ +package org.apache.lucene.search.queryfactory; + +import java.io.IOException; +import java.io.StringReader; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Vector; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.document.DateField; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.FuzzyQuery; +import org.apache.lucene.search.MultiPhraseQuery; +import org.apache.lucene.search.PhraseQuery; +import org.apache.lucene.search.PrefixQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryFactory; +import org.apache.lucene.search.RangeQuery; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.WildcardQuery; + +/** + * A default implementation of the {@link QueryFactory} interface. + * + *

The code for this was refactored from the + * {@link org.apache.lucene.queryParser.QueryParser} class and all of the + * authors of that code have been credited here.

+ * + * @author Brian Goetz + * @author Peter Halacsy + * @author Tatu Saloranta + * @author Matthew Denner + * @version $Revision$ + */ +public final class QueryFactoryImpl implements QueryFactory { + /** + * @see org.apache.lucene.search.QueryFactory#getWildcardQuery(java.lang.String, java.lang.String) + */ + public Query getWildcardQuery(final String field, final String termStr) { + return new WildcardQuery(new Term(field, termStr)); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getBooleanQuery(java.util.Collection) + */ + public Query getBooleanQuery(final Collection clauses) { + BooleanQuery query = new BooleanQuery(); + for (Iterator it = clauses.iterator(); it.hasNext(); ) { + query.add((BooleanClause)it.next()); + } + return query; + } + + /** + * @see org.apache.lucene.search.QueryFactory#getFieldQuery(java.lang.String, org.apache.lucene.analysis.Analyzer, java.lang.String, int) + */ + public Query getFieldQuery(final String field, final Analyzer analyzer, final String queryText, int slop) { + // Use the analyzer to get all the tokens, and then build a TermQuery, + // PhraseQuery, or nothing based on the term count + + TokenStream source = analyzer.tokenStream(field, new StringReader(queryText)); + Vector v = new Vector(); + org.apache.lucene.analysis.Token t; + int positionCount = 0; + boolean severalTokensAtSamePosition = false; + + while (true) { + try { + t = source.next(); + } + catch (IOException e) { + t = null; + } + if (t == null) + break; + v.addElement(t); + if (t.getPositionIncrement() == 1) + positionCount++; + else + severalTokensAtSamePosition = true; + } + try { + source.close(); + } + catch (IOException e) { + // ignore + } + + if (v.size() == 0) + return null; + else if (v.size() == 1) { + t = (org.apache.lucene.analysis.Token) v.elementAt(0); + return new TermQuery(new Term(field, t.termText())); + } else { + if (severalTokensAtSamePosition) { + if (positionCount == 1) { + // no phrase query: + BooleanQuery q = new BooleanQuery(); + for (int i = 0; i < v.size(); i++) { + t = (org.apache.lucene.analysis.Token) v.elementAt(i); + TermQuery currentQuery = new TermQuery( + new Term(field, t.termText())); + q.add(currentQuery, BooleanClause.Occur.SHOULD); + } + return q; + } + else { + // phrase query: + MultiPhraseQuery mpq = new MultiPhraseQuery(); + List multiTerms = new ArrayList(); + for (int i = 0; i < v.size(); i++) { + t = (org.apache.lucene.analysis.Token) v.elementAt(i); + if (t.getPositionIncrement() == 1 && multiTerms.size() > 0) { + mpq.add((Term[])multiTerms.toArray(new Term[0])); + multiTerms.clear(); + } + multiTerms.add(new Term(field, t.termText())); + } + mpq.add((Term[])multiTerms.toArray(new Term[0])); + mpq.setSlop(slop); + return mpq; + } + } + else { + PhraseQuery q = new PhraseQuery(); + q.setSlop(slop); + for (int i = 0; i < v.size(); i++) { + q.add(new Term(field, ((org.apache.lucene.analysis.Token) + v.elementAt(i)).termText())); + + } + return q; + } + } + } + + /** + * @see org.apache.lucene.search.QueryFactory#getFuzzyQuery(java.lang.String, java.lang.String, float) + */ + public Query getFuzzyQuery(final String field, final String termStr, final float minSimilarity) { + return new FuzzyQuery(new Term(field, termStr), minSimilarity, m_fuzzyPrefixLength); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getPrefixQuery(java.lang.String, java.lang.String) + */ + public Query getPrefixQuery(final String field, final String termStr) { + return new PrefixQuery(new Term(field, termStr)); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getRangeQuery(java.lang.String, java.lang.String, java.lang.String, boolean) + */ + public Query getRangeQuery(final String field, String lower, String upper, final boolean inclusive) { + try { + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, m_locale); + df.setLenient(true); + Date d1 = df.parse(lower); + Date d2 = df.parse(upper); + lower = DateField.dateToString(d1); + upper = DateField.dateToString(d2); + } + catch (Exception e) { } + + return new RangeQuery( + new Term(field, lower), + new Term(field, upper), + inclusive); + } + + /** + * @see org.apache.lucene.search.QueryFactory#getLocale() + */ + public Locale getLocale() { + return m_locale; + } + + /** + * @param locale the {@link Locale} instance to use + */ + public void setLocale(final Locale locale) { + m_locale = locale; + } + + /** + * @return the length of the fuzzy query prefix + */ + public int getFuzzyPrefixLength() { + return m_fuzzyPrefixLength; + } + + /** + * @param length the length of the fuzzy query prefix + */ + public void setFuzzyPrefixLength(final int length) { + m_fuzzyPrefixLength = length; + } + + private Locale m_locale = Locale.getDefault(); + private int m_fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength; +} Index: src/test/org/apache/lucene/search/queryfactory/MockQuery.java =================================================================== RCS file: src/test/org/apache/lucene/search/queryfactory/MockQuery.java diff -N src/test/org/apache/lucene/search/queryfactory/MockQuery.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/test/org/apache/lucene/search/queryfactory/MockQuery.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,18 @@ +package org.apache.lucene.search.queryfactory; + +import org.apache.lucene.search.Query; + +/** + * A dummy {@link Query} implementation. + * + * @author Matthew Denner + * @version $Revision$ + */ +final class MockQuery extends Query { + /** + * @see org.apache.lucene.search.Query#toString(java.lang.String) + */ + public String toString(String field) { + return field; + } +} Index: src/test/org/apache/lucene/search/queryfactory/TestLowerCaseQueryFactory.java =================================================================== RCS file: src/test/org/apache/lucene/search/queryfactory/TestLowerCaseQueryFactory.java diff -N src/test/org/apache/lucene/search/queryfactory/TestLowerCaseQueryFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/test/org/apache/lucene/search/queryfactory/TestLowerCaseQueryFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,177 @@ +/** + * Copyright 2002-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. + */ +package org.apache.lucene.search.queryfactory; + +import java.util.ArrayList; +import java.util.Locale; + +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.search.QueryFactory; + +import com.mockobjects.constraint.Constraint; +import com.mockobjects.constraint.IsEqual; +import com.mockobjects.dynamic.C; +import com.mockobjects.dynamic.FullConstraintMatcher; +import com.mockobjects.dynamic.Mock; + +import junit.framework.TestCase; + +/** + * Test {@link org.apache.lucene.search.queryfactory.LowerCaseQueryFactory}. + * + * @author Matthew Denner + * @version $Revision$ + */ +public class TestLowerCaseQueryFactory extends TestCase { + public void testConstruction() { + try { + new LowerCaseQueryFactory(null); + fail("null delegate QueryFactory did not throw"); + } catch (final IllegalArgumentException exception) { + assertTrue(true); + } + } + + public void testGetLocale() { + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getLocale", C.NO_ARGS, Locale.getDefault()); + + final LowerCaseQueryFactory factory = new LowerCaseQueryFactory((QueryFactory)mockDelegate.proxy()); + assertEquals("Locale different", Locale.getDefault(), factory.getLocale()); + + mockDelegate.verify(); + } + + public void testGetBooleanQuery() { + final MockQuery query = new MockQuery(); + + final ArrayList clauses = new ArrayList(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getBooleanQuery", C.args(C.eq(clauses)), query); + + final LowerCaseQueryFactory factory = new LowerCaseQueryFactory((QueryFactory)mockDelegate.proxy()); + assertEquals("Boolean query different", query, factory.getBooleanQuery(clauses)); + + mockDelegate.verify(); + } + + public void testGetWildcardQuery() throws Exception { + final MockQuery query = new MockQuery(); + + final ArrayList clauses = new ArrayList(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getWildcardQuery", C.args(C.eq("field"), C.eq("TERM")), query); + + final LowerCaseQueryFactory factory = new LowerCaseQueryFactory((QueryFactory)mockDelegate.proxy()); + assertEquals("Wildcard query different", query, factory.getWildcardQuery("field", "TERM")); + + mockDelegate.verify(); + } + + public void testGetRangeQuery() throws Exception { + final MockQuery query = new MockQuery(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getLocale", C.NO_ARGS, Locale.getDefault()); + mockDelegate.expectAndReturn("getLocale", C.NO_ARGS, Locale.getDefault()); + mockDelegate.expectAndReturn( + "getRangeQuery", + new FullConstraintMatcher(new Constraint[] { + C.eq("field"), + C.eq("LOWER".toLowerCase(Locale.getDefault())), + C.eq("UPPER".toLowerCase(Locale.getDefault())), + C.eq(true) + }), + query); + + final LowerCaseQueryFactory factory = new LowerCaseQueryFactory((QueryFactory)mockDelegate.proxy()); + assertEquals( + "Range query different", + query, + factory.getRangeQuery("field", "LOWER", "UPPER", true)); + + mockDelegate.verify(); + } + + public void testGetPrefixQuery() throws Exception { + final MockQuery query = new MockQuery(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getLocale", C.NO_ARGS, Locale.getDefault()); + mockDelegate.expectAndReturn( + "getPrefixQuery", + C.args(C.eq("field"), C.eq("TERM".toLowerCase(Locale.getDefault()))), + query); + + final LowerCaseQueryFactory factory = new LowerCaseQueryFactory((QueryFactory)mockDelegate.proxy()); + assertEquals( + "Prefix query different", + query, + factory.getPrefixQuery("field", "TERM")); + + mockDelegate.verify(); + } + + public void testGetFuzzyQuery() throws Exception { + final MockQuery query = new MockQuery(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getLocale", C.NO_ARGS, Locale.getDefault()); + mockDelegate.expectAndReturn( + "getFuzzyQuery", + C.args( + C.eq("field"), + C.eq("TERM".toLowerCase(Locale.getDefault())), + new IsEqual(new Float(1.0f))), // Damn floats & doubles! + query); + + final LowerCaseQueryFactory factory = new LowerCaseQueryFactory((QueryFactory)mockDelegate.proxy()); + assertEquals( + "Fuzzy query different", + query, + factory.getFuzzyQuery("field", "TERM", 1.0f)); + + mockDelegate.verify(); + } + + public void testGetFieldQuery() throws Exception { + final StandardAnalyzer analyzer = new StandardAnalyzer(); + + final MockQuery query = new MockQuery(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getLocale", C.NO_ARGS, Locale.getDefault()); + mockDelegate.expectAndReturn( + "getFieldQuery", + new FullConstraintMatcher(new Constraint[] { + C.eq("field"), + C.eq(analyzer), + C.eq("TERM".toLowerCase(Locale.getDefault())), + C.eq(0) + }), + query); + + final LowerCaseQueryFactory factory = new LowerCaseQueryFactory((QueryFactory)mockDelegate.proxy()); + assertEquals( + "Fuzzy query different", + query, + factory.getFieldQuery("field", analyzer, "TERM", 0)); + + mockDelegate.verify(); + } +} Index: src/test/org/apache/lucene/search/queryfactory/TestMultiFieldQueryFactory.java =================================================================== RCS file: src/test/org/apache/lucene/search/queryfactory/TestMultiFieldQueryFactory.java diff -N src/test/org/apache/lucene/search/queryfactory/TestMultiFieldQueryFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/test/org/apache/lucene/search/queryfactory/TestMultiFieldQueryFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,343 @@ +/** + * Copyright 2002-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. + */ +package org.apache.lucene.search.queryfactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; + +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryFactory; +import org.apache.lucene.search.queryfactory.MultiFieldQueryFactory.Handler; + +import com.mockobjects.constraint.Constraint; +import com.mockobjects.constraint.IsEqual; +import com.mockobjects.dynamic.C; +import com.mockobjects.dynamic.FullConstraintMatcher; +import com.mockobjects.dynamic.Mock; + +import junit.framework.TestCase; + +/** + * Tests {@link org.apache.lucene.search.queryfactory.MultiFieldQueryFactory}. + * + * @author Matthew Denner + * @version $Revision$ + */ +public class TestMultiFieldQueryFactory extends TestCase { + public void testConstruction() { + { + final Mock mockDelegate = new Mock(QueryFactory.class); + + try { + new MultiFieldQueryFactory(null, (QueryFactory)mockDelegate.proxy()); + fail("null fields did not throw"); + } catch (final IllegalArgumentException exception) { + assertTrue(true); + } + + mockDelegate.verify(); + } + { + final Mock mockDelegate = new Mock(QueryFactory.class); + + try { + new MultiFieldQueryFactory(new String[ 0 ], (QueryFactory)mockDelegate.proxy()); + fail("Zero fields did not throw"); + } catch (final IllegalArgumentException exception) { + assertTrue(true); + } + + mockDelegate.verify(); + } + { + try { + new MultiFieldQueryFactory(new String[ 1 ], null); + fail("null QueryFactory delegate did not throw"); + } catch (final IllegalArgumentException exception) { + assertTrue(true); + } + } + } + + public void testGetLocale() { + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getLocale", C.NO_ARGS, Locale.getDefault()); + + final MultiFieldQueryFactory factory = + new MultiFieldQueryFactory( + new String[] { "field1" }, + (QueryFactory)mockDelegate.proxy()); + assertEquals("Locale different", Locale.getDefault(), factory.getLocale()); + + mockDelegate.verify(); + } + + public void testGetBooleanQuery() throws Exception { + final MockQuery query = new MockQuery(); + + final ArrayList clauses = new ArrayList(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn("getBooleanQuery", C.args(C.eq(clauses)), query); + + final MultiFieldQueryFactory factory = + new MultiFieldQueryFactory( + new String[] { "field1" }, + (QueryFactory)mockDelegate.proxy()); + assertEquals("Boolean query invalid", query, factory.getBooleanQuery(clauses)); + + mockDelegate.verify(); + } + + public void testGetBooleanQueryWithHandler() throws Exception { + { // Non-null field calls handler directly + final MockQuery query = new MockQuery(); + + final Mock mockHandler = new Mock(Handler.class); + mockHandler.expectAndReturn("getQuery", C.args(C.eq("field2")), query); + + final Mock mockDelegate = new Mock(QueryFactory.class); + + final MultiFieldQueryFactory factory = + new MultiFieldQueryFactory( + new String[] { "field1" }, + (QueryFactory)mockDelegate.proxy()); + assertEquals( + "Query invalid", + query, + factory.getBooleanQuery("field2", (Handler)mockHandler.proxy())); + + mockDelegate.verify(); + mockHandler.verify(); + } + { // null field calls delegate for each defined field + final MockQuery fieldQuery = new MockQuery(); + + final Mock mockHandler = new Mock(Handler.class); + mockHandler.expectAndReturn("getQuery", C.args(C.eq("field1")), fieldQuery); + + final MockQuery query = new MockQuery(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn( + "getBooleanQuery", + C.args(new ClauseConstraint(new Query[] { fieldQuery })), + query); + + final MultiFieldQueryFactory factory = + new MultiFieldQueryFactory( + new String[] { "field1" }, + (QueryFactory)mockDelegate.proxy()); + + assertEquals( + "Query invalid", + query, + factory.getBooleanQuery(null, (Handler)mockHandler.proxy())); + + mockDelegate.verify(); + mockHandler.verify(); + } + { // null field calls delegate for each defined field (two fields defined) + final MockQuery fieldQuery1 = new MockQuery(); + final MockQuery fieldQuery2 = new MockQuery(); + + final Mock mockHandler = new Mock(Handler.class); + mockHandler.expectAndReturn("getQuery", C.args(C.eq("field1")), fieldQuery1); + mockHandler.expectAndReturn("getQuery", C.args(C.eq("field2")), fieldQuery2); + + final MockQuery query = new MockQuery(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + mockDelegate.expectAndReturn( + "getBooleanQuery", + C.args(new ClauseConstraint(new Query[] { fieldQuery1, fieldQuery2 })), + query); + + final MultiFieldQueryFactory factory = + new MultiFieldQueryFactory( + new String[] { "field1", "field2" }, + (QueryFactory)mockDelegate.proxy()); + + assertEquals( + "Query invalid", + query, + factory.getBooleanQuery(null, (Handler)mockHandler.proxy())); + + mockDelegate.verify(); + mockHandler.verify(); + } + } + + // From now on we really only need to check that the appropriate methods get called + public void testGetWildcardQuery() throws Exception { + checkQuery(new MethodTest() { + public void configureDelegateFactory(final Mock mockDelegate, final MockQuery fieldQuery) { + mockDelegate.expectAndReturn( + "getWildcardQuery", + C.args(C.eq("field1"), C.eq("term")), + fieldQuery); + } + + public Query performQuery(final QueryFactory factory) throws Exception { + return factory.getWildcardQuery(null, "term"); + } + }); + } + + public void testGetPrefixQuery() throws Exception { + checkQuery(new MethodTest() { + public void configureDelegateFactory(final Mock mockDelegate, final MockQuery fieldQuery) { + mockDelegate.expectAndReturn( + "getPrefixQuery", + C.args(C.eq("field1"), C.eq("term")), + fieldQuery); + } + + public Query performQuery(final QueryFactory factory) throws Exception { + return factory.getPrefixQuery(null, "term"); + } + }); + } + + public void testGetFuzzyQuery() throws Exception { + checkQuery(new MethodTest() { + public void configureDelegateFactory(final Mock mockDelegate, final MockQuery fieldQuery) { + mockDelegate.expectAndReturn( + "getFuzzyQuery", + C.args(C.eq("field1"), C.eq("term"), new IsEqual(new Float(1.0f))), + fieldQuery); + } + + public Query performQuery(final QueryFactory factory) throws Exception { + return factory.getFuzzyQuery(null, "term", 1.0f); + } + }); + } + + public void testGetRangeQuery() throws Exception { + checkQuery(new MethodTest() { + public void configureDelegateFactory(final Mock mockDelegate, final MockQuery fieldQuery) { + mockDelegate.expectAndReturn( + "getRangeQuery", + new FullConstraintMatcher(new Constraint[] { + C.eq("field1"), + C.eq("lower"), + C.eq("upper"), + C.eq(true) + }), + fieldQuery); + } + + public Query performQuery(final QueryFactory factory) throws Exception { + return factory.getRangeQuery(null, "lower", "upper", true); + } + }); + } + + public void testGetFieldQuery() throws Exception { + final StandardAnalyzer analyzer = new StandardAnalyzer(); + + checkQuery(new MethodTest() { + public void configureDelegateFactory(final Mock mockDelegate, final MockQuery fieldQuery) { + mockDelegate.expectAndReturn( + "getFieldQuery", + new FullConstraintMatcher(new Constraint[] { + C.eq("field1"), + C.eq(analyzer), + C.eq("term"), + C.eq(0) + }), + fieldQuery); + } + + public Query performQuery(final QueryFactory factory) throws Exception { + return factory.getFieldQuery(null, analyzer, "term", 0); + } + }); + } + + // Utility method to test method calls + private void checkQuery(final MethodTest test) throws Exception { + final MockQuery query = new MockQuery(); + + final MockQuery fieldQuery = new MockQuery(); + + final Mock mockDelegate = new Mock(QueryFactory.class); + test.configureDelegateFactory(mockDelegate, fieldQuery); + mockDelegate.expectAndReturn( + "getBooleanQuery", + C.args(new ClauseConstraint(new Query[] { fieldQuery })), + query); + + final MultiFieldQueryFactory factory = + new MultiFieldQueryFactory( + new String[] { "field1" }, + (QueryFactory)mockDelegate.proxy()); + + assertEquals("Query invalid", query, test.performQuery(factory)); + + mockDelegate.verify(); + } + + /** + * Interface to aid in repeated testing of method calls. + * + * @author Matthew Denner + * @version $Revision$ + */ + private static interface MethodTest { + void configureDelegateFactory(Mock mockDelegate, MockQuery fieldQuery); + Query performQuery(QueryFactory factory) throws Exception; + } + + /** + * Simple (and probably buggy!) {@link Constraint} implemetation that will + * check that the {@link Query} instances in a collection of {@link BooleanClause} + * instances are the same as expected. + * + * @author Matthew Denner + * @version $Revision$ + */ + private static final class ClauseConstraint implements Constraint { + public ClauseConstraint(final Query[] queries) { + m_queries = new HashSet(Arrays.asList(queries)); + } + + /** + * @see com.mockobjects.constraint.Constraint#eval(java.lang.Object) + */ + public boolean eval(final Object arg0) { + return m_queries.equals(toQuerySet((Collection)arg0)); + } + + private Set toQuerySet(final Collection collection) { + final HashSet queries = new HashSet(); + for (Iterator it = collection.iterator(); it.hasNext(); ) { + queries.add(((BooleanClause)it.next()).getQuery()); + } + return queries; + } + + private final Set m_queries; + } +} Index: src/test/org/apache/lucene/search/queryfactory/TestQueryFactoryImpl.java =================================================================== RCS file: src/test/org/apache/lucene/search/queryfactory/TestQueryFactoryImpl.java diff -N src/test/org/apache/lucene/search/queryfactory/TestQueryFactoryImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/test/org/apache/lucene/search/queryfactory/TestQueryFactoryImpl.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,48 @@ +/** + * Copyright 2002-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. + */ +package org.apache.lucene.search.queryfactory; + +import org.apache.lucene.search.QueryFactory; + +import junit.framework.TestCase; + +/** + * Tests {@link org.apache.lucene.search.queryfactory.QueryFactoryImpl}. + * + * @author Matthew Denner + * @version $Revision$ + */ +public class TestQueryFactoryImpl extends TestCase { + /** + * @see junit.framework.TestCase#setUp() + */ + protected void setUp() throws Exception { + m_factory = new QueryFactoryImpl(); + } + + public void testGetRangeQuery() throws Exception { + assertEquals( + "Inclusive query invalid", + "[abc TO def]", + m_factory.getRangeQuery("field", "abc", "def", true).toString("field")); + assertEquals( + "Non-inclusive query invalid", + "{abc TO def}", + m_factory.getRangeQuery("field", "abc", "def", false).toString("field")); + } + + private QueryFactory m_factory; +}