diff --git a/src/main/java/org/apache/lucene/russian/morphology/HeuristicBuilder.java b/src/main/java/org/apache/lucene/russian/morphology/HeuristicBuilder.java
index bbe8e32..542a5a9 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/HeuristicBuilder.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/HeuristicBuilder.java
@@ -16,20 +16,15 @@
 
 package org.apache.lucene.russian.morphology;
 
-import org.apache.lucene.russian.morphology.dictonary.DictonaryReader;
-import org.apache.lucene.russian.morphology.dictonary.FrequentyReader;
-import org.apache.lucene.russian.morphology.dictonary.GrammaReader;
-import org.apache.lucene.russian.morphology.dictonary.IgnoredFormReader;
+import org.apache.lucene.russian.morphology.dictonary.*;
 import org.apache.lucene.russian.morphology.heuristic.HeuristicBySuffixLegth;
 import org.apache.lucene.russian.morphology.heuristic.StatiticsCollectors;
 import org.apache.lucene.russian.morphology.heuristic.SuffixCounter;
-import org.apache.lucene.russian.morphology.heuristic.SuffixHeuristic;
+import org.apache.lucene.russian.morphology.heuristic.SimpleSuffixHeuristic;
 
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Set;
-import java.util.TreeMap;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
 
 
 public class HeuristicBuilder {
@@ -57,47 +52,28 @@ public class HeuristicBuilder {
             heuristic.addHeuristic(((SuffixCounter) objects[i]).getSuffixHeuristic());
         }
 
-        TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
+        final Map<Long,Set<SimpleSuffixHeuristic>> map = heuristic.getUnkowns();
 
-        int ct = 0;
-        for (Set<SuffixHeuristic> s : heuristic.getHeuristics().values()) {
-            Integer d = map.get(s.size());
-            map.put(s.size(), 1 + (d == null ? 0 : d));
-            if (s.size() == 1) {
-                ct++;
-                continue;
-            }
-            SuffixHeuristic heuristic1 = s.iterator().next();
-            Integer sufixSize = heuristic1.getActualSuffixLength();
-            String normalSuffix = heuristic1.getNormalFromSuffix();
-            if (heuristic1.getFormSuffix().length() < 6) {
-                ct++;
-                continue;
-            }
-            Boolean flag = true;
-            if (sufixSize > 3) continue;
-            for (SuffixHeuristic sh : s) {
-                flag = flag && (sufixSize.equals(sh.getActualSuffixLength()))
-                        && (normalSuffix.equals(sh.getNormalFromSuffix()));
-            }
-            if (flag) {
-                System.out.println(s);
-                ct++;
-            }
-            //HashSet<String> integers = new HashSet<String>();
-//            for(SuffixHeuristic sh:s){
-//                integers.add(sh.getMorphInfoCode());
-//            }
-//            if(s.size() == integers.size()){
-//                ct++;
-//            }else{
-//               if(s.size() == 2) System.out.println(s);
-//            }
-        }
-        System.out.println(objects.length);
-        System.out.println(heuristic.getHeuristics().size());
-        System.out.println(ct);
-        System.out.println(map);
-        //heuristic.writeToFile("russianSuffixesHeuristic.txt");
+        //final RussianSuffixDecoderEncoder decoderEncoder = new RussianSuffixDecoderEncoder(6);
+        final AtomicLong c = new AtomicLong(0L);
+        final AtomicLong all  = new AtomicLong(0L);
+        dictonaryReader.proccess(
+                new WordProccessor(){
+                    public void proccess(WordCard wordCard) throws IOException {
+                        for (FlexiaModel fm : wordCard.getWordsFroms()) {
+                            String form = fm.create(wordCard.getBase());
+                            int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0;
+                            String formSuffix = form.substring(startSymbol);
+                            Long aLong = RussianSuffixDecoderEncoder.encode(formSuffix);
+                            all.incrementAndGet();
+                            if(map.containsKey(aLong)) c.incrementAndGet();
+                        }
+                    }
+                }
+        );
+
+
+        System.out.println("Ankown words " + all.longValue());
+        System.out.println("Ankown words " + c.longValue());
     }
 }
diff --git a/src/main/java/org/apache/lucene/russian/morphology/RussianSuffixDecoderEncoder.java b/src/main/java/org/apache/lucene/russian/morphology/RussianSuffixDecoderEncoder.java
index 3802050..38d1d2b 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/RussianSuffixDecoderEncoder.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/RussianSuffixDecoderEncoder.java
@@ -24,13 +24,17 @@ package org.apache.lucene.russian.morphology;
  */
 public class RussianSuffixDecoderEncoder {
     public static final int RUSSIAN_SMALL_LETTER_OFFSET = 1071;
-    public static final int SUFFIX_LENGTH = 6;
+    static public int suffixLength = 6;
     public static final int EE_CHAR = 34;
     public static final int E_CHAR = 6;
     public static final int DASH_CHAR = 45;
     public static final int DASH_CODE = 33;
 
 
+    public RussianSuffixDecoderEncoder(int suffixLength) {
+        RussianSuffixDecoderEncoder.suffixLength = suffixLength;
+    }
+
     static public Long encode(String string) {
         if (string.length() > 12) throw new SuffixToLongException("Suffix length should not be greater then " + 12);
         long result = 0L;
diff --git a/src/main/java/org/apache/lucene/russian/morphology/Test.java b/src/main/java/org/apache/lucene/russian/morphology/Test.java
index 3badcdd..1313c13 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/Test.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/Test.java
@@ -8,6 +8,6 @@ import java.io.IOException;
 public class Test {
     public static void main(String[] args) throws IOException {
         GrammaReader grammaReader = new GrammaReader("dictonary/Dicts/Morph/rgramtab.tab");
-        System.out.println(grammaReader.getInversIndex().size());
+        //System.out.println(grammaReader.getInversIndex().size());
     }
 }
diff --git a/src/main/java/org/apache/lucene/russian/morphology/analayzer/SuffixHeuristic.java b/src/main/java/org/apache/lucene/russian/morphology/analayzer/SuffixHeuristic.java
index a8db9e2..4100c35 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/analayzer/SuffixHeuristic.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/analayzer/SuffixHeuristic.java
@@ -58,7 +58,7 @@ public class SuffixHeuristic {
     }
 
     public String getCanonicalForm(String form) {
-        int startSymbol = form.length() > RussianSuffixDecoderEncoder.SUFFIX_LENGTH ? form.length() - RussianSuffixDecoderEncoder.SUFFIX_LENGTH : 0;
+        int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0;
         String suffixS = form.substring(startSymbol);
 
         if (!chechSuffix(suffixS)) return form;
diff --git a/src/main/java/org/apache/lucene/russian/morphology/dictonary/GrammaReader.java b/src/main/java/org/apache/lucene/russian/morphology/dictonary/GrammaReader.java
index 038a737..8ace76d 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/dictonary/GrammaReader.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/dictonary/GrammaReader.java
@@ -6,12 +6,14 @@ import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 
 //todo spleet this class on two.
 public class GrammaReader {
     private String fileName;
     private String fileEncoding = "windows-1251";
-    private Map<Integer, String> grammaInfo = new HashMap<Integer, String>();
+    private List<String> grammaInfo = new ArrayList<String>();
     private Map<String, Integer> inversIndex = new HashMap<String, Integer>();
 
     public GrammaReader(String fileName) throws IOException {
@@ -34,21 +36,17 @@ public class GrammaReader {
                 String[] strings = line.split(" ", 2);
                 Integer i = grammaInfo.size();
                 inversIndex.put(strings[0], i);
-                grammaInfo.put(i, strings[1]);
+                grammaInfo.add(i, strings[1]);
             }
             line = bufferedReader.readLine();
         }
     }
 
-    public Map<Integer, String> getGrammaInfo() {
+    public List<String> getGrammaInfo() {
         return grammaInfo;
     }
 
-    public void setGrammaInfo(Map<Integer, String> grammaInfo) {
-        this.grammaInfo = grammaInfo;
-    }
-
-    public Map<String, Integer> getInversIndex() {
+    public Map<String, Integer> getGrammInversIndex() {
         return inversIndex;
     }
 
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/Heuristic.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/Heuristic.java
index 0463511..9ed5d82 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/heuristic/Heuristic.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/heuristic/Heuristic.java
@@ -28,16 +28,16 @@ import java.util.TreeMap;
 public class Heuristic {
     private TreeMap<Long, Long> encodedSuffixesPairs = new TreeMap<Long, Long>();
 
-    public void addHeuristic(SuffixHeuristic suffixHeuristic) {
-//        Long suffix = RussianSuffixDecoderEncoder.encode(suffixHeuristic.getFormSuffix());
+    public void addHeuristic(SimpleSuffixHeuristic simpleSuffixHeuristic) {
+//        Long suffix = RussianSuffixDecoderEncoder.encode(simpleSuffixHeuristic.getFormSuffix());
 //        Long longs = encodedSuffixesPairs.get(suffix);
 //        if (longs == null) {
-//            encodedSuffixesPairs.put(suffix, RussianSuffixDecoderEncoder.encode(suffixHeuristic.getNormalSuffix()));
+//            encodedSuffixesPairs.put(suffix, RussianSuffixDecoderEncoder.encode(simpleSuffixHeuristic.getNormalSuffix()));
 //        }
     }
 
     public String getNormalForm(String form) {
-        int startSymbol = form.length() > RussianSuffixDecoderEncoder.SUFFIX_LENGTH ? form.length() - RussianSuffixDecoderEncoder.SUFFIX_LENGTH : 0;
+        int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0;
         Long suffix = RussianSuffixDecoderEncoder.encode(form.substring(startSymbol));
 
         Long normalSuffix = encodedSuffixesPairs.get(suffix);
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/HeuristicBySuffixLegth.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/HeuristicBySuffixLegth.java
index d6d736e..4432e3b 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/heuristic/HeuristicBySuffixLegth.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/heuristic/HeuristicBySuffixLegth.java
@@ -9,19 +9,77 @@ import java.util.Set;
 
 
 public class HeuristicBySuffixLegth {
-    private Map<Long, Set<SuffixHeuristic>> heuristics = new HashMap<Long, Set<SuffixHeuristic>>();
+    private Map<Long, Set<SimpleSuffixHeuristic>> heuristics = new HashMap<Long, Set<SimpleSuffixHeuristic>>();
 
-    public void addHeuristic(SuffixHeuristic suffixHeuristic) {
-        Long suffix = RussianSuffixDecoderEncoder.encode(suffixHeuristic.getFormSuffix());
-        Set<SuffixHeuristic> suffixHeuristics = heuristics.get(suffix);
-        if (suffixHeuristics == null) {
-            suffixHeuristics = new HashSet<SuffixHeuristic>();
-            heuristics.put(suffix, suffixHeuristics);
+    public void addHeuristic(SimpleSuffixHeuristic simpleSuffixHeuristic) {
+        Long suffix = RussianSuffixDecoderEncoder.encode(simpleSuffixHeuristic.getFormSuffix());
+        Set<SimpleSuffixHeuristic> simpleSuffixHeuristics = heuristics.get(suffix);
+        if (simpleSuffixHeuristics == null) {
+            simpleSuffixHeuristics = new HashSet<SimpleSuffixHeuristic>();
+            heuristics.put(suffix, simpleSuffixHeuristics);
         }
-        suffixHeuristics.add(suffixHeuristic);
+        simpleSuffixHeuristics.add(simpleSuffixHeuristic);
     }
 
-    public Map<Long, Set<SuffixHeuristic>> getHeuristics() {
+    public Map<Long, Set<SimpleSuffixHeuristic>> getHeuristics() {
         return heuristics;
     }
+
+    public Map<Long,SimpleSuffixHeuristic> getSingleSuffixes(){
+        HashMap<Long, SimpleSuffixHeuristic> result = new HashMap<Long, SimpleSuffixHeuristic>();
+        for(Long st:heuristics.keySet()){
+            if(heuristics.get(st).size() == 1){
+                result.put(st,heuristics.get(st).iterator().next());
+            }
+        }
+        return result;
+    }
+
+
+    public Map<Long,Set<SimpleSuffixHeuristic>> getWordWithMorphology(){
+        HashMap<Long, Set<SimpleSuffixHeuristic>> result = new HashMap<Long, Set<SimpleSuffixHeuristic>>();
+        for(Long st:heuristics.keySet()){
+            if(heuristics.get(st).size() == 1) continue;
+            if(checkSetOnSuffix(heuristics.get(st))) {
+                result.put(st,heuristics.get(st));
+            }
+        }
+        return result;
+    }
+
+    public Map<Long,Set<SimpleSuffixHeuristic>> getOnonyms(){
+        HashMap<Long, Set<SimpleSuffixHeuristic>> result = new HashMap<Long, Set<SimpleSuffixHeuristic>>();
+        for(Long st:heuristics.keySet()){
+            if(heuristics.get(st).size() == 1) continue;
+            if(checkSetOnSuffix(heuristics.get(st))) continue;
+            if(heuristics.get(st).iterator().next().getFormSuffix().length() < 6){
+                result.put(st,heuristics.get(st));
+            }
+        }
+        return result;
+    }
+
+    public Map<Long,Set<SimpleSuffixHeuristic>> getUnkowns(){
+        HashMap<Long, Set<SimpleSuffixHeuristic>> result = new HashMap<Long, Set<SimpleSuffixHeuristic>>();
+        for(Long st:heuristics.keySet()){
+            if(heuristics.get(st).size() == 1) continue;
+            if(checkSetOnSuffix(heuristics.get(st))) continue;
+            if(heuristics.get(st).iterator().next().getFormSuffix().length() >= 6){
+                result.put(st,heuristics.get(st));
+            }
+        }
+        return result;
+    }
+
+    private Boolean checkSetOnSuffix(Set<SimpleSuffixHeuristic> sshs) {
+        SimpleSuffixHeuristic heuristic = sshs.iterator().next();
+        String normalSuffix = heuristic.getFormSuffix();
+        Integer suffixLenght = heuristic.getActualSuffixLength();
+        Boolean result = true;
+        for(SimpleSuffixHeuristic ssh:sshs){
+            result = result && ssh.getActualSuffixLength().equals(suffixLenght) && ssh.getNormalSuffix().endsWith(normalSuffix);
+        }
+        return result;
+    }
+
 }
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SimpleSuffixHeuristic.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SimpleSuffixHeuristic.java
new file mode 100644
index 0000000..95c6b70
--- /dev/null
+++ b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SimpleSuffixHeuristic.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2009 Alexander Kuznetsov 
+ *
+ * Licensed 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.
+ */
+
+package org.apache.lucene.russian.morphology.heuristic;
+
+/**
+ * Represent evristic that assume that
+ * canonical from of word is defined by word suffix.
+ * It contains to suffixes from given position of
+ * canonical word form and for form.
+ */
+public class SimpleSuffixHeuristic {
+    private String formSuffix;
+    private Integer actualSuffixLength;
+    private String normalSuffix;
+    private String morphInfoCode;
+
+    public SimpleSuffixHeuristic(String formSuffix, Integer actualSuffixLength, String normalSuffix, String morphInfoCode) {
+        this.formSuffix = formSuffix;
+        this.actualSuffixLength = actualSuffixLength;
+        this.normalSuffix = normalSuffix;
+        this.morphInfoCode = morphInfoCode;
+    }
+
+    public String getFormSuffix() {
+        return formSuffix;
+    }
+
+    public Integer getActualSuffixLength() {
+        return actualSuffixLength;
+    }
+
+    public String getNormalSuffix() {
+        return normalSuffix;
+    }
+
+    public String getMorphInfoCode() {
+        return morphInfoCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        SimpleSuffixHeuristic that = (SimpleSuffixHeuristic) o;
+
+        if (actualSuffixLength != null ? !actualSuffixLength.equals(that.actualSuffixLength) : that.actualSuffixLength != null)
+            return false;
+        if (formSuffix != null ? !formSuffix.equals(that.formSuffix) : that.formSuffix != null) return false;
+        if (morphInfoCode != null ? !morphInfoCode.equals(that.morphInfoCode) : that.morphInfoCode != null)
+            return false;
+        if (normalSuffix != null ? !normalSuffix.equals(that.normalSuffix) : that.normalSuffix != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = formSuffix != null ? formSuffix.hashCode() : 0;
+        result = 31 * result + (actualSuffixLength != null ? actualSuffixLength.hashCode() : 0);
+        result = 31 * result + (normalSuffix != null ? normalSuffix.hashCode() : 0);
+        result = 31 * result + (morphInfoCode != null ? morphInfoCode.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return formSuffix + " " + actualSuffixLength + " " + normalSuffix + " " + morphInfoCode;
+    }
+}
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/StatiticsCollectors.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/StatiticsCollectors.java
index db9782b..b9dc025 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/heuristic/StatiticsCollectors.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/heuristic/StatiticsCollectors.java
@@ -27,7 +27,7 @@ import java.util.Map;
 
 
 public class StatiticsCollectors implements WordProccessor {
-    Map<SuffixHeuristic, SuffixCounter> statititics = new HashMap<SuffixHeuristic, SuffixCounter>();
+    Map<SimpleSuffixHeuristic, SuffixCounter> statititics = new HashMap<SimpleSuffixHeuristic, SuffixCounter>();
     private Map<String, Double> wordsFreq;
     private GrammaReader grammaInfo;
 
@@ -40,12 +40,12 @@ public class StatiticsCollectors implements WordProccessor {
 
     public void proccess(WordCard wordCard) {
         for (FlexiaModel fm : wordCard.getWordsFroms()) {
-            SuffixHeuristic suffixHeuristic = createEvristic(wordCard.getCanonicalFrom(), wordCard.getCanonicalSuffix(), fm);
-            if (suffixHeuristic == null) continue;
-            SuffixCounter suffixCounter = statititics.get(suffixHeuristic);
+            SimpleSuffixHeuristic simpleSuffixHeuristic = createEvristic(wordCard.getBase(), wordCard.getCanonicalSuffix(), fm);
+            if (simpleSuffixHeuristic == null) continue;
+            SuffixCounter suffixCounter = statititics.get(simpleSuffixHeuristic);
             if (suffixCounter == null) {
-                suffixCounter = new SuffixCounter(suffixHeuristic);
-                statititics.put(suffixHeuristic, suffixCounter);
+                suffixCounter = new SuffixCounter(simpleSuffixHeuristic);
+                statititics.put(simpleSuffixHeuristic, suffixCounter);
             }
             Double freq = wordsFreq.get(wordCard.getCanonicalFrom());
             if (freq != null) {
@@ -57,27 +57,17 @@ public class StatiticsCollectors implements WordProccessor {
         }
     }
 
-    public Map<SuffixHeuristic, SuffixCounter> getStatititics() {
+    public Map<SimpleSuffixHeuristic, SuffixCounter> getStatititics() {
         return statititics;
     }
 
-    private SuffixHeuristic createEvristic(String wordBase, String canonicalSuffix, FlexiaModel fm) {
+    private SimpleSuffixHeuristic createEvristic(String wordBase, String canonicalSuffix, FlexiaModel fm) {
         String form = fm.create(wordBase);
-        int startSymbol = form.length() > RussianSuffixDecoderEncoder.SUFFIX_LENGTH ? form.length() - RussianSuffixDecoderEncoder.SUFFIX_LENGTH : 0;
+        int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0;
         String formSuffix = form.substring(startSymbol);
         String actualSuffix = fm.getSuffix();
         Integer actualSuffixLengh = actualSuffix.length();
-//        if (word.length() < startSymbol) {
-//            ignoredCount++;
-//            return null;
-//        }
-//        String wordSuffix = word.length() > startSymbol ? word.substring(startSymbol) : "";
-//        if (wordSuffix.length() > 12) {
-//            System.out.println(word + " " + form);
-//            return null;
-//        }
-//        return new SuffixHeuristic(formSuffix, wordSuffix);
-        return new SuffixHeuristic(formSuffix, actualSuffixLengh, canonicalSuffix, fm.getCode());
+        return new SimpleSuffixHeuristic(formSuffix, actualSuffixLengh, canonicalSuffix, fm.getCode());
     }
 
 
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixCounter.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixCounter.java
index d66f9b5..2db5a07 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixCounter.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixCounter.java
@@ -21,11 +21,11 @@ package org.apache.lucene.russian.morphology.heuristic;
  * in dictionary.
  */
 public class SuffixCounter implements Comparable {
-    private SuffixHeuristic suffixHeuristic;
+    private SimpleSuffixHeuristic simpleSuffixHeuristic;
     private Double amnout = 0.0;
 
-    public SuffixCounter(SuffixHeuristic suffixHeuristic) {
-        this.suffixHeuristic = suffixHeuristic;
+    public SuffixCounter(SimpleSuffixHeuristic simpleSuffixHeuristic) {
+        this.simpleSuffixHeuristic = simpleSuffixHeuristic;
     }
 
     public void incrementAmount() {
@@ -36,12 +36,12 @@ public class SuffixCounter implements Comparable {
         amnout += wordFreq;
     }
 
-    public SuffixHeuristic getSuffixHeuristic() {
-        return suffixHeuristic;
+    public SimpleSuffixHeuristic getSuffixHeuristic() {
+        return simpleSuffixHeuristic;
     }
 
-    public void setSuffixEvristic(SuffixHeuristic suffixHeuristic) {
-        this.suffixHeuristic = suffixHeuristic;
+    public void setSuffixEvristic(SimpleSuffixHeuristic simpleSuffixHeuristic) {
+        this.simpleSuffixHeuristic = simpleSuffixHeuristic;
     }
 
     public Double getAmnout() {
@@ -59,6 +59,6 @@ public class SuffixCounter implements Comparable {
 
     @Override
     public String toString() {
-        return "" + amnout + " " + suffixHeuristic.toString();
+        return "" + amnout + " " + simpleSuffixHeuristic.toString();
     }
 }
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixHeuristic.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixHeuristic.java
index 8dfadc8..0bdf6f8 100644
--- a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixHeuristic.java
+++ b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixHeuristic.java
@@ -1,85 +1,10 @@
-/**
- * Copyright 2009 Alexander Kuznetsov 
- *
- * Licensed 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.
- */
-
-package org.apache.lucene.russian.morphology.heuristic;
-
-/**
- * Represent evristic that assume that
- * canonical from of word is defined by word suffix.
- * It contains to suffixes from given position of
- * canonical word form and for form.
- */
-public class SuffixHeuristic {
-    private String formSuffix;
-    private Integer actualSuffixLength;
-    private String normalFromSuffix;
-    private String morphInfoCode;
-
-    public SuffixHeuristic(String formSuffix, Integer actualSuffixLength, String normalFromSuffix, String morphInfoCode) {
-        this.formSuffix = formSuffix;
-        this.actualSuffixLength = actualSuffixLength;
-        this.normalFromSuffix = normalFromSuffix;
-        this.morphInfoCode = morphInfoCode;
-    }
-
-    public String getFormSuffix() {
-        return formSuffix;
-    }
-
-    public Integer getActualSuffixLength() {
-        return actualSuffixLength;
-    }
-
-    public String getNormalFromSuffix() {
-        return normalFromSuffix;
-    }
-
-    public String getMorphInfoCode() {
-        return morphInfoCode;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        SuffixHeuristic that = (SuffixHeuristic) o;
-
-        if (actualSuffixLength != null ? !actualSuffixLength.equals(that.actualSuffixLength) : that.actualSuffixLength != null)
-            return false;
-        if (formSuffix != null ? !formSuffix.equals(that.formSuffix) : that.formSuffix != null) return false;
-        if (morphInfoCode != null ? !morphInfoCode.equals(that.morphInfoCode) : that.morphInfoCode != null)
-            return false;
-        if (normalFromSuffix != null ? !normalFromSuffix.equals(that.normalFromSuffix) : that.normalFromSuffix != null)
-            return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = formSuffix != null ? formSuffix.hashCode() : 0;
-        result = 31 * result + (actualSuffixLength != null ? actualSuffixLength.hashCode() : 0);
-        result = 31 * result + (normalFromSuffix != null ? normalFromSuffix.hashCode() : 0);
-        result = 31 * result + (morphInfoCode != null ? morphInfoCode.hashCode() : 0);
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return formSuffix + " " + actualSuffixLength + " " + normalFromSuffix + " " + morphInfoCode;
-    }
-}
+package org.apache.lucene.russian.morphology.heuristic;
+
+
+public class SuffixHeuristic {
+    private SuffixTypes suffixType;
+    private Byte suffixLengh;
+    private Short indexOfWordTransorm;
+    private Short indexOfMothInfo;
+}
+
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixHeuristicMerger.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixHeuristicMerger.java
deleted file mode 100644
index cbaac4a..0000000
--- a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixHeuristicMerger.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.apache.lucene.russian.morphology.heuristic;
-
-
-public class SuffixHeuristicMerger {
-
-    public SuffixHeuristic merge(SuffixHeuristic one, SuffixHeuristic two) {
-        if (!one.getMorphInfoCode().equals(two.getMorphInfoCode()))
-            return null;
-        SuffixHeuristic min = one.getActualSuffixLength() > two.getActualSuffixLength() ? two : one;
-
-        return null;
-    }
-}
diff --git a/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixTypes.java b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixTypes.java
new file mode 100644
index 0000000..3d4a33d
--- /dev/null
+++ b/src/main/java/org/apache/lucene/russian/morphology/heuristic/SuffixTypes.java
@@ -0,0 +1,8 @@
+package org.apache.lucene.russian.morphology.heuristic;
+
+
+public enum SuffixTypes {
+     SINGLE,
+     DIFFIRENT_MORPH,
+     ONONIMS 
+}
diff --git a/src/main/java/org/apache/lucene/russian/morphology/informations/GrammaInfo.java b/src/main/java/org/apache/lucene/russian/morphology/informations/GrammaInfo.java
new file mode 100644
index 0000000..cd37b23
--- /dev/null
+++ b/src/main/java/org/apache/lucene/russian/morphology/informations/GrammaInfo.java
@@ -0,0 +1,16 @@
+package org.apache.lucene.russian.morphology.informations;
+
+import java.io.Serializable;
+
+
+public class GrammaInfo implements Serializable{
+    private String[] grammaInfo;
+
+    public GrammaInfo(String[] grammaInfo) {
+        this.grammaInfo = grammaInfo;
+    }
+
+    public String getInfo(Integer index){
+        return grammaInfo[index];
+    }
+}
diff --git a/src/main/java/org/apache/lucene/russian/morphology/informations/NormalSuffixCollection.java b/src/main/java/org/apache/lucene/russian/morphology/informations/NormalSuffixCollection.java
new file mode 100644
index 0000000..efdebd7
--- /dev/null
+++ b/src/main/java/org/apache/lucene/russian/morphology/informations/NormalSuffixCollection.java
@@ -0,0 +1,16 @@
+package org.apache.lucene.russian.morphology.informations;
+
+import java.io.Serializable;
+
+
+public class NormalSuffixCollection implements Serializable{
+    private String[] normalSuffixes;
+
+    public NormalSuffixCollection(String[] normalSuffixes) {
+        this.normalSuffixes = normalSuffixes;
+    }
+
+    public String getSuffix(Integer index){
+        return normalSuffixes[index];
+    }
+}
diff --git a/src/test/java/org/apache/lucene/russian/morphology/SpeedTest.java b/src/test/java/org/apache/lucene/russian/morphology/SpeedTest.java
new file mode 100644
index 0000000..35ea625
--- /dev/null
+++ b/src/test/java/org/apache/lucene/russian/morphology/SpeedTest.java
@@ -0,0 +1,45 @@
+package org.apache.lucene.russian.morphology;
+
+import org.junit.Test;
+import static org.junit.Assert.assertThat;
+import org.apache.lucene.russian.morphology.analayzer.RussianMorphlogyAnalayzer;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.TokenStream;
+import static org.hamcrest.core.IsEqual.equalTo;
+
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+
+public class SpeedTest {
+
+    @Test
+    public void getTestOfSpeed() throws IOException {
+        Long startTime = System.currentTimeMillis();
+        RussianMorphlogyAnalayzer morphlogyAnalayzer = new RussianMorphlogyAnalayzer();
+        System.out.println("To build analayzer take " + (System.currentTimeMillis() - startTime) + " ms.");        
+        InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/text.txt");
+        BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
+
+
+        final Token reusableToken = new Token();
+
+        Token nextToken;
+
+
+        startTime = System.currentTimeMillis();
+        Integer count = 0;
+        TokenStream in = morphlogyAnalayzer.tokenStream(null, reader);
+        for (; ;) {
+            nextToken = in.next(reusableToken);
+            count++;
+            if (nextToken == null) {
+                break;
+            }
+
+        }
+        System.out.println("It takes " + (System.currentTimeMillis() - startTime) + " ms. To proccess  " + count + " words." );
+    }
+}
diff --git a/src/test/resources/org/apache/lucene/russian/morphology/text.txt b/src/test/resources/org/apache/lucene/russian/morphology/text.txt
new file mode 100644
index 0000000..449a01e
--- /dev/null
+++ b/src/test/resources/org/apache/lucene/russian/morphology/text.txt
@@ -0,0 +1,160 @@
+Морфологический анализатор для русского языка — это что-то заумное? Программа, которая приводит слово к начальной форме, определяет падеж, находит словоформы — непонятно, как и подступиться? А на самом деле все не так и сложно. В статье — как я писал аналог mystem, lemmatizer и phpmorphy на Python, и что из этого получилось.
+
+Сразу скажу, получилась библиотека для морфологического анализа на Python, которую Вы можете использовать и дорабатывать согласно лицензии MIT.
+
+Первый вопрос — зачем все это?
+
+Потихоньку делаю один хобби-проект, назрело решение писать его на Python. А для проекта был жизненно необходим более-менее качественный морфологический анализатор. Вариант с mystem не подошел из-за лицензии и отсутствием возможности поковыряться, lemmatizer и phpmorphy меня слегка напрягали своими словарями не в юникоде, а приличного аналога на python я почему-то не нашел. Вообщем причин много, все, если честно, не очень серьезные, на самом деле просто захотелось. Решил я, в итоге, изобрести велосипед и написать свою реализацию.
+
+За основу взял наработки с сайта aot.ru. Словари (LGPL) для русского и английского, а также идеи — оттуда. Там были описаны и конкретные алгоритмы реализации, но в терминах теории автоматов. Я знаком с теорией автоматов (даже диплом по формальным грамматикам защитил), но мне показалось, что тут можно прекрасно обойтись без нее. Поэтому реализация — независимая, что имеет как плюсы, так и минусы.
+
+Для начала, библиотека должна, как минимум, уметь:
+1. Приводить слово к нормальной форме (например, в ед.ч., И.п. для существительных) — для слова «ЛЮДЕЙ» она должна вернуть «ЧЕЛОВЕК»
+2. Определять форму слова (или формы). Например, для слова «ЛЮДЕЙ» она должна как-то дать знать, что это существительное, во множественном числе, может оказаться в родительном или винительном падежах.
+
+Разбираемся со словарями
+
+Словари с сайта aot.ru содержат следующую информацию:
+1. парадигмы слов и конкретные правила образования;
+2. ударения;
+3. пользовательские сессии;
+4. набор префиксов (продуктивных приставок);
+5. леммы (незменяемые части слова, основы);
+и еще есть 6. грамматическая информация — в отдельном файле.
+
+Из этого всего нам интересны правила образования слов, префиксы, леммы и грамматическая информация.
+
+Все слова образуются по одному принципу:
+[префикс]+[приставка]+[основа]+[окончание]
+
+Префиксы — это всякие «мега», «супер» и т.д. Набор префиксов хранится просто списком.
+
+Приставки — имеются в виду приставки, присущие грамматической форме, но не присущие неизменяемой части слова («по»,«наи»). Например, «наи» в слове «наикрасивейший», т.к. без превосходной степени будет «красивый».
+
+Правила образования слов — это то, что надо приписать спереди и сзади основы, чтобы получить какую-то форму. В словаре хранятся пары «приставка — окончание», + «номер» записи о грамматической информации (которая хранится отдельно).
+
+Правила образования слов объединены в парадигмы. Например, для какого-нибудь класса существительных может быть описано, как слово выглядит во всех падежах и родах. Зная, что существительное принадлежит к этому классу, мы сможем правильно получить любую его форму. Такой класс — это и есть парадигма. Первой в парадигме всегда идет нормальная форма слова (если честно, вывод эмпирический))
+
+Леммы — это неизменяемые части слов. В словаре хранится информация о том, какой лемме соответствуют какие парадигмы (какой набор правил для образования грамматических форм слова). Одной лемме может соответствовать несколько парадигм.
+
+Грамматическая информация — просто пары («номер» записи, грам. информация). «Номер» в кавычках, т.к. это 2 буквы, просто от балды, но все разные.
+
+Файл со словарем — обычный текстовый, для каждого раздела сначала указано число строк в нем, а потом идут строки, формат их описан, так что написать парсер труда не составило.
+
+Поняв структуру словаря, уже несложно написать первую версию морфологического анализатора.
+
+Пишем морфологический анализатор
+
+По сути, нам дано слово, и его надо найти среди всех разумных комбинаций вида
+<префикс>+<приставка>+<лемма>+<окончание> и
+<приставка>+<лемма>+<окончание>
+
+Дело упрощает то, что оказалось (как показала пара строчек на питоне), что «приставок» у нас в языке (да и в английском вроде тоже) всего 2. А префиксов в словаре — порядка 20 для русского языка. Поэтому искать можно среди комбинаций
+<префикс>+<лемма>+<окончание>, объединив в уме список приставок и префиксов, а затем выполнив небольшую проверочку.
+
+С префиксом разберемся по-свойски: если слово начинается с одного из возможных префиксов, то мы его (префикс) отбрасываем и пытаемся морфологически анализировать остаток (рекурсивно), а потом просто припишем отброшенный префикс к полученным формам.
+
+В итоге получается, что задача сводится к поиску среди комбинаций
+<лемма>+<окончание>, что еще лучше. Ищем подходящие леммы, потом смотрим, есть ли для них подходящие окончания*.
+
+Тут я решил сильно упростить себе жизнь, и задействовать стандартный питоновский ассоциативный массив, в который поместил все леммы. Получился словарь вида lemmas: {base -> [rule_id]}, т.е. ключ — это лемма, а значение — список номеров допустимых парадигм. А дальше поехали — сначала считаем, что лемма — это первая буква слова, потом, что это 2 первых буквы и т.д. По лемме пытаемся получить список парадигм. Если получили, то в каждой допустимой парадигме пробегаем по всем правилам и смотрим, получится ли наше слово, если правило применить. Получается — добавляем его в список найденных форм.
+
+*Еще был вариант — составить сразу словарь всех возможных слов вида <лемма>+<окончание>, получалось в итоге где-то миллионов 5 слов, не так и много, но вариант, вообщем, мне не очень понравился.
+
+Дописываем морфологический анализатор
+
+По сути — все готово, мы написали морфологический анализатор, за исключением некоторых деталей, которые заняли у меня 90% времени)
+
+Деталь первая
+Если вспомнить пример, который был в начале, про «ЛЮДЕЙ» — «ЧЕЛОВЕК», то станет понятно, что есть слова, у которых неизменяемая часть отсутствует. И где тогда искать формы этих слов — непонятно. Пробовал искать среди всех окончаний (точно так же, как и среди лемм), ведь для таких слов и «ЛЮДЕЙ», и «ЧЕЛОВЕКУ» в словаре будут храниться как окончания. Для некоторых слов работало, для некоторых выдавало, кроме правильного результата, еще и кучу мусора. В итоге, после долгих экспериментов выяснилось, что есть в словаре такая хитрая магическая лемма "#", которая и соответствует всем пустым леммам. Ура, задача решена, ищем каждый раз еще и там.
+
+Деталь вторая
+Хорошо бы иметь «предсказатель», который смог бы работать и со словами, которых нет в словаре. Это не только неизвестные науке редкие слова, но и просто описки, например.
+
+Тут есть 2 несложных, но вполне работающих подхода:
+1. Если слова отличаются только тем, что к одному из них приписано что-то спереди, то, скорее всего, склоняться они будут однаково
+2. Если 2 слова оканчиваются одинаково, то и склоняться они, скорее всего, будут одинаково.
+
+Первый подход — это угадывание префикса. Реализуется очень просто: пробуем считать сначала одну первую букву слова префиксом, потом 2 первых буквы и т.д. А то, что осталось, передаем морфологическому анализатору. Ну и делаем это только для не очень длинных префиксов и не очень коротких остатков.
+
+Второй (предсказание по концу слова) подход чуть сложнее в реализации (так-то сильно сложнее, если нужна хорошая реализация)) и «поумнее» в плане предсказаний.
+Первая сложность связана с тем, что конец слова может состоять не только из окончания, но и из части леммы. Тут я тоже решил «срезать углы» и задействовал опять ассоциативный массив с предварительно подготовленными всеми возмоными окончаниями слов (до 5 букв). Не так и много их получилось, несколько сот тысяч. Ключ массива — конец слова, значение — список возможных правил. Дальше — все как при поиске подходящей леммы, только у слова берем не начало, а 1, 2, 3, 4, 5-буквенные концы, а вместо лемм у нас теперь новый монстромассив.
+Вторая сложность — получается много заведомого мусора. Мусор этот отсекается, если учесть, что полученные слова могут быть только существительными, прилагательными, наречиями или глаголами.
+Даже после этого у нас остается слишком много не-мусорных правил. Для определенности, для каждой части речи оставляем только самое распространенное правило.
+По идее, если слово не было предсказано как существительное, хорошо бы добавить вариант с неизменяемым существительным в ед.ч. и.п., но это в TODO.
+
+Идеальный текст для проверки работы предсказателя — конечно же, «Сяпала Калуша по напушке», про то, как она там увазила бутявку и что из этого вышло:
+
+    Сяпала Калуша по напушке и увазила бутявку. И волит:
+    — Калушата, калушаточки! Бутявка!
+    Калушата присяпали и бутявку стрямкали. И подудонились.
+    А Калуша волит:
+    — Оее, оее! Бутявка-то некузявая!
+    Калушата бутявку вычучили.
+    Бутявка вздребезнулась, сопритюкнулась и усяпала с напушки.
+    А Калуша волит:
+    — Бутявок не трямкают. Бутявки дюбые и зюмо-зюмо некузявые. От бутявок дудонятся.
+    А бутявка волит за напушкой:
+    — Калушата подудонились! Калушата подудонились! Зюмо некузявые! Пуськи бятые!
+
+
+Из текста предсказатель не справился с именем собственным Калуша, с «Калушата»(они стали мужиками «Калуш» и «Калушат»), с междометием «Оее», загадочным «зюмо-зюмо», и вместо «Пуська» опять выдал мужика «Пусек», остальное все, на мой взгляд, определил правильно. Вообщем есть куда стремиться, но уже неплохо.
+
+О ужас, «хабрахабр» предсказывается тоже никак. А вот «хабрахабра» — уже понимает, что «хабрахабр».
+
+Тут можно было бы, в принципе, подвести итог, если бы компьютеры работали мгновенно. Но это не так, поэтому есть
+
+Деталь №3: ресурсы процессора и оперативной памяти
+Скорость работы первого варианта меня вполне устроила. Получалось, по прикидкам, тыщ до 10 слов в секунду для простых русских слов, около тыщи для навороченных. Для английского — еще быстрее. Но было 2 очевидных (еще до начала разработки) «но», связанных с тем, что все данные грузились в оперативную память (через pickle/cPickle).
+1. первоначальная загрузка занимала 3-4 секунды
+2. кушалось порядка 150 мегабайт оперативной памяти с psyco и порядка 100 без ( +удалось немного сократить, когда привел всякие там питоновские set и list к tulpe, где возможно)
+
+Не долго думая, провел небольшой рефакторинг и вынес все данные в отдельную сущность. А дальше мне на помощь пришла магия Python и duck typing. Вкратце — в алгоритмах использовались данные в виде ассоциативных и простых массивов. И все будет работать без переписывания алгоритмов, если вместо «настоящих» массивов подсунуть что-нибудь, что ведет себя как массив, а конкретнее, для нашей задачи, — поддерживает [] и in. Все) В стандартной поставке питона обнаружились такие «массивные» интерфейсы к нескольким нереляционным базам данных. Эти базы (bsddb, ndbm, gdbm), по сути, и есть ассоциативные массивы на диске. Как раз то, что нужно. Еще там обнаружилась пара высокоуровневых надстроек над этим хозяйством (anydbm и shelve). Остановился на том, что унаследовался от DbfilenameShelf и добавил поддержку ключей в юникоде и ключей-целых чисел. А, еще добавил кеширование результата, которое почему-то есть в Shelf, но убито в DbfilenameShelf.
+
+Данные по скорости на тестовых текстах (995 слов, русский словарь, macbook):
+get_pickle_morph('ru', predict_by_prefix = False): 0.214 CPU seconds
+get_pickle_morph('ru'): 0.262 CPU seconds
+get_shelve_morph('ru', predict_by_prefix = False): 0.726 CPU seconds
+get_shelve_morph('ru'): 0.874 CPU seconds
+
+Памяти вариант shelve, можно сказать, не кушал совсем.
+
+Варианты shelve похоже, работали, когда словари уже сидели в дисковом кеше. Без этого время может быть и 20 секунд с включенным предсказателем. Еще замечал, что медленнее всего работает предсказание по префиксу: до того, как прикрутил кеширование к своим наследникам от DbfilenameShelf, тормозило это предсказание раз в 5 больше, чем все остальное вместе взятое. А в этих тестах вроде не сильно уже.
+
+Кстати, пользуясь случаем, хочу спросить, вдруг кто-то знает, как в питоне можно узнать количество занятой текущим процессом памяти. По возможности кроссплатформенно как-нибудь. А то ставил в конец скрипта задержку и мерил по списку процессов.
+
+Пример использования
+
+import pymorphy
+morph = pymorphy.get_shelve_morph('ru')
+#слова должны быть в юникоде и ЗАГЛАВНЫМИ
+info = morph.get_graminfo(unicode('Вася').upper())
+
+
+Так все-таки, зачем?
+
+В самом начале я уже объяснил, зачем стал писать морфологический анализатор.
+Теперь время объяснить, почему я стал писать эту статью. Я ее написал в надежде на то, что такая библиотека интересна и полезна, и вместе мы эту библиотеку улучшим. Дело в том, что функционал, который уже реализован, вполне достаточен для моих нужд. Я буду ее поддерживать и исправлять, но не очень активно. Поэтому эта статья — не подробная инструкция по применению, а попытка описать, как все работает.
+
+В поставке
+
+pymorphy.py — сама библиотека
+shelve_addons.py — наследники от shelf, может кому пригодится
+encode_dicts.py — утилита, которая преобразовывает словари из формата AOT в форматы pymorphy. Без параметров, работает долго, ест метров 200 памяти, запускается 1 раз. Сконвертированные словари не распространяю из-за возможной бинарной несовместимости и большого объема.
+test.py — юнит-тесты для pymorphy
+example.py — небольшой пример и тексты с теми 995 словами
+dicts/src — папка с исходными словарями, скачанными с aot.ru
+dicts/converted — папка, куда encode_dicts.py будет складывать сконвертированные словари
+
+Напоследок
+
+ссылки:
+www.assembla.com/wiki/show/pymorphy
+hg.assembla.com/pymorphy
+trac-hg.assembla.com/pymorphy
+
+Лицензия — MIT.
+
+проверял только под Python 2.5.
+
+Замечания, предложения, вопросы по делу — приветствуются. Если интересно — подключайтесь к разработке.
\ No newline at end of file