Index: lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java (revision 1024236) +++ lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java (working copy) @@ -22,6 +22,8 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermsEnum; +import org.apache.lucene.util.Attribute; +import org.apache.lucene.util.AttributeImpl; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.Bits; import org.apache.lucene.util.BytesRef; @@ -34,6 +36,7 @@ import org.apache.lucene.util.automaton.LevenshteinAutomata; import java.io.IOException; +import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -53,6 +56,7 @@ attributes().addAttribute(MultiTermQuery.BoostAttribute.class); private final MultiTermQuery.MaxNonCompetitiveBoostAttribute maxBoostAtt; + private final LevenshteinAutomataAttribute dfaAtt; private float bottom; private BytesRef bottomTerm; @@ -123,6 +127,7 @@ this.scale_factor = 1.0f / (1.0f - this.minSimilarity); this.maxBoostAtt = atts.addAttribute(MultiTermQuery.MaxNonCompetitiveBoostAttribute.class); + this.dfaAtt = atts.addAttribute(LevenshteinAutomataAttribute.class); bottom = maxBoostAtt.getMaxNonCompetitiveBoost(); bottomTerm = maxBoostAtt.getCompetitiveTerm(); bottomChanged(null, true); @@ -150,16 +155,20 @@ LevenshteinAutomata builder = new LevenshteinAutomata(UnicodeUtil.newString(termText, realPrefixLength, termText.length - realPrefixLength)); - final ByteRunAutomaton[] ra = new ByteRunAutomaton[maxDistance + 1]; - for (int i = 0; i <= maxDistance; i++) { - Automaton a = builder.toAutomaton(i); - // constant prefix - if (realPrefixLength > 0) { - Automaton prefix = BasicAutomata.makeString( + ByteRunAutomaton[] ra = dfaAtt.getAutomata(); + if (ra == null || ra.length <= maxDistance) { + ra = new ByteRunAutomaton[maxDistance + 1]; + for (int i = 0; i <= maxDistance; i++) { + Automaton a = builder.toAutomaton(i); + // constant prefix + if (realPrefixLength > 0) { + Automaton prefix = BasicAutomata.makeString( UnicodeUtil.newString(termText, 0, realPrefixLength)); - a = BasicOperations.concatenate(prefix, a); + a = BasicOperations.concatenate(prefix, a); + } + ra[i] = new ByteRunAutomaton(a); } - ra[i] = new ByteRunAutomaton(a); + dfaAtt.setAutomata(ra); } runAutomata = Arrays.asList(ra); } @@ -545,4 +554,51 @@ public float getScaleFactor() { return scale_factor; } + + /** @lucene.internal */ + public static interface LevenshteinAutomataAttribute extends Attribute { + public ByteRunAutomaton[] getAutomata(); + public void setAutomata(ByteRunAutomaton[] automata); + } + + /** @lucene.internal */ + public static class LevenshteinAutomataAttributeImpl extends AttributeImpl implements LevenshteinAutomataAttribute, Cloneable, Serializable { + private ByteRunAutomaton[] automata; + + @Override + public ByteRunAutomaton[] getAutomata() { + return automata; + } + + @Override + public void setAutomata(ByteRunAutomaton[] automata) { + this.automata = automata; + } + + @Override + public void clear() { + this.automata = null; + } + + @Override + public int hashCode() { + return 0; // nocommit + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof LevenshteinAutomataAttribute)) return false; + return Arrays.equals(automata, ((LevenshteinAutomataAttribute)other).getAutomata()); + } + + @Override + public void copyTo(AttributeImpl target) { + LevenshteinAutomataAttribute att = (LevenshteinAutomataAttribute) target; + att.setAutomata(automata); + } + } }