Index: lucene/src/java/org/apache/lucene/search/PhraseQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/PhraseQuery.java (revision 1167477) +++ lucene/src/java/org/apache/lucene/search/PhraseQuery.java (working copy) @@ -18,6 +18,7 @@ */ import java.io.IOException; +import java.util.Iterator; import java.util.Set; import java.util.ArrayList; @@ -47,6 +48,7 @@ private ArrayList positions = new ArrayList(4); private int maxPosition = 0; private int slop = 0; + private boolean optimized = false; /** Constructs an empty phrase query. */ public PhraseQuery() {} @@ -116,7 +118,60 @@ result[i] = positions.get(i).intValue(); return result; } + + /** + * Returns whether n-gram optimizer has been called or not + * @return true if n-gram optimizer has been called, otherwise false + */ + public boolean optimized(){ + return optimized; + } + + /** + * Executes n-gram optimizer. This should be called after constructing + * ({@link #add(Term)}ing or {@link #add(Term, int)}ing) this {@link PhraseQuery}. + * To know n of n-gram, refers to the first term. + */ + public void optimizeForNgram(){ + if(terms.size() == 0) return; + optimizeForNgram(terms.get(0).text().length()); + } + + /** + * Executes n-gram optimizer. This should be called after constructing + * ({@link #add(Term)}ing or {@link #add(Term, int)}ing) this {@link PhraseQuery}. + * + * @param n gram size (N of N-gram) + */ + public void optimizeForNgram(int n){ + if(optimized || slop != 0) return; + optimized = true; + + // check whether optimizable or not + if(n < 2 || // non-overlap n-gram cannot be optimized + terms.size() < 3) return; // too short to optimize + + int prevPosition = positions.get(0).intValue(); + for(int i = 1; i < positions.size(); i++){ + int pos = positions.get(i).intValue(); + if(prevPosition + 1 != pos) return; + prevPosition = pos; + } + int pos = 0; + final int lastPos = terms.size() - 1; + Iterator pi = positions.iterator(); + for(Iterator ti = terms.iterator(); ti.hasNext() && pi.hasNext();){ + pi.next(); + ti.next(); + if(pos % n != 0 && pos < lastPos){ + pi.remove(); + ti.remove(); + } + pos++; + } + } + @Override public Query rewrite(IndexReader reader) throws IOException { if (terms.size() == 1) {