001: package org.apache.lucene.queryParser;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import org.apache.lucene.util.LuceneTestCase;
021: import org.apache.lucene.analysis.Analyzer;
022: import org.apache.lucene.analysis.Token;
023: import org.apache.lucene.analysis.TokenStream;
024: import org.apache.lucene.analysis.standard.StandardAnalyzer;
025: import org.apache.lucene.document.Document;
026: import org.apache.lucene.document.Field;
027: import org.apache.lucene.index.IndexWriter;
028: import org.apache.lucene.search.BooleanClause;
029: import org.apache.lucene.search.BooleanQuery;
030: import org.apache.lucene.search.Hits;
031: import org.apache.lucene.search.IndexSearcher;
032: import org.apache.lucene.search.Query;
033: import org.apache.lucene.search.BooleanClause.Occur;
034: import org.apache.lucene.store.Directory;
035: import org.apache.lucene.store.RAMDirectory;
036:
037: import java.io.Reader;
038: import java.util.HashMap;
039: import java.util.Map;
040:
041: /**
042: * Tests QueryParser.
043: * @author Daniel Naber
044: */
045: public class TestMultiFieldQueryParser extends LuceneTestCase {
046:
047: /** test stop words arsing for both the non static form, and for the
048: * corresponding static form (qtxt, fields[]). */
049: public void tesStopwordsParsing() throws Exception {
050: assertStopQueryEquals("one", "b:one t:one");
051: assertStopQueryEquals("one stop", "b:one t:one");
052: assertStopQueryEquals("one (stop)", "b:one t:one");
053: assertStopQueryEquals("one ((stop))", "b:one t:one");
054: assertStopQueryEquals("stop", "");
055: assertStopQueryEquals("(stop)", "");
056: assertStopQueryEquals("((stop))", "");
057: }
058:
059: // verify parsing of query using a stopping analyzer
060: private void assertStopQueryEquals(String qtxt, String expectedRes)
061: throws Exception {
062: String[] fields = { "b", "t" };
063: Occur occur[] = { Occur.SHOULD, Occur.SHOULD };
064: TestQueryParser.QPTestAnalyzer a = new TestQueryParser.QPTestAnalyzer();
065: MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields,
066: a);
067:
068: Query q = mfqp.parse(qtxt);
069: assertEquals(expectedRes, q.toString());
070:
071: q = MultiFieldQueryParser.parse(qtxt, fields, occur, a);
072: assertEquals(expectedRes, q.toString());
073: }
074:
075: public void testSimple() throws Exception {
076: String[] fields = { "b", "t" };
077: MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields,
078: new StandardAnalyzer());
079:
080: Query q = mfqp.parse("one");
081: assertEquals("b:one t:one", q.toString());
082:
083: q = mfqp.parse("one two");
084: assertEquals("(b:one t:one) (b:two t:two)", q.toString());
085:
086: q = mfqp.parse("+one +two");
087: assertEquals("+(b:one t:one) +(b:two t:two)", q.toString());
088:
089: q = mfqp.parse("+one -two -three");
090: assertEquals(
091: "+(b:one t:one) -(b:two t:two) -(b:three t:three)", q
092: .toString());
093:
094: q = mfqp.parse("one^2 two");
095: assertEquals("((b:one t:one)^2.0) (b:two t:two)", q.toString());
096:
097: q = mfqp.parse("one~ two");
098: assertEquals("(b:one~0.5 t:one~0.5) (b:two t:two)", q
099: .toString());
100:
101: q = mfqp.parse("one~0.8 two^2");
102: assertEquals("(b:one~0.8 t:one~0.8) ((b:two t:two)^2.0)", q
103: .toString());
104:
105: q = mfqp.parse("one* two*");
106: assertEquals("(b:one* t:one*) (b:two* t:two*)", q.toString());
107:
108: q = mfqp.parse("[a TO c] two");
109: assertEquals("(b:[a TO c] t:[a TO c]) (b:two t:two)", q
110: .toString());
111:
112: q = mfqp.parse("w?ldcard");
113: assertEquals("b:w?ldcard t:w?ldcard", q.toString());
114:
115: q = mfqp.parse("\"foo bar\"");
116: assertEquals("b:\"foo bar\" t:\"foo bar\"", q.toString());
117:
118: q = mfqp.parse("\"aa bb cc\" \"dd ee\"");
119: assertEquals(
120: "(b:\"aa bb cc\" t:\"aa bb cc\") (b:\"dd ee\" t:\"dd ee\")",
121: q.toString());
122:
123: q = mfqp.parse("\"foo bar\"~4");
124: assertEquals("b:\"foo bar\"~4 t:\"foo bar\"~4", q.toString());
125:
126: // make sure that terms which have a field are not touched:
127: q = mfqp.parse("one f:two");
128: assertEquals("(b:one t:one) f:two", q.toString());
129:
130: // AND mode:
131: mfqp.setDefaultOperator(QueryParser.AND_OPERATOR);
132: q = mfqp.parse("one two");
133: assertEquals("+(b:one t:one) +(b:two t:two)", q.toString());
134: q = mfqp.parse("\"aa bb cc\" \"dd ee\"");
135: assertEquals(
136: "+(b:\"aa bb cc\" t:\"aa bb cc\") +(b:\"dd ee\" t:\"dd ee\")",
137: q.toString());
138:
139: }
140:
141: public void testBoostsSimple() throws Exception {
142: Map boosts = new HashMap();
143: boosts.put("b", new Float(5));
144: boosts.put("t", new Float(10));
145: String[] fields = { "b", "t" };
146: MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields,
147: new StandardAnalyzer(), boosts);
148:
149: //Check for simple
150: Query q = mfqp.parse("one");
151: assertEquals("b:one^5.0 t:one^10.0", q.toString());
152:
153: //Check for AND
154: q = mfqp.parse("one AND two");
155: assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0)",
156: q.toString());
157:
158: //Check for OR
159: q = mfqp.parse("one OR two");
160: assertEquals("(b:one^5.0 t:one^10.0) (b:two^5.0 t:two^10.0)", q
161: .toString());
162:
163: //Check for AND and a field
164: q = mfqp.parse("one AND two AND foo:test");
165: assertEquals(
166: "+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0) +foo:test",
167: q.toString());
168:
169: q = mfqp.parse("one^3 AND two^4");
170: assertEquals(
171: "+((b:one^5.0 t:one^10.0)^3.0) +((b:two^5.0 t:two^10.0)^4.0)",
172: q.toString());
173: }
174:
175: public void testStaticMethod1() throws ParseException {
176: String[] fields = { "b", "t" };
177: String[] queries = { "one", "two" };
178: Query q = MultiFieldQueryParser.parse(queries, fields,
179: new StandardAnalyzer());
180: assertEquals("b:one t:two", q.toString());
181:
182: String[] queries2 = { "+one", "+two" };
183: q = MultiFieldQueryParser.parse(queries2, fields,
184: new StandardAnalyzer());
185: assertEquals("(+b:one) (+t:two)", q.toString());
186:
187: String[] queries3 = { "one", "+two" };
188: q = MultiFieldQueryParser.parse(queries3, fields,
189: new StandardAnalyzer());
190: assertEquals("b:one (+t:two)", q.toString());
191:
192: String[] queries4 = { "one +more", "+two" };
193: q = MultiFieldQueryParser.parse(queries4, fields,
194: new StandardAnalyzer());
195: assertEquals("(b:one +b:more) (+t:two)", q.toString());
196:
197: String[] queries5 = { "blah" };
198: try {
199: q = MultiFieldQueryParser.parse(queries5, fields,
200: new StandardAnalyzer());
201: fail();
202: } catch (IllegalArgumentException e) {
203: // expected exception, array length differs
204: }
205:
206: // check also with stop words for this static form (qtxts[], fields[]).
207: TestQueryParser.QPTestAnalyzer stopA = new TestQueryParser.QPTestAnalyzer();
208:
209: String[] queries6 = { "((+stop))", "+((stop))" };
210: q = MultiFieldQueryParser.parse(queries6, fields, stopA);
211: assertEquals("", q.toString());
212:
213: String[] queries7 = { "one ((+stop)) +more", "+((stop)) +two" };
214: q = MultiFieldQueryParser.parse(queries7, fields, stopA);
215: assertEquals("(b:one +b:more) (+t:two)", q.toString());
216:
217: }
218:
219: public void testStaticMethod2() throws ParseException {
220: String[] fields = { "b", "t" };
221: BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST,
222: BooleanClause.Occur.MUST_NOT };
223: Query q = MultiFieldQueryParser.parse("one", fields, flags,
224: new StandardAnalyzer());
225: assertEquals("+b:one -t:one", q.toString());
226:
227: q = MultiFieldQueryParser.parse("one two", fields, flags,
228: new StandardAnalyzer());
229: assertEquals("+(b:one b:two) -(t:one t:two)", q.toString());
230:
231: try {
232: BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST };
233: q = MultiFieldQueryParser.parse("blah", fields, flags2,
234: new StandardAnalyzer());
235: fail();
236: } catch (IllegalArgumentException e) {
237: // expected exception, array length differs
238: }
239: }
240:
241: public void testStaticMethod2Old() throws ParseException {
242: String[] fields = { "b", "t" };
243: //int[] flags = {MultiFieldQueryParser.REQUIRED_FIELD, MultiFieldQueryParser.PROHIBITED_FIELD};
244: BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST,
245: BooleanClause.Occur.MUST_NOT };
246: MultiFieldQueryParser parser = new MultiFieldQueryParser(
247: fields, new StandardAnalyzer());
248:
249: Query q = MultiFieldQueryParser.parse("one", fields, flags,
250: new StandardAnalyzer());//, fields, flags, new StandardAnalyzer());
251: assertEquals("+b:one -t:one", q.toString());
252:
253: q = MultiFieldQueryParser.parse("one two", fields, flags,
254: new StandardAnalyzer());
255: assertEquals("+(b:one b:two) -(t:one t:two)", q.toString());
256:
257: try {
258: BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST };
259: q = MultiFieldQueryParser.parse("blah", fields, flags2,
260: new StandardAnalyzer());
261: fail();
262: } catch (IllegalArgumentException e) {
263: // expected exception, array length differs
264: }
265: }
266:
267: public void testStaticMethod3() throws ParseException {
268: String[] queries = { "one", "two", "three" };
269: String[] fields = { "f1", "f2", "f3" };
270: BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST,
271: BooleanClause.Occur.MUST_NOT,
272: BooleanClause.Occur.SHOULD };
273: Query q = MultiFieldQueryParser.parse(queries, fields, flags,
274: new StandardAnalyzer());
275: assertEquals("+f1:one -f2:two f3:three", q.toString());
276:
277: try {
278: BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST };
279: q = MultiFieldQueryParser.parse(queries, fields, flags2,
280: new StandardAnalyzer());
281: fail();
282: } catch (IllegalArgumentException e) {
283: // expected exception, array length differs
284: }
285: }
286:
287: public void testStaticMethod3Old() throws ParseException {
288: String[] queries = { "one", "two" };
289: String[] fields = { "b", "t" };
290: BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST,
291: BooleanClause.Occur.MUST_NOT };
292: Query q = MultiFieldQueryParser.parse(queries, fields, flags,
293: new StandardAnalyzer());
294: assertEquals("+b:one -t:two", q.toString());
295:
296: try {
297: BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST };
298: q = MultiFieldQueryParser.parse(queries, fields, flags2,
299: new StandardAnalyzer());
300: fail();
301: } catch (IllegalArgumentException e) {
302: // expected exception, array length differs
303: }
304: }
305:
306: public void testAnalyzerReturningNull() throws ParseException {
307: String[] fields = new String[] { "f1", "f2", "f3" };
308: MultiFieldQueryParser parser = new MultiFieldQueryParser(
309: fields, new AnalyzerReturningNull());
310: Query q = parser.parse("bla AND blo");
311: assertEquals("+(f2:bla f3:bla) +(f2:blo f3:blo)", q.toString());
312: // the following queries are not affected as their terms are not analyzed anyway:
313: q = parser.parse("bla*");
314: assertEquals("f1:bla* f2:bla* f3:bla*", q.toString());
315: q = parser.parse("bla~");
316: assertEquals("f1:bla~0.5 f2:bla~0.5 f3:bla~0.5", q.toString());
317: q = parser.parse("[a TO c]");
318: assertEquals("f1:[a TO c] f2:[a TO c] f3:[a TO c]", q
319: .toString());
320: }
321:
322: public void testStopWordSearching() throws Exception {
323: Analyzer analyzer = new StandardAnalyzer();
324: Directory ramDir = new RAMDirectory();
325: IndexWriter iw = new IndexWriter(ramDir, analyzer, true);
326: Document doc = new Document();
327: doc.add(new Field("body", "blah the footest blah",
328: Field.Store.NO, Field.Index.TOKENIZED));
329: iw.addDocument(doc);
330: iw.close();
331:
332: MultiFieldQueryParser mfqp = new MultiFieldQueryParser(
333: new String[] { "body" }, analyzer);
334: mfqp.setDefaultOperator(QueryParser.Operator.AND);
335: Query q = mfqp.parse("the footest");
336: IndexSearcher is = new IndexSearcher(ramDir);
337: Hits hits = is.search(q);
338: assertEquals(1, hits.length());
339: is.close();
340: }
341:
342: /**
343: * Return empty tokens for field "f1".
344: */
345: private static class AnalyzerReturningNull extends Analyzer {
346: StandardAnalyzer stdAnalyzer = new StandardAnalyzer();
347:
348: public AnalyzerReturningNull() {
349: }
350:
351: public TokenStream tokenStream(String fieldName, Reader reader) {
352: if ("f1".equals(fieldName)) {
353: return new EmptyTokenStream();
354: } else {
355: return stdAnalyzer.tokenStream(fieldName, reader);
356: }
357: }
358:
359: private static class EmptyTokenStream extends TokenStream {
360: public Token next() {
361: return null;
362: }
363: }
364: }
365:
366: }
|