Index: lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java =================================================================== --- lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java (revision 1024441) +++ 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,7 +36,7 @@ import org.apache.lucene.util.automaton.LevenshteinAutomata; import java.io.IOException; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -53,6 +55,7 @@ attributes().addAttribute(MultiTermQuery.BoostAttribute.class); private final MultiTermQuery.MaxNonCompetitiveBoostAttribute maxBoostAtt; + private final LevenshteinAutomataAttribute dfaAtt; private float bottom; private BytesRef bottomTerm; @@ -67,8 +70,6 @@ private int maxEdits; private final boolean raw; - private List runAutomata; - private final IndexReader reader; private final Term term; private final int termText[]; @@ -123,6 +124,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); @@ -134,35 +136,38 @@ */ private TermsEnum getAutomatonEnum(int editDistance, BytesRef lastTerm) throws IOException { - initAutomata(editDistance); + final List runAutomata = initAutomata(editDistance); if (runAutomata != null && editDistance < runAutomata.size()) { return new AutomatonFuzzyTermsEnum(runAutomata.subList(0, editDistance + 1) - .toArray(new ByteRunAutomaton[0]), lastTerm); + .toArray(new ByteRunAutomaton[editDistance + 1]), lastTerm); } else { return null; } } /** initialize levenshtein DFAs up to maxDistance, if possible */ - private void initAutomata(int maxDistance) { - if (runAutomata == null && + private List initAutomata(int maxDistance) { + List runAutomata = dfaAtt.getAutomata(); + if ((runAutomata == null || runAutomata.size() <= maxDistance) && maxDistance <= LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE) { 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++) { + if (runAutomata == null) + runAutomata = new ArrayList(maxDistance + 1); + for (int i = runAutomata.size(); i <= maxDistance; i++) { Automaton a = builder.toAutomaton(i); // constant prefix if (realPrefixLength > 0) { Automaton prefix = BasicAutomata.makeString( - UnicodeUtil.newString(termText, 0, realPrefixLength)); + UnicodeUtil.newString(termText, 0, realPrefixLength)); a = BasicOperations.concatenate(prefix, a); } - ra[i] = new ByteRunAutomaton(a); + runAutomata.add(new ByteRunAutomaton(a)); } - runAutomata = Arrays.asList(ra); + dfaAtt.setAutomata(runAutomata); } + return runAutomata; } /** swap in a new actual enum to proxy to */ @@ -545,4 +550,50 @@ public float getScaleFactor() { return scale_factor; } + + /** @lucene.internal */ + public static interface LevenshteinAutomataAttribute extends Attribute { + public List getAutomata(); + public void setAutomata(List automata); + } + + /** @lucene.internal */ + public static class LevenshteinAutomataAttributeImpl extends AttributeImpl implements LevenshteinAutomataAttribute { + private List automata; + + public List getAutomata() { + return automata; + } + + public void setAutomata(List automata) { + this.automata = automata; + } + + @Override + public void clear() { + this.automata = null; + } + + @Override + public int hashCode() { + return (automata == null) ? 0 : automata.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof LevenshteinAutomataAttributeImpl)) return false; + final LevenshteinAutomataAttributeImpl o = (LevenshteinAutomataAttributeImpl) other; + return automata == null ? o.automata == null : automata.equals(o.automata); + } + + @Override + public void copyTo(AttributeImpl target) { + LevenshteinAutomataAttribute att = (LevenshteinAutomataAttribute) target; + att.setAutomata(automata); + } + } }