Index: CHANGES.txt =================================================================== --- CHANGES.txt (revision 828142) +++ CHANGES.txt (working copy) @@ -39,6 +39,11 @@ settings in StandardAnalyzer to be compatible with the coming Lucene 3.0. (Uwe Schindler) + * LUCENE-2002: Add required Version matchVersion argument when + constructing QueryParser or MultiFieldQueryParser and, default (as + of 2.9) enablePositionIncrements to true to match + StandardAnalyzer's default (Uwe Schindler, Mike McCandless) + Documentation * LUCENE-1955: Fix Hits deprecation notice to point users in right Index: src/test/org/apache/lucene/queryParser/TestQueryParser.java =================================================================== --- src/test/org/apache/lucene/queryParser/TestQueryParser.java (revision 828142) +++ src/test/org/apache/lucene/queryParser/TestQueryParser.java (working copy) @@ -47,6 +47,7 @@ import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Term; +import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.FuzzyQuery; @@ -60,7 +61,10 @@ import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.MockRAMDirectory; import org.apache.lucene.util.LocalizedTestCase; +import org.apache.lucene.util.Version; /** * Tests QueryParser. @@ -1014,4 +1018,24 @@ BooleanQuery.setMaxClauseCount(originalMaxClauses); } + // LUCENE-2002: make sure defaults for StandardAnalyzer's + // enableStopPositionIncr & QueryParser's enablePosIncr + // "match" + public void testPositionIncrements() throws Exception { + Directory dir = new MockRAMDirectory(); + Analyzer a = new StandardAnalyzer(Version.LUCENE_CURRENT); + IndexWriter w = new IndexWriter(dir, a, IndexWriter.MaxFieldLength.UNLIMITED); + Document doc = new Document(); + doc.add(new Field("f", "the wizard of ozzy", Field.Store.NO, Field.Index.ANALYZED)); + w.addDocument(doc); + IndexReader r = w.getReader(); + w.close(); + IndexSearcher s = new IndexSearcher(r); + QueryParser qp = new QueryParser(Version.LUCENE_CURRENT, "f", a); + Query q = qp.parse("\"wizard of ozzy\""); + assertEquals(1, s.search(q, 1).totalHits); + r.close(); + dir.close(); + } + } Index: src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java =================================================================== --- src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java (revision 828142) +++ src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java (working copy) @@ -27,6 +27,7 @@ import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.util.Version; /** * A QueryParser which constructs queries to search multiple fields. @@ -64,13 +65,47 @@ * *

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

+ * + * @deprecated Please use {@link #MultiFieldQueryParser(Version, String[], Analyzer, Map)} instead */ public MultiFieldQueryParser(String[] fields, Analyzer analyzer, Map boosts) { - this(fields,analyzer); + this(Version.LUCENE_24, fields, analyzer); this.boosts = boosts; } /** + * Creates a MultiFieldQueryParser. + * Allows passing of a map with term to Boost, and the boost to apply to each term. + * + *

It 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 title and body):

+ * + * + * (title:term1 body:term1) (title:term2 body:term2) + * + * + *

When setDefaultOperator(AND_OPERATOR) is set, the result will be:

+ * + * + * +(title:term1 body:term1) +(title:term2 body:term2) + * + * + *

When you pass a boost (title=>5 body=>10) you can get

+ * + * + * +(title:term1^5.0 body:term1^10.0) +(title:term2^5.0 body:term2^10.0) + * + * + *

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

+ */ + public MultiFieldQueryParser(Version matchVersion, String[] fields, Analyzer analyzer, Map boosts) { + this(matchVersion, fields, analyzer); + this.boosts = boosts; + } + + /** * Creates a MultiFieldQueryParser. * *

It will, when parse(String query) @@ -89,9 +124,35 @@ * *

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

+ * + * @deprecated Please use {@link #MultiFieldQueryParser(Version, String[], Analyzer} instead */ public MultiFieldQueryParser(String[] fields, Analyzer analyzer) { - super(null, analyzer); + this(Version.LUCENE_24, fields, analyzer); + } + + /** + * Creates a MultiFieldQueryParser. + * + *

It 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 title and body):

+ * + * + * (title:term1 body:term1) (title:term2 body:term2) + * + * + *

When setDefaultOperator(AND_OPERATOR) is set, the result will be:

+ * + * + * +(title:term1 body:term1) +(title:term2 body:term2) + * + * + *

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

+ */ + public MultiFieldQueryParser(Version matchVersion, String[] fields, Analyzer analyzer) { + super(matchVersion, null, analyzer); this.fields = fields; } @@ -202,16 +263,40 @@ * @throws ParseException if query parsing fails * @throws IllegalArgumentException if the length of the queries array differs * from the length of the fields array + * @deprecated Use {@link #parse(Version,String[],Analyzer)} instead */ public static Query parse(String[] queries, String[] fields, Analyzer analyzer) throws ParseException { + return parse(Version.LUCENE_24, queries, fields, analyzer); + } + + /** + * Parses a query which searches on the fields specified. + *

+ * If x fields are specified, this effectively constructs: + *

+   * 
+   * (field1:query1) (field2:query2) (field3:query3)...(fieldx:queryx)
+   * 
+   * 
+ * @param matchVersion Lucene version to patch; this is passed through to QueryParser. + * @param queries Queries strings to parse + * @param fields Fields to search on + * @param analyzer Analyzer to use + * @throws ParseException 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(Version matchVersion, String[] queries, String[] fields, + Analyzer analyzer) throws ParseException + { if (queries.length != fields.length) throw new IllegalArgumentException("queries.length != fields.length"); BooleanQuery bQuery = new BooleanQuery(); for (int i = 0; i < fields.length; i++) { - QueryParser qp = new QueryParser(fields[i], analyzer); + QueryParser qp = new QueryParser(matchVersion, fields[i], analyzer); Query q = qp.parse(queries[i]); if (q!=null && // q never null, just being defensive (!(q instanceof BooleanQuery) || ((BooleanQuery)q).getClauses().length>0)) { @@ -250,14 +335,51 @@ * @throws ParseException if query parsing fails * @throws IllegalArgumentException if the length of the fields array differs * from the length of the flags array + * @deprecated Use {@link #parse(Version, String, String[], BooleanClause.Occur[], Analyzer)} instead */ public static Query parse(String query, String[] fields, BooleanClause.Occur[] flags, Analyzer analyzer) throws ParseException { + return parse(Version.LUCENE_24, query, fields, flags, analyzer); + } + + /** + * Parses a query, searching on the fields specified. + * Use this if you need to specify certain fields as required, + * and others as prohibited. + *

+   * Usage:
+   * 
+   * String[] fields = {"filename", "contents", "description"};
+   * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD,
+   *                BooleanClause.Occur.MUST,
+   *                BooleanClause.Occur.MUST_NOT};
+   * MultiFieldQueryParser.parse("query", fields, flags, analyzer);
+   * 
+   * 
+ *

+ * The code above would construct a query: + *

+   * 
+   * (filename:query) +(contents:query) -(description:query)
+   * 
+   * 
+ * + * @param matchVersion Lucene version to patch; this is passed through to QueryParser. + * @param query Query string to parse + * @param fields Fields to search on + * @param flags Flags describing the fields + * @param analyzer Analyzer to use + * @throws ParseException 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(Version matchVersion, String query, String[] fields, + BooleanClause.Occur[] flags, 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++) { - QueryParser qp = new QueryParser(fields[i], analyzer); + QueryParser qp = new QueryParser(matchVersion, fields[i], analyzer); Query q = qp.parse(query); if (q!=null && // q never null, just being defensive (!(q instanceof BooleanQuery) || ((BooleanQuery)q).getClauses().length>0)) { @@ -297,16 +419,55 @@ * @throws ParseException if query parsing fails * @throws IllegalArgumentException if the length of the queries, fields, * and flags array differ + * @deprecated Used {@link #parse(Version, String[], String[], BooleanClause.Occur[], Analyzer)} instead */ public static Query parse(String[] queries, String[] fields, BooleanClause.Occur[] flags, Analyzer analyzer) throws ParseException { + return parse(Version.LUCENE_24, queries, fields, flags, analyzer); + } + + /** + * Parses a query, searching on the fields specified. + * Use this if you need to specify certain fields as required, + * and others as prohibited. + *

+   * Usage:
+   * 
+   * String[] query = {"query1", "query2", "query3"};
+   * String[] fields = {"filename", "contents", "description"};
+   * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD,
+   *                BooleanClause.Occur.MUST,
+   *                BooleanClause.Occur.MUST_NOT};
+   * MultiFieldQueryParser.parse(query, fields, flags, analyzer);
+   * 
+   * 
+ *

+ * The code above would construct a query: + *

+   * 
+   * (filename:query1) +(contents:query2) -(description:query3)
+   * 
+   * 
+ * + * @param matchVersion Lucene version to patch; this is passed through to QueryParser. + * @param queries Queries string to parse + * @param fields Fields to search on + * @param flags Flags describing the fields + * @param analyzer Analyzer to use + * @throws ParseException if query parsing fails + * @throws IllegalArgumentException if the length of the queries, fields, + * and flags array differ + */ + public static Query parse(Version matchVersion, String[] queries, String[] fields, BooleanClause.Occur[] flags, + Analyzer analyzer) throws ParseException + { 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++) { - QueryParser qp = new QueryParser(fields[i], analyzer); + QueryParser qp = new QueryParser(matchVersion, fields[i], analyzer); Query q = qp.parse(queries[i]); if (q!=null && // q never null, just being defensive (!(q instanceof BooleanQuery) || ((BooleanQuery)q).getClauses().length>0)) { Index: src/java/org/apache/lucene/queryParser/QueryParser.java =================================================================== --- src/java/org/apache/lucene/queryParser/QueryParser.java (revision 828142) +++ src/java/org/apache/lucene/queryParser/QueryParser.java (working copy) @@ -35,6 +35,7 @@ import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.util.Parameter; +import org.apache.lucene.util.Version; /** * This class is generated by JavaCC. The most important method is @@ -101,6 +102,14 @@ *

NOTE: there is a new QueryParser in contrib, which matches * the same syntax as this class, but is more modular, * enabling substantial customization to how a query is created. + * + * + *

NOTE: You must specify the required {@link Version} + * compatibility when creating QueryParser: + *

*/ public class QueryParser implements QueryParserConstants { @@ -125,7 +134,7 @@ boolean lowercaseExpandedTerms = true; MultiTermQuery.RewriteMethod multiTermRewriteMethod = MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT; boolean allowLeadingWildcard = false; - boolean enablePositionIncrements = false; + boolean enablePositionIncrements = true; Analyzer analyzer; String field; @@ -158,11 +167,27 @@ /** Constructs a query parser. * @param f the default field for query terms. * @param a used to find terms in the query text. + * @deprecated Use {@link #QueryParser(String, Analyzer, + * Version)} instead. */ public QueryParser(String f, Analyzer a) { + this(Version.LUCENE_24, f, a); + } + + /** Constructs a query parser. + * @param matchVersion Lucene version to match. See {@link above) + * @param f the default field for query terms. + * @param a used to find terms in the query text. + */ + public QueryParser(Version matchVersion, String f, Analyzer a) { this(new FastCharStream(new StringReader(""))); analyzer = a; field = f; + if (matchVersion.onOrAfter(Version.LUCENE_29)) { + enablePositionIncrements = true; + } else { + enablePositionIncrements = false; + } } /** Parses a query string, returning a {@link org.apache.lucene.search.Query}. @@ -759,7 +784,7 @@ DateTools.Resolution resolution = getDateResolution(field); if (resolution == null) { // no default or field specific date resolution has been set, - // use deprecated DateField to maintain compatibilty with + // use deprecated DateField to maintain compatibility with // pre-1.9 Lucene versions. part1 = DateField.dateToString(d1); part2 = DateField.dateToString(d2); @@ -1155,7 +1180,7 @@ System.out.println("Usage: java org.apache.lucene.queryParser.QueryParser "); System.exit(0); } - QueryParser qp = new QueryParser("field", + QueryParser qp = new QueryParser(Version.LUCENE_CURRENT, "field", new org.apache.lucene.analysis.SimpleAnalyzer()); Query q = qp.parse(args[0]); System.out.println(q.toString("field")); @@ -1591,6 +1616,12 @@ finally { jj_save(0, xla); } } + private boolean jj_3R_2() { + if (jj_scan_token(TERM)) return true; + if (jj_scan_token(COLON)) return true; + return false; + } + private boolean jj_3_1() { Token xsp; xsp = jj_scanpos; @@ -1607,12 +1638,6 @@ return false; } - private boolean jj_3R_2() { - if (jj_scan_token(TERM)) return true; - if (jj_scan_token(COLON)) return true; - return false; - } - /** Generated Token Manager. */ public QueryParserTokenManager token_source; /** Current token. */ Index: src/java/org/apache/lucene/queryParser/QueryParser.jj =================================================================== --- src/java/org/apache/lucene/queryParser/QueryParser.jj (revision 828142) +++ src/java/org/apache/lucene/queryParser/QueryParser.jj (working copy) @@ -59,6 +59,7 @@ import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.util.Parameter; +import org.apache.lucene.util.Version; /** * This class is generated by JavaCC. The most important method is @@ -125,6 +126,14 @@ *

NOTE: there is a new QueryParser in contrib, which matches * the same syntax as this class, but is more modular, * enabling substantial customization to how a query is created. + * + * + *

NOTE: You must specify the required {@link Version} + * compatibility when creating QueryParser: + *

*/ public class QueryParser { @@ -149,7 +158,7 @@ boolean lowercaseExpandedTerms = true; MultiTermQuery.RewriteMethod multiTermRewriteMethod = MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT; boolean allowLeadingWildcard = false; - boolean enablePositionIncrements = false; + boolean enablePositionIncrements = true; Analyzer analyzer; String field; @@ -182,11 +191,27 @@ /** Constructs a query parser. * @param f the default field for query terms. * @param a used to find terms in the query text. + * @deprecated Use {@link #QueryParser(String, Analyzer, + * Version)} instead. */ public QueryParser(String f, Analyzer a) { + this(Version.LUCENE_24, f, a); + } + + /** Constructs a query parser. + * @param matchVersion Lucene version to match. See {@link above) + * @param f the default field for query terms. + * @param a used to find terms in the query text. + */ + public QueryParser(Version matchVersion, String f, Analyzer a) { this(new FastCharStream(new StringReader(""))); analyzer = a; field = f; + if (matchVersion.onOrAfter(Version.LUCENE_29)) { + enablePositionIncrements = true; + } else { + enablePositionIncrements = false; + } } /** Parses a query string, returning a {@link org.apache.lucene.search.Query}. @@ -1179,7 +1204,7 @@ System.out.println("Usage: java org.apache.lucene.queryParser.QueryParser "); System.exit(0); } - QueryParser qp = new QueryParser("field", + QueryParser qp = new QueryParser(Version.LUCENE_CURRENT, "field", new org.apache.lucene.analysis.SimpleAnalyzer()); Query q = qp.parse(args[0]); System.out.println(q.toString("field")); Index: src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java =================================================================== --- src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java (revision 828142) +++ src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java (working copy) @@ -33,6 +33,7 @@ import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.util.Parameter; +import org.apache.lucene.util.Version; /** Token Manager. */ public class QueryParserTokenManager implements QueryParserConstants Index: contrib/CHANGES.txt =================================================================== --- contrib/CHANGES.txt (revision 828142) +++ contrib/CHANGES.txt (working copy) @@ -10,6 +10,14 @@ list. This has no effect on Arabic text, but if you are using a custom stopword list that contains some non-Arabic words, you'll need to fully reindex. (DM Smith via Robert Muir) + +API Changes: + + * LUCENE-2002: Add required Version matchVersion argument when + constructing ComplexPhraseQueryParser and default (as of 2.9) + enablePositionIncrements to true to match StandardAnalyzer's + default (Uwe Schindler, Mike McCandless) + Bug fixes Index: contrib/misc/src/java/org/apache/lucene/queryParser/complexPhrase/ComplexPhraseQueryParser.java =================================================================== --- contrib/misc/src/java/org/apache/lucene/queryParser/complexPhrase/ComplexPhraseQueryParser.java (revision 828142) +++ contrib/misc/src/java/org/apache/lucene/queryParser/complexPhrase/ComplexPhraseQueryParser.java (working copy) @@ -38,6 +38,7 @@ import org.apache.lucene.search.spans.SpanOrQuery; import org.apache.lucene.search.spans.SpanQuery; import org.apache.lucene.search.spans.SpanTermQuery; +import org.apache.lucene.util.Version; /** * QueryParser which permits complex phrase query syntax eg "(john jon @@ -67,10 +68,17 @@ private ComplexPhraseQuery currentPhraseQuery = null; + /** @deprecated Use {@link + #ComplexPhraseQueryParser{Version, String, Analyzer)} + instead.*/ public ComplexPhraseQueryParser(String f, Analyzer a) { - super(f, a); + this(Version.LUCENE_24, f, a); } + public ComplexPhraseQueryParser(Version matchVersion, String f, Analyzer a) { + super(matchVersion, f, a); + } + protected Query getFieldQuery(String field, String queryText, int slop) { ComplexPhraseQuery cpq = new ComplexPhraseQuery(field, queryText, slop); complexPhrases.add(cpq); // add to list of phrases to be parsed once