Index: lucene/CHANGES.txt =================================================================== --- lucene/CHANGES.txt (revision 1578078) +++ lucene/CHANGES.txt (working copy) @@ -97,6 +97,9 @@ * LUCENE-5493: SortingMergePolicy, and EarlyTerminatingSortingCollector support arbitrary Sort specifications. (Robert Muir, Mike McCandless, Adrien Grand) + +* LUCENE-3758: Allow the ComplexPhraseQueryParser to search order or + un-order proximity queries. (Ahmet Arslan via Erick Erickson) API Changes Index: lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java =================================================================== --- lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java (revision 1578078) +++ lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java (working copy) @@ -66,6 +66,18 @@ private boolean isPass2ResolvingPhrases; + private boolean inOrder = true; + + /** + * When inOrder is true, the search terms must + * exists in the documents as the same order as in query. + * + * @param inOrder parameter to choose between ordered or un-ordered proximity search + */ + public void setInOrder(final boolean inOrder) { + this.inOrder = inOrder; + } + private ComplexPhraseQuery currentPhraseQuery = null; public ComplexPhraseQueryParser(Version matchVersion, String f, Analyzer a) { @@ -74,7 +86,7 @@ @Override protected Query getFieldQuery(String field, String queryText, int slop) { - ComplexPhraseQuery cpq = new ComplexPhraseQuery(field, queryText, slop); + ComplexPhraseQuery cpq = new ComplexPhraseQuery(field, queryText, slop, inOrder); complexPhrases.add(cpq); // add to list of phrases to be parsed once // we // are through with this pass @@ -202,14 +214,17 @@ int slopFactor; + private final boolean inOrder; + private Query contents; public ComplexPhraseQuery(String field, String phrasedQueryStringContents, - int slopFactor) { + int slopFactor, boolean inOrder) { super(); this.field = field; this.phrasedQueryStringContents = phrasedQueryStringContents; this.slopFactor = slopFactor; + this.inOrder = inOrder; } // Called by ComplexPhraseQueryParser for each phrase after the main @@ -280,7 +295,7 @@ } if (numNegatives == 0) { // The simple case - no negative elements in phrase - return new SpanNearQuery(allSpanClauses, slopFactor, true); + return new SpanNearQuery(allSpanClauses, slopFactor, inOrder); } // Complex case - we have mixed positives and negatives in the // sequence. @@ -302,11 +317,11 @@ // need to increase slop factor based on gaps introduced by // negatives include = new SpanNearQuery(includeClauses, slopFactor + numNegatives, - true); + inOrder); } // Use sequence of positive and negative values as the exclude. SpanNearQuery exclude = new SpanNearQuery(allSpanClauses, slopFactor, - true); + inOrder); SpanNotQuery snot = new SpanNotQuery(include, exclude); return snot; } Index: lucene/queryparser/src/test/org/apache/lucene/queryparser/complexPhrase/TestComplexPhraseQuery.java =================================================================== --- lucene/queryparser/src/test/org/apache/lucene/queryparser/complexPhrase/TestComplexPhraseQuery.java (revision 1578078) +++ lucene/queryparser/src/test/org/apache/lucene/queryparser/complexPhrase/TestComplexPhraseQuery.java (working copy) @@ -49,6 +49,8 @@ String defaultFieldName = "name"; + boolean inOrder = true; + public void testComplexPhrases() throws Exception { checkMatches("\"john smith\"", "1"); // Simple multi-term still works checkMatches("\"j* smyth~\"", "1,2"); // wildcards and fuzzies are OK in @@ -72,8 +74,20 @@ checkBadQuery("\"jo* \"smith\" \""); // phrases inside phrases is bad } + + public void testUnOrderedProximitySearches() throws Exception { + + inOrder = true; + checkMatches("\"smith jo*\"~2", ""); // ordered proximity produces empty set + + inOrder = false; + checkMatches("\"smith jo*\"~2", "1,2,3"); // un-ordered proximity + + } + private void checkBadQuery(String qString) { - QueryParser qp = new ComplexPhraseQueryParser(TEST_VERSION_CURRENT, defaultFieldName, analyzer); + ComplexPhraseQueryParser qp = new ComplexPhraseQueryParser(TEST_VERSION_CURRENT, defaultFieldName, analyzer); + qp.setInOrder(inOrder); Throwable expected = null; try { qp.parse(qString); @@ -86,7 +100,8 @@ private void checkMatches(String qString, String expectedVals) throws Exception { - QueryParser qp = new ComplexPhraseQueryParser(TEST_VERSION_CURRENT, defaultFieldName, analyzer); + ComplexPhraseQueryParser qp = new ComplexPhraseQueryParser(TEST_VERSION_CURRENT, defaultFieldName, analyzer); + qp.setInOrder(inOrder); qp.setFuzzyPrefixLength(1); // usually a good idea Query q = qp.parse(qString);