Index: lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinWithExplanations.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinWithExplanations.java (revision ) +++ lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinWithExplanations.java (revision ) @@ -0,0 +1,191 @@ +package org.apache.lucene.search.join; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import org.apache.lucene.analysis.MockAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.document.Field.Store; +import org.apache.lucene.document.IntPoint; +import org.apache.lucene.document.NumericDocValuesField; +import org.apache.lucene.document.SortedDocValuesField; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.document.StringField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.index.LogDocMergePolicy; +import org.apache.lucene.index.MultiFields; +import org.apache.lucene.index.NoMergePolicy; +import org.apache.lucene.index.PostingsEnum; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.index.ReaderUtil; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.*; +import org.apache.lucene.search.BooleanClause.Occur; +import org.apache.lucene.search.grouping.GroupDocs; +import org.apache.lucene.search.grouping.TopGroups; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BitSet; +import org.apache.lucene.util.Bits; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util.TestUtil; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class TestBlockJoinWithExplanations extends BaseExplanationTestCase { + + // One resume... + private Document makeResume(String name, String country) { + Document resume = new Document(); + resume.add(newStringField("docType", "resume", Store.NO)); + resume.add(newStringField("name", name, Store.YES)); + resume.add(newStringField("country", country, Store.NO)); + return resume; + } + + // ... has multiple jobs + private Document makeJob(String skill, int year) { + Document job = new Document(); + job.add(newStringField("skill", skill, Store.YES)); + job.add(new IntPoint("year", year)); + job.add(new StoredField("year", year)); + return job; + } + + // ... has multiple qualifications + private Document makeQualification(String qualification, int year) { + Document job = new Document(); + job.add(newStringField("qualification", qualification, Store.YES)); + job.add(new IntPoint("year", year)); + return job; + } + + private Document getParentDoc(IndexReader reader, BitSetProducer parents, int childDocID) throws IOException { + final List leaves = reader.leaves(); + final int subIndex = ReaderUtil.subIndex(childDocID, leaves); + final LeafReaderContext leaf = leaves.get(subIndex); + final BitSet bits = parents.getBitSet(leaf); + return leaf.reader().document(bits.nextSetBit(childDocID - leaf.docBase)); + } + + public void testSimple() throws Exception { + + final Directory dir = newDirectory(); + final RandomIndexWriter w = new RandomIndexWriter(random(), dir); + + final List docs = new ArrayList<>(); + + docs.add(makeJob("java", 2007)); + docs.add(makeJob("python", 2010)); + docs.add(makeResume("Lisa", "United Kingdom")); + w.addDocuments(docs); + + docs.clear(); + docs.add(makeJob("ruby", 2005)); + docs.add(makeJob("java", 2006)); + docs.add(makeResume("Frank", "United States")); + w.addDocuments(docs); + + IndexReader r = w.getReader(); + w.close(); + IndexSearcher s = newSearcher(r, false); + + // Create a filter that defines "parent" documents in the index - in this case resumes + BitSetProducer parentsFilter = new QueryBitSetProducer(new TermQuery(new Term("docType", "resume"))); + CheckJoinIndex.check(r, parentsFilter); + + // Define child document criteria (finds an example of relevant work experience) + BooleanQuery.Builder childQuery = new BooleanQuery.Builder(); + childQuery.add(new BooleanClause(new TermQuery(new Term("skill", "java")), Occur.MUST)); + childQuery.add(new BooleanClause(IntPoint.newRangeQuery("year", 2006, 2011), Occur.MUST)); + + // Define parent document criteria (find a resident in the UK) + Query parentQuery = new TermQuery(new Term("country", "United Kingdom")); + + // Wrap the child document query to 'join' any matches + // up to corresponding parent: + ToParentBlockJoinQuery childJoinQuery = new ToParentBlockJoinQuery(childQuery.build(), parentsFilter, ScoreMode.Avg); + + // Combine the parent and nested child queries into a single query for a candidate + BooleanQuery.Builder fullQuery = new BooleanQuery.Builder(); + fullQuery.add(new BooleanClause(parentQuery, Occur.MUST)); + fullQuery.add(new BooleanClause(childJoinQuery, Occur.MUST)); + + ToParentBlockJoinCollector c = new ToParentBlockJoinCollector(Sort.RELEVANCE, 1, true, true); + + //TODO: call CheckHits.checkHitCollector yourself + CheckHits.checkHitCollector(random(), fullQuery.build(), "country", s, new int[] {2}); + + + s.search(fullQuery.build(), c); + + TopGroups results = c.getTopGroups(childJoinQuery, null, 0, 10, 0, true); + assertFalse(Float.isNaN(results.maxScore)); + + //assertEquals(1, results.totalHitCount); + assertEquals(1, results.totalGroupedHitCount); + assertEquals(1, results.groups.length); + + final GroupDocs group = results.groups[0]; + assertEquals(1, group.totalHits); + assertFalse(Float.isNaN(group.score)); + + Document childDoc = s.doc(group.scoreDocs[0].doc); + //System.out.println(" doc=" + group.scoreDocs[0].doc); + assertEquals("java", childDoc.get("skill")); + assertNotNull(group.groupValue); + Document parentDoc = s.doc(group.groupValue); + assertEquals("Lisa", parentDoc.get("name")); + + + //System.out.println("TEST: now test up"); + + // Now join "up" (map parent hits to child docs) instead...: + ToChildBlockJoinQuery parentJoinQuery = new ToChildBlockJoinQuery(parentQuery, parentsFilter); + BooleanQuery.Builder fullChildQuery = new BooleanQuery.Builder(); + fullChildQuery.add(new BooleanClause(parentJoinQuery, Occur.MUST)); + fullChildQuery.add(new BooleanClause(childQuery.build(), Occur.MUST)); + + //System.out.println("FULL: " + fullChildQuery); + TopDocs hits = s.search(fullChildQuery.build(), 10); + assertEquals(1, hits.totalHits); + childDoc = s.doc(hits.scoreDocs[0].doc); + //System.out.println("CHILD = " + childDoc + " docID=" + hits.scoreDocs[0].doc); + assertEquals("java", childDoc.get("skill")); + assertEquals(2007, childDoc.getField("year").numericValue()); + assertEquals("Lisa", getParentDoc(r, parentsFilter, hits.scoreDocs[0].doc).get("name")); + + // Test with filter on child docs: + fullChildQuery.add(new TermQuery(new Term("skill", "foosball")), Occur.FILTER); + assertEquals(0, s.search(fullChildQuery.build(), 1).totalHits); + + r.close(); + dir.close(); + } +} Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/TokenMgrError.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/TokenMgrError.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/TokenMgrError.java (revision ) @@ -144,4 +144,4 @@ this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); } } -/* JavaCC - OriginalChecksum=0c275864a1972d9a01601ab81426872d (do not edit this line) */ +/* JavaCC - OriginalChecksum=f433e1a52b8eadbf12f3fbbbf87fd140 (do not edit this line) */ Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/CharStream.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/CharStream.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/CharStream.java (revision ) @@ -112,4 +112,4 @@ void Done(); } -/* JavaCC - OriginalChecksum=c847dd1920bf7901125a7244125682ad (do not edit this line) */ +/* JavaCC - OriginalChecksum=30b94cad7b10d0d81e3a59a1083939d0 (do not edit this line) */ Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParserTokenManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParserTokenManager.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParserTokenManager.java (revision ) @@ -40,23 +40,23 @@ switch(curChar) { case 40: - return jjStopAtPos(0, 14); - case 41: return jjStopAtPos(0, 15); + case 41: + return jjStopAtPos(0, 16); case 42: - return jjStartNfaWithStates_2(0, 17, 49); + return jjStartNfaWithStates_2(0, 18, 53); case 43: - return jjStartNfaWithStates_2(0, 11, 15); - case 45: return jjStartNfaWithStates_2(0, 12, 15); + case 45: + return jjStartNfaWithStates_2(0, 13, 54); case 58: - return jjStopAtPos(0, 16); + return jjStopAtPos(0, 17); case 91: - return jjStopAtPos(0, 25); + return jjStopAtPos(0, 26); case 94: - return jjStopAtPos(0, 18); + return jjStopAtPos(0, 19); case 123: - return jjStopAtPos(0, 26); + return jjStopAtPos(0, 27); default : return jjMoveNfa_2(0, 0); } @@ -84,7 +84,7 @@ private int jjMoveNfa_2(int startState, int curPos) { int startsAt = 0; - jjnewStateCnt = 49; + jjnewStateCnt = 53; int i = 1; jjstateSet[0] = startState; int kind = 0x7fffffff; @@ -99,25 +99,17 @@ { switch(jjstateSet[--i]) { - case 49: - case 33: - if ((0xfbff7cf8ffffd9ffL & l) == 0L) - break; - if (kind > 23) - kind = 23; - jjCheckNAddTwoStates(33, 34); - break; case 0: if ((0xfbff54f8ffffd9ffL & l) != 0L) { - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); } else if ((0x100002600L & l) != 0L) { - if (kind > 7) - kind = 7; + if (kind > 8) + kind = 8; } else if ((0x280200000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 15; @@ -127,42 +119,71 @@ jjCheckNAddStates(3, 5); if ((0x7bff50f8ffffd9ffL & l) != 0L) { - if (kind > 20) - kind = 20; + if (kind > 21) + kind = 21; jjCheckNAddStates(6, 10); } + else if (curChar == 45) + jjCheckNAdd(42); else if (curChar == 42) { - if (kind > 22) - kind = 22; + if (kind > 23) + kind = 23; } else if (curChar == 33) { - if (kind > 10) - kind = 10; + if (kind > 11) + kind = 11; } - if (curChar == 38) + if ((0x3ff000000000000L & l) != 0L) + { + if (kind > 28) + kind = 28; + jjCheckNAddTwoStates(42, 43); + } + else if (curChar == 38) jjstateSet[jjnewStateCnt++] = 4; break; + case 54: + if ((0x3ff000000000000L & l) != 0L) + { + if (kind > 28) + kind = 28; + jjCheckNAddTwoStates(42, 43); + } + else if ((0x100002600L & l) != 0L) + { + if (kind > 14) + kind = 14; + } + break; + case 53: + case 33: + if ((0xfbff7cf8ffffd9ffL & l) == 0L) + break; + if (kind > 24) + kind = 24; + jjCheckNAddTwoStates(33, 34); + break; case 4: - if (curChar == 38 && kind > 8) - kind = 8; + if (curChar == 38 && kind > 9) + kind = 9; break; case 5: if (curChar == 38) jjstateSet[jjnewStateCnt++] = 4; break; case 13: - if (curChar == 33 && kind > 10) - kind = 10; + if (curChar == 33 && kind > 11) + kind = 11; break; case 14: if ((0x280200000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 15; break; case 15: - if ((0x100002600L & l) != 0L && kind > 13) - kind = 13; + if ((0x100002600L & l) != 0L && kind > 14) + kind = 14; break; case 16: if (curChar == 34) @@ -176,14 +197,14 @@ jjCheckNAddStates(3, 5); break; case 20: - if (curChar == 34 && kind > 19) - kind = 19; + if (curChar == 34 && kind > 20) + kind = 20; break; case 22: if ((0x3ff000000000000L & l) == 0L) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddStates(11, 14); break; case 23: @@ -193,48 +214,48 @@ case 24: if ((0x3ff000000000000L & l) == 0L) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddStates(15, 17); break; case 25: if ((0x7bff78f8ffffd9ffL & l) == 0L) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(25, 26); break; case 27: - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(25, 26); break; case 28: if ((0x7bff78f8ffffd9ffL & l) == 0L) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(28, 29); break; case 30: - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(28, 29); break; case 31: - if (curChar == 42 && kind > 22) - kind = 22; + if (curChar == 42 && kind > 23) + kind = 23; break; case 32: if ((0xfbff54f8ffffd9ffL & l) == 0L) break; - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); break; case 35: - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); break; case 36: @@ -247,33 +268,55 @@ jjCheckNAddStates(0, 2); break; case 40: - if (curChar == 47 && kind > 24) - kind = 24; + if (curChar == 47 && kind > 25) + kind = 25; break; case 41: - if ((0x7bff50f8ffffd9ffL & l) == 0L) + if (curChar == 45) + jjCheckNAdd(42); - break; + break; - if (kind > 20) - kind = 20; - jjCheckNAddStates(6, 10); - break; case 42: - if ((0x7bff78f8ffffd9ffL & l) == 0L) + if ((0x3ff000000000000L & l) == 0L) break; - if (kind > 20) - kind = 20; + if (kind > 28) + kind = 28; jjCheckNAddTwoStates(42, 43); break; + case 43: + if (curChar == 46) + jjCheckNAdd(44); + break; case 44: - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(42, 43); + if ((0x3ff000000000000L & l) == 0L) - break; + break; + if (kind > 28) + kind = 28; + jjCheckNAdd(44); + break; case 45: + if ((0x7bff50f8ffffd9ffL & l) == 0L) + break; + if (kind > 21) + kind = 21; + jjCheckNAddStates(6, 10); + break; + case 46: + if ((0x7bff78f8ffffd9ffL & l) == 0L) + break; + if (kind > 21) + kind = 21; + jjCheckNAddTwoStates(46, 47); + break; + case 48: + if (kind > 21) + kind = 21; + jjCheckNAddTwoStates(46, 47); + break; + case 49: if ((0x7bff78f8ffffd9ffL & l) != 0L) jjCheckNAddStates(18, 20); break; - case 47: + case 51: jjCheckNAddStates(18, 20); break; default : break; @@ -287,35 +330,25 @@ { switch(jjstateSet[--i]) { - case 49: - if ((0x97ffffff87ffffffL & l) != 0L) - { - if (kind > 23) - kind = 23; - jjCheckNAddTwoStates(33, 34); - } - else if (curChar == 92) - jjCheckNAddTwoStates(35, 35); - break; case 0: if ((0x97ffffff87ffffffL & l) != 0L) { - if (kind > 20) - kind = 20; + if (kind > 21) + kind = 21; jjCheckNAddStates(6, 10); } else if (curChar == 92) jjCheckNAddStates(21, 23); else if (curChar == 126) { - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddStates(24, 26); } if ((0x97ffffff87ffffffL & l) != 0L) { - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); } if (curChar == 78) @@ -327,9 +360,19 @@ else if (curChar == 65) jjstateSet[jjnewStateCnt++] = 2; break; + case 53: + if ((0x97ffffff87ffffffL & l) != 0L) + { + if (kind > 24) + kind = 24; + jjCheckNAddTwoStates(33, 34); + } + else if (curChar == 92) + jjCheckNAddTwoStates(35, 35); + break; case 1: - if (curChar == 68 && kind > 8) - kind = 8; + if (curChar == 68 && kind > 9) + kind = 9; break; case 2: if (curChar == 78) @@ -340,24 +383,24 @@ jjstateSet[jjnewStateCnt++] = 2; break; case 6: - if (curChar == 82 && kind > 9) - kind = 9; + if (curChar == 82 && kind > 10) + kind = 10; break; case 7: if (curChar == 79) jjstateSet[jjnewStateCnt++] = 6; break; case 8: - if (curChar == 124 && kind > 9) - kind = 9; + if (curChar == 124 && kind > 10) + kind = 10; break; case 9: if (curChar == 124) jjstateSet[jjnewStateCnt++] = 8; break; case 10: - if (curChar == 84 && kind > 10) - kind = 10; + if (curChar == 84 && kind > 11) + kind = 11; break; case 11: if (curChar == 79) @@ -381,15 +424,15 @@ case 21: if (curChar != 126) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddStates(24, 26); break; case 25: if ((0x97ffffff87ffffffL & l) == 0L) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(25, 26); break; case 26: @@ -397,15 +440,15 @@ jjAddStates(27, 28); break; case 27: - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(25, 26); break; case 28: if ((0x97ffffff87ffffffL & l) == 0L) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(28, 29); break; case 29: @@ -413,22 +456,22 @@ jjAddStates(29, 30); break; case 30: - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(28, 29); break; case 32: if ((0x97ffffff87ffffffL & l) == 0L) break; - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); break; case 33: if ((0x97ffffff87ffffffL & l) == 0L) break; - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); break; case 34: @@ -436,8 +479,8 @@ jjCheckNAddTwoStates(35, 35); break; case 35: - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); break; case 37: @@ -447,41 +490,41 @@ if (curChar == 92) jjstateSet[jjnewStateCnt++] = 38; break; - case 41: + case 45: if ((0x97ffffff87ffffffL & l) == 0L) break; - if (kind > 20) - kind = 20; + if (kind > 21) + kind = 21; jjCheckNAddStates(6, 10); break; - case 42: + case 46: if ((0x97ffffff87ffffffL & l) == 0L) break; - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(42, 43); + if (kind > 21) + kind = 21; + jjCheckNAddTwoStates(46, 47); break; - case 43: + case 47: if (curChar == 92) - jjCheckNAddTwoStates(44, 44); + jjCheckNAddTwoStates(48, 48); break; - case 44: - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(42, 43); + case 48: + if (kind > 21) + kind = 21; + jjCheckNAddTwoStates(46, 47); break; - case 45: + case 49: if ((0x97ffffff87ffffffL & l) != 0L) jjCheckNAddStates(18, 20); break; - case 46: + case 50: if (curChar == 92) - jjCheckNAddTwoStates(47, 47); + jjCheckNAddTwoStates(51, 51); break; - case 47: + case 51: jjCheckNAddStates(18, 20); break; - case 48: + case 52: if (curChar == 92) jjCheckNAddStates(21, 23); break; @@ -500,37 +543,38 @@ { switch(jjstateSet[--i]) { - case 49: - case 33: - if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) - break; - if (kind > 23) - kind = 23; - jjCheckNAddTwoStates(33, 34); - break; case 0: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) { - if (kind > 7) - kind = 7; + if (kind > 8) + kind = 8; } if (jjCanMove_2(hiByte, i1, i2, l1, l2)) { - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); } if (jjCanMove_2(hiByte, i1, i2, l1, l2)) { - if (kind > 20) - kind = 20; + if (kind > 21) + kind = 21; jjCheckNAddStates(6, 10); } break; + case 54: case 15: - if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 13) - kind = 13; + if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 14) + kind = 14; break; + case 53: + case 33: + if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) + break; + if (kind > 24) + kind = 24; + jjCheckNAddTwoStates(33, 34); + break; case 17: case 19: if (jjCanMove_1(hiByte, i1, i2, l1, l2)) @@ -539,75 +583,75 @@ case 25: if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(25, 26); break; case 27: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(25, 26); break; case 28: if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(28, 29); break; case 30: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; - if (kind > 21) - kind = 21; + if (kind > 22) + kind = 22; jjCheckNAddTwoStates(28, 29); break; case 32: if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) break; - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); break; case 35: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; - if (kind > 23) - kind = 23; + if (kind > 24) + kind = 24; jjCheckNAddTwoStates(33, 34); break; case 37: if (jjCanMove_1(hiByte, i1, i2, l1, l2)) jjAddStates(0, 2); break; - case 41: + case 45: if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) break; - if (kind > 20) - kind = 20; + if (kind > 21) + kind = 21; jjCheckNAddStates(6, 10); break; - case 42: + case 46: if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) break; - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(42, 43); + if (kind > 21) + kind = 21; + jjCheckNAddTwoStates(46, 47); break; - case 44: + case 48: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(42, 43); + if (kind > 21) + kind = 21; + jjCheckNAddTwoStates(46, 47); break; - case 45: + case 49: if (jjCanMove_2(hiByte, i1, i2, l1, l2)) jjCheckNAddStates(18, 20); break; - case 47: + case 51: if (jjCanMove_1(hiByte, i1, i2, l1, l2)) jjCheckNAddStates(18, 20); break; @@ -622,7 +666,7 @@ kind = 0x7fffffff; } ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 49 - (jjnewStateCnt = startsAt))) + if ((i = jjnewStateCnt) == (startsAt = 53 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } @@ -653,8 +697,8 @@ case 0: if ((0x3ff000000000000L & l) == 0L) break; - if (kind > 27) - kind = 27; + if (kind > 29) + kind = 29; jjAddStates(31, 32); break; case 1: @@ -664,8 +708,8 @@ case 2: if ((0x3ff000000000000L & l) == 0L) break; - if (kind > 27) - kind = 27; + if (kind > 29) + kind = 29; jjCheckNAdd(2); break; default : break; @@ -716,9 +760,9 @@ switch (pos) { case 0: - if ((active0 & 0x10000000L) != 0L) + if ((active0 & 0x40000000L) != 0L) { - jjmatchedKind = 32; + jjmatchedKind = 34; return 6; } return -1; @@ -735,11 +779,11 @@ switch(curChar) { case 84: - return jjMoveStringLiteralDfa1_1(0x10000000L); + return jjMoveStringLiteralDfa1_1(0x40000000L); case 93: - return jjStopAtPos(0, 29); + return jjStopAtPos(0, 31); case 125: - return jjStopAtPos(0, 30); + return jjStopAtPos(0, 32); default : return jjMoveNfa_1(0, 0); } @@ -754,8 +798,8 @@ switch(curChar) { case 79: - if ((active0 & 0x10000000L) != 0L) - return jjStartNfaWithStates_1(1, 28, 6); + if ((active0 & 0x40000000L) != 0L) + return jjStartNfaWithStates_1(1, 30, 6); break; default : break; @@ -791,14 +835,14 @@ case 0: if ((0xfffffffeffffffffL & l) != 0L) { - if (kind > 32) - kind = 32; + if (kind > 34) + kind = 34; jjCheckNAdd(6); } if ((0x100002600L & l) != 0L) { - if (kind > 7) - kind = 7; + if (kind > 8) + kind = 8; } else if (curChar == 34) jjCheckNAddTwoStates(2, 4); @@ -816,14 +860,14 @@ jjCheckNAddStates(33, 35); break; case 5: - if (curChar == 34 && kind > 31) - kind = 31; + if (curChar == 34 && kind > 33) + kind = 33; break; case 6: if ((0xfffffffeffffffffL & l) == 0L) break; - if (kind > 32) - kind = 32; + if (kind > 34) + kind = 34; jjCheckNAdd(6); break; default : break; @@ -841,8 +885,8 @@ case 6: if ((0xdfffffffdfffffffL & l) == 0L) break; - if (kind > 32) - kind = 32; + if (kind > 34) + kind = 34; jjCheckNAdd(6); break; case 2: @@ -870,13 +914,13 @@ case 0: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) { - if (kind > 7) - kind = 7; + if (kind > 8) + kind = 8; } if (jjCanMove_1(hiByte, i1, i2, l1, l2)) { - if (kind > 32) - kind = 32; + if (kind > 34) + kind = 34; jjCheckNAdd(6); } break; @@ -887,8 +931,8 @@ case 6: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; - if (kind > 32) - kind = 32; + if (kind > 34) + kind = 34; jjCheckNAdd(6); break; default : break; @@ -909,8 +953,8 @@ } } static final int[] jjnextStates = { - 37, 39, 40, 17, 18, 20, 42, 45, 31, 46, 43, 22, 23, 25, 26, 24, - 25, 26, 45, 31, 46, 44, 47, 35, 22, 28, 29, 27, 27, 30, 30, 0, + 37, 39, 40, 17, 18, 20, 46, 49, 31, 50, 47, 22, 23, 25, 26, 24, + 25, 26, 49, 31, 50, 48, 51, 35, 22, 28, 29, 27, 27, 30, 30, 0, 1, 2, 4, 5, }; private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2) @@ -952,9 +996,9 @@ /** Token literal values. */ public static final String[] jjstrLiteralImages = { -"", null, null, null, null, null, null, null, null, null, null, "\53", "\55", -null, "\50", "\51", "\72", "\52", "\136", null, null, null, null, null, null, -"\133", "\173", null, "\124\117", "\135", "\175", null, null, }; +"", null, null, null, null, null, null, null, null, null, null, null, "\53", +"\55", null, "\50", "\51", "\72", "\52", "\136", null, null, null, null, null, null, +"\133", "\173", null, null, "\124\117", "\135", "\175", null, null, }; /** Lexer state names. */ public static final String[] lexStateNames = { @@ -965,18 +1009,18 @@ /** Lex State array. */ public static final int[] jjnewLexState = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, - 1, 1, 2, -1, 2, 2, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, + -1, 1, 1, -1, 2, -1, 2, 2, -1, -1, }; static final long[] jjtoToken = { - 0x1ffffff01L, + 0x7fffffe01L, }; static final long[] jjtoSkip = { - 0x80L, + 0x100L, }; protected CharStream input_stream; -private final int[] jjrounds = new int[49]; -private final int[] jjstateSet = new int[98]; +private final int[] jjrounds = new int[53]; +private final int[] jjstateSet = new int[106]; protected char curChar; /** Constructor. */ public QueryParserTokenManager(CharStream stream){ @@ -1001,7 +1045,7 @@ { int i; jjround = 0x80000001; - for (i = 49; i-- > 0;) + for (i = 53; i-- > 0;) jjrounds[i] = 0x80000000; } Index: lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java (revision ) @@ -17,8 +17,10 @@ package org.apache.lucene.search.join; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Set; @@ -184,7 +186,7 @@ public Explanation explain(LeafReaderContext context, int doc) throws IOException { BlockJoinScorer scorer = (BlockJoinScorer) scorer(context); if (scorer != null && scorer.iterator().advance(doc) == doc) { - return scorer.explain(context.docBase); + return scorer.explain(context, childWeight); } return Explanation.noMatch("Not a match"); } @@ -436,10 +438,19 @@ return parentFreq; } - public Explanation explain(int docBase) throws IOException { - int start = docBase + prevParentDoc + 1; // +1 b/c prevParentDoc is previous parent doc - int end = docBase + parentDoc - 1; // -1 b/c parentDoc is parent doc - return Explanation.match(score(), String.format(Locale.ROOT, "Score based on child doc range from %d to %d", start, end) + public Explanation explain(LeafReaderContext context, Weight childWeight) throws IOException { + int start = context.docBase + prevParentDoc + 1; // +1 b/c prevParentDoc is previous parent doc + int end = context.docBase + parentDoc - 1; // -1 b/c parentDoc is parent doc + + List explanations = new ArrayList<>(); + for (int childDoc = start; childDoc <= end; childDoc++) { + Explanation childExpl = childWeight.explain(context, childDoc); + if (childExpl.isMatch()) { + explanations.add(childExpl); + } + } + + return Explanation.match(score(), String.format(Locale.ROOT, "Score based on child doc range from %d to %d", start, end), explanations ); } Index: lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestQueryParser.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestQueryParser.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestQueryParser.java (revision ) @@ -33,6 +33,7 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.MultiPhraseQuery; +import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.SynonymQuery; import org.apache.lucene.search.TermQuery; @@ -62,7 +63,31 @@ throw new ParseException("Wildcard queries not allowed"); } } - + + @SuppressWarnings("unchecked") + private static Q assertQueryType(Query query, Class queryClass) { + assertTrue(String.format("query was a %s but should be %s", + query.getClass().getSimpleName(), + queryClass.getSimpleName()), + queryClass.isAssignableFrom(query.getClass())); + return (Q) query; + } + + private static void assertTermQuery(Query query, String expectedFieldName, String expectedTermText) { + TermQuery tq = assertQueryType(query, TermQuery.class); + assertTerm(tq.getTerm(), expectedFieldName, expectedTermText); + } + + private static void assertTerm(Term term, String expectedField, String expectedText) { + assertEquals(expectedField, term.field()); + assertEquals(expectedText, term.text()); + } + + private static void assertBooleanQuery(BooleanClause clause, BooleanClause.Occur expectedOccur, String expectedFieldName, String expectedTermText) { + assertEquals(expectedOccur, clause.getOccur()); + assertTermQuery(clause.getQuery(), expectedFieldName, expectedTermText); + } + public QueryParser getParser(Analyzer a) throws Exception { if (a == null) a = new MockAnalyzer(random(), MockTokenizer.SIMPLE, true); QueryParser qp = new QueryParser(getDefaultField(), a); @@ -482,5 +507,36 @@ expectThrows(TooComplexToDeterminizeException.class, () -> { qp.parse("a*aaaaaaa"); }); + } + + /** for LUCENE-2916, ensure that unquoted negative numbers work in term text */ + public void testUnquotedNegativeNumber() throws Exception { + String defaultField = "field"; + QueryParser qp = new QueryParser(defaultField, new MockAnalyzer(random())); + + assertTermQuery(qp.parse("field1:11"), "field1", "11"); + assertTermQuery(qp.parse("field2:-12"), "field2", "-12"); + assertTermQuery(qp.parse("field3:12.1"), "field3", "12.1"); + assertTermQuery(qp.parse("field4:-13.2"), "field4", "-13.2"); + + expectThrows(ParseException.class, () -> { + // this still shouldn't be valid, since at least one digit on either side of a decimal is required + qp.parse("field5:-.3"); + }); + + BooleanQuery bq1 = assertQueryType(qp.parse("-nothing field6:-13.2 +everything"), BooleanQuery.class); + assertBooleanQuery(bq1.clauses().get(0), BooleanClause.Occur.MUST_NOT, defaultField, "nothing"); + assertBooleanQuery(bq1.clauses().get(1), BooleanClause.Occur.SHOULD, "field6", "-13.2"); + assertBooleanQuery(bq1.clauses().get(2), BooleanClause.Occur.MUST, defaultField, "everything"); + + BooleanQuery bq2 = assertQueryType(qp.parse("-field7:-37 -\"Some phrase\" +grouped:(-17 -32.1 +10)"), BooleanQuery.class); + assertBooleanQuery(bq2.clauses().get(0), BooleanClause.Occur.MUST_NOT, "field7", "-37"); + PhraseQuery bq2SubQ1 = assertQueryType(bq2.clauses().get(1).getQuery(), PhraseQuery.class); + assertTerm(bq2SubQ1.getTerms()[0], defaultField, "some"); + assertTerm(bq2SubQ1.getTerms()[1], defaultField, "phrase"); + BooleanQuery bq2SubQ2 = (BooleanQuery) bq2.clauses().get(2).getQuery(); + assertBooleanQuery(bq2SubQ2.clauses().get(0), BooleanClause.Occur.SHOULD, "grouped", "-17"); + assertBooleanQuery(bq2SubQ2.clauses().get(1), BooleanClause.Occur.SHOULD, "grouped", "-32.1"); + assertBooleanQuery(bq2SubQ2.clauses().get(2), BooleanClause.Occur.MUST, "grouped", "10"); } } Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParserConstants.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParserConstants.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParserConstants.java (revision ) @@ -23,55 +23,59 @@ /** RegularExpression Id. */ int _QUOTED_CHAR = 6; /** RegularExpression Id. */ - int AND = 8; + int _NUMBER = 7; /** RegularExpression Id. */ - int OR = 9; + int AND = 9; /** RegularExpression Id. */ - int NOT = 10; + int OR = 10; /** RegularExpression Id. */ - int PLUS = 11; + int NOT = 11; /** RegularExpression Id. */ - int MINUS = 12; + int PLUS = 12; /** RegularExpression Id. */ - int BAREOPER = 13; + int MINUS = 13; /** RegularExpression Id. */ - int LPAREN = 14; + int BAREOPER = 14; /** RegularExpression Id. */ - int RPAREN = 15; + int LPAREN = 15; /** RegularExpression Id. */ - int COLON = 16; + int RPAREN = 16; /** RegularExpression Id. */ - int STAR = 17; + int COLON = 17; /** RegularExpression Id. */ - int CARAT = 18; + int STAR = 18; /** RegularExpression Id. */ - int QUOTED = 19; + int CARAT = 19; /** RegularExpression Id. */ - int TERM = 20; + int QUOTED = 20; /** RegularExpression Id. */ - int FUZZY_SLOP = 21; + int TERM = 21; /** RegularExpression Id. */ - int PREFIXTERM = 22; + int FUZZY_SLOP = 22; /** RegularExpression Id. */ - int WILDTERM = 23; + int PREFIXTERM = 23; /** RegularExpression Id. */ - int REGEXPTERM = 24; + int WILDTERM = 24; /** RegularExpression Id. */ - int RANGEIN_START = 25; + int REGEXPTERM = 25; /** RegularExpression Id. */ - int RANGEEX_START = 26; + int RANGEIN_START = 26; /** RegularExpression Id. */ - int NUMBER = 27; + int RANGEEX_START = 27; /** RegularExpression Id. */ - int RANGE_TO = 28; + int MAYBE_NEGATIVE_NUMBER = 28; /** RegularExpression Id. */ - int RANGEIN_END = 29; + int NUMBER = 29; /** RegularExpression Id. */ - int RANGEEX_END = 30; + int RANGE_TO = 30; /** RegularExpression Id. */ - int RANGE_QUOTED = 31; + int RANGEIN_END = 31; /** RegularExpression Id. */ - int RANGE_GOOP = 32; + int RANGEEX_END = 32; + /** RegularExpression Id. */ + int RANGE_QUOTED = 33; + /** RegularExpression Id. */ + int RANGE_GOOP = 34; /** Lexical state. */ int Boost = 0; @@ -89,7 +93,8 @@ "<_TERM_CHAR>", "<_WHITESPACE>", "<_QUOTED_CHAR>", - "", + "<_NUMBER>", + "", "", "", "", @@ -109,6 +114,7 @@ "", "\"[\"", "\"{\"", + "", "", "\"TO\"", "\"]\"", Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/Token.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/Token.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/Token.java (revision ) @@ -128,4 +128,4 @@ } } -/* JavaCC - OriginalChecksum=c1e1418b35aa9e47ef8dc98b87423d70 (do not edit this line) */ +/* JavaCC - OriginalChecksum=405bb5d2fcd84e94ac1c8f0b12c1f914 (do not edit this line) */ Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/ParseException.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/ParseException.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/ParseException.java (revision ) @@ -184,4 +184,4 @@ } } -/* JavaCC - OriginalChecksum=61602edcb3a15810cbc58f5593eba40d (do not edit this line) */ +/* JavaCC - OriginalChecksum=b187d97d5bb75c3fc63d642c1c26ac6e (do not edit this line) */ Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.java (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.java (revision ) @@ -190,7 +190,7 @@ case REGEXPTERM: case RANGEIN_START: case RANGEEX_START: - case NUMBER: + case MAYBE_NEGATIVE_NUMBER: ; break; default: @@ -243,7 +243,7 @@ case REGEXPTERM: case RANGEIN_START: case RANGEEX_START: - case NUMBER: + case MAYBE_NEGATIVE_NUMBER: q = Term(field); break; case LPAREN: @@ -285,7 +285,7 @@ case PREFIXTERM: case WILDTERM: case REGEXPTERM: - case NUMBER: + case MAYBE_NEGATIVE_NUMBER: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TERM: term = jj_consume_token(TERM); @@ -306,8 +306,8 @@ term = jj_consume_token(REGEXPTERM); regexp=true; break; - case NUMBER: - term = jj_consume_token(NUMBER); + case MAYBE_NEGATIVE_NUMBER: + term = jj_consume_token(MAYBE_NEGATIVE_NUMBER); break; case BAREOPER: term = jj_consume_token(BAREOPER); @@ -467,12 +467,6 @@ 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; @@ -489,6 +483,12 @@ 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. */ @@ -507,10 +507,10 @@ jj_la1_init_1(); } private static void jj_la1_init_0() { - jj_la1_0 = new int[] {0x300,0x300,0x1c00,0x1c00,0xfda7f00,0x120000,0x40000,0xfda6000,0x9d22000,0x200000,0x200000,0x40000,0x6000000,0x80000000,0x10000000,0x80000000,0x60000000,0x40000,0x200000,0x40000,0xfda2000,}; + jj_la1_0 = new int[] {0x600,0x600,0x3800,0x3800,0x1fb4fe00,0x240000,0x80000,0x1fb4c000,0x13a44000,0x400000,0x400000,0x80000,0xc000000,0x0,0x40000000,0x0,0x80000000,0x80000,0x400000,0x80000,0x1fb44000,}; } private static void jj_la1_init_1() { - jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,}; + jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x6,0x1,0x0,0x0,0x0,0x0,}; } final private JJCalls[] jj_2_rtns = new JJCalls[1]; private boolean jj_rescan = false; @@ -664,7 +664,7 @@ /** Generate ParseException. */ public ParseException generateParseException() { jj_expentries.clear(); - boolean[] la1tokens = new boolean[33]; + boolean[] la1tokens = new boolean[35]; if (jj_kind >= 0) { la1tokens[jj_kind] = true; jj_kind = -1; @@ -681,7 +681,7 @@ } } } - for (int i = 0; i < 33; i++) { + for (int i = 0; i < 35; i++) { if (la1tokens[i]) { jj_expentry = new int[1]; jj_expentry[0] = i; Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.jj IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.jj (revision 645889f6b296fd445b1b104ad112b3b9beea8f9d) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/classic/QueryParser.jj (revision ) @@ -132,6 +132,7 @@ | <#_TERM_CHAR: ( <_TERM_START_CHAR> | <_ESCAPED_CHAR> | "-" | "+" ) > | <#_WHITESPACE: ( " " | "\t" | "\n" | "\r" | "\u3000") > | <#_QUOTED_CHAR: ( ~[ "\"", "\\" ] | <_ESCAPED_CHAR> ) > +| <#_NUMBER: (<_NUM_CHAR>)+ ( "." (<_NUM_CHAR>)+ )? > } SKIP : { @@ -158,10 +159,11 @@ | | : Range | : Range +| )? <_NUMBER> > } TOKEN : { -)+ ( "." (<_NUM_CHAR>)+ )? > : DEFAULT + > : DEFAULT } TOKEN : { @@ -276,7 +278,7 @@ | term= { prefix=true; } | term= { wildcard=true; } | term= { regexp=true; } - | term= + | term= | term= { term.image = term.image.substring(0,1); } ) [ fuzzySlop= { fuzzy=true; } ]