working on new model for morphology

git-svn-id: https://russianmorphology.googlecode.com/svn/trunk@43 d817d54c-26ab-11de-abc9-2f7d1455ff7a
This commit is contained in:
alexander.a.kuznetsov 2009-08-15 17:02:46 +00:00
parent f2856e5696
commit 613cd0d72b
23 changed files with 401 additions and 570 deletions

View File

@ -16,18 +16,13 @@
package org.apache.lucene.russian.morphology; package org.apache.lucene.russian.morphology;
import org.apache.lucene.russian.morphology.dictonary.*; import org.apache.lucene.russian.morphology.dictonary.DictonaryReader;
import org.apache.lucene.russian.morphology.heuristic.HeuristicBySuffixLegth; import org.apache.lucene.russian.morphology.dictonary.FrequentyReader;
import org.apache.lucene.russian.morphology.heuristic.SimpleSuffixHeuristic; import org.apache.lucene.russian.morphology.dictonary.GrammaReader;
import org.apache.lucene.russian.morphology.heuristic.StatiticsCollectors; import org.apache.lucene.russian.morphology.dictonary.IgnoredFormReader;
import org.apache.lucene.russian.morphology.heuristic.SuffixCounter;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
public class HeuristicBuilder { public class HeuristicBuilder {
@ -39,9 +34,9 @@ public class HeuristicBuilder {
GrammaReader grammaInfo = new GrammaReader("dictonary/Dicts/Morph/rgramtab.tab"); GrammaReader grammaInfo = new GrammaReader("dictonary/Dicts/Morph/rgramtab.tab");
DictonaryReader dictonaryReader = new DictonaryReader("dictonary/Dicts/SrcMorph/RusSrc/morphs.mrd", form); DictonaryReader dictonaryReader = new DictonaryReader("dictonary/Dicts/SrcMorph/RusSrc/morphs.mrd", form);
NewModel newModel = new NewModel(); StatiticsCollector statiticsCollector = new StatiticsCollector();
dictonaryReader.proccess(newModel); dictonaryReader.proccess(statiticsCollector);
newModel.printInfo(); statiticsCollector.printInfo();
// StatiticsCollectors statiticsCollectors = new StatiticsCollectors(frequentyReader.read()); // StatiticsCollectors statiticsCollectors = new StatiticsCollectors(frequentyReader.read());
@ -84,7 +79,7 @@ public class HeuristicBuilder {
// if(form.startsWith("ïðèê") && form.endsWith("üÿ")) System.out.println(form); // if(form.startsWith("ïðèê") && form.endsWith("üÿ")) System.out.println(form);
// //
// //
// int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0; // int startSymbol = form.length() > RussianSuffixDecoderEncoder.SUFFIX_LENGTH ? form.length() - RussianSuffixDecoderEncoder.SUFFIX_LENGTH : 0;
// String formSuffix = form.substring(startSymbol); // String formSuffix = form.substring(startSymbol);
// Long aLong = RussianSuffixDecoderEncoder.encode(formSuffix); // Long aLong = RussianSuffixDecoderEncoder.encode(formSuffix);
// all.incrementAndGet(); // all.incrementAndGet();

View File

@ -16,6 +16,8 @@
package org.apache.lucene.russian.morphology; package org.apache.lucene.russian.morphology;
import java.util.ArrayList;
/** /**
* This helper class allow encode suffix of russian word * This helper class allow encode suffix of russian word
* to long value and decode from it. * to long value and decode from it.
@ -24,39 +26,67 @@ package org.apache.lucene.russian.morphology;
*/ */
public class RussianSuffixDecoderEncoder { public class RussianSuffixDecoderEncoder {
public static final int RUSSIAN_SMALL_LETTER_OFFSET = 1071; public static final int RUSSIAN_SMALL_LETTER_OFFSET = 1071;
static public int suffixLength = 6; static public int SUFFIX_LENGTH = 6;
public static final int EE_CHAR = 34; public static final int EE_CHAR = 34;
public static final int E_CHAR = 6; public static final int E_CHAR = 6;
public static final int DASH_CHAR = 45; public static final int DASH_CHAR = 45;
public static final int DASH_CODE = 33; public static final int DASH_CODE = 33;
static public Integer encode(String string) {
public RussianSuffixDecoderEncoder(int suffixLength) { if (string.length() > 6) throw new SuffixToLongException("Suffix length should not be greater then " + 12);
RussianSuffixDecoderEncoder.suffixLength = suffixLength; int result = 0;
}
static public Long encode(String string) {
if (string.length() > 12) throw new SuffixToLongException("Suffix length should not be greater then " + 12);
long result = 0L;
for (int i = 0; i < string.length(); i++) { for (int i = 0; i < string.length(); i++) {
int c = 0 + string.charAt(i) - RUSSIAN_SMALL_LETTER_OFFSET; int c = 0 + string.charAt(i) - RUSSIAN_SMALL_LETTER_OFFSET;
if (c == 45 - RUSSIAN_SMALL_LETTER_OFFSET) { if (c == 45 - RUSSIAN_SMALL_LETTER_OFFSET) {
c = DASH_CODE; c = DASH_CODE;
} }
if (c == EE_CHAR) c = E_CHAR; if (c == EE_CHAR) c = E_CHAR;
if (c < 0 || c > 33) throw new WrongCharaterException(); if (c < 0 || c > 33)
result = result * 35L + c; throw new WrongCharaterException("Symblo " + string.charAt(i) + " is not small cirillic letter");
result = result * 34 + c;
}
for (int i = string.length(); i < 6; i++) {
result *= 34;
} }
return result; return result;
} }
static public String decode(Long suffixN) { static public int[] encodeToArray(String s) {
ArrayList<Integer> integers = new ArrayList<Integer>();
while (s.length() > 6) {
integers.add(encode(s.substring(0, 6)));
s = s.substring(6);
}
integers.add(encode(s));
int[] ints = new int[integers.size()];
int pos = 0;
for (Integer i : integers) {
ints[pos] = i;
pos++;
}
return ints;
}
static public String decodeArray(int[] array) {
String result = ""; String result = "";
while (suffixN > 35) { for (int i : array) {
long c = suffixN % 35 + RUSSIAN_SMALL_LETTER_OFFSET; result += decode(i);
}
return result;
}
static public String decode(Integer suffixN) {
String result = "";
while (suffixN > 33) {
int c = suffixN % 34 + RUSSIAN_SMALL_LETTER_OFFSET;
if (c == RUSSIAN_SMALL_LETTER_OFFSET) {
suffixN /= 34;
continue;
}
if (c == DASH_CODE + RUSSIAN_SMALL_LETTER_OFFSET) c = DASH_CHAR; if (c == DASH_CODE + RUSSIAN_SMALL_LETTER_OFFSET) c = DASH_CHAR;
result = (char) c + result; result = (char) c + result;
suffixN /= 35; suffixN /= 34;
} }
long c = suffixN + RUSSIAN_SMALL_LETTER_OFFSET; long c = suffixN + RUSSIAN_SMALL_LETTER_OFFSET;
if (c == DASH_CODE + RUSSIAN_SMALL_LETTER_OFFSET) c = DASH_CHAR; if (c == DASH_CODE + RUSSIAN_SMALL_LETTER_OFFSET) c = DASH_CHAR;
@ -68,7 +98,6 @@ public class RussianSuffixDecoderEncoder {
int code = 0 + c; int code = 0 + c;
if (code == 45) return true; if (code == 45) return true;
code -= RUSSIAN_SMALL_LETTER_OFFSET; code -= RUSSIAN_SMALL_LETTER_OFFSET;
if (code == 34) return true;
if (code > 0 && code < 33) return true; if (code > 0 && code < 33) return true;
return false; return false;
} }

View File

@ -1,48 +1,100 @@
/**
* 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; package org.apache.lucene.russian.morphology;
import org.apache.lucene.russian.morphology.heuristic.SimpleSuffixHeuristic;
import org.apache.lucene.russian.morphology.dictonary.WordProccessor;
import org.apache.lucene.russian.morphology.dictonary.WordCard;
import org.apache.lucene.russian.morphology.dictonary.FlexiaModel; import org.apache.lucene.russian.morphology.dictonary.FlexiaModel;
import org.apache.lucene.russian.morphology.dictonary.WordCard;
import org.apache.lucene.russian.morphology.dictonary.WordProccessor;
import org.apache.lucene.russian.morphology.informations.Splitter;
import java.util.TreeMap;
import java.util.Set;
import java.util.HashSet;
import java.io.IOException; import java.io.IOException;
import java.util.*;
public class NewModel implements WordProccessor{ public class StatiticsCollector implements WordProccessor {
private TreeMap<String, Set<Heuristic>> inversIndex = new TreeMap<String,Set<Heuristic>>(); private TreeMap<String, Set<Heuristic>> inversIndex = new TreeMap<String, Set<Heuristic>>();
private Set<Heuristic> noramlSuffix = new HashSet<Heuristic>();
public void proccess(WordCard wordCard) throws IOException { public void proccess(WordCard wordCard) throws IOException {
String normalStringMorph = wordCard.getWordsFroms().get(0).getCode(); String normalStringMorph = wordCard.getWordsFroms().get(0).getCode();
String word = wordCard.getBase() + wordCard.getCanonicalSuffix();
if (word.contains("-")) return;
//if(wordCard.getBase()+)
for (FlexiaModel fm : wordCard.getWordsFroms()) { for (FlexiaModel fm : wordCard.getWordsFroms()) {
Heuristic heuristic = createEvristic(wordCard.getBase(), wordCard.getCanonicalSuffix(), fm, normalStringMorph); Heuristic heuristic = createEvristic(wordCard.getBase(), wordCard.getCanonicalSuffix(), fm, normalStringMorph);
String form = revertWord(fm.create(wordCard.getBase())); String form = revertWord(fm.create(wordCard.getBase()));
Set<Heuristic> suffixHeuristics = inversIndex.get(form); Set<Heuristic> suffixHeuristics = inversIndex.get(form);
if(suffixHeuristics == null){ if (suffixHeuristics == null) {
suffixHeuristics = new HashSet<Heuristic>(); suffixHeuristics = new HashSet<Heuristic>();
inversIndex.put(form,suffixHeuristics); inversIndex.put(form, suffixHeuristics);
} }
suffixHeuristics.add(heuristic); suffixHeuristics.add(heuristic);
} }
} }
public void printInfo(){ public void printInfo() throws IOException {
System.out.println("All ivers words " + inversIndex.size());
Map<Integer, Integer> dist = new TreeMap<Integer, Integer>();
Set<Heuristic> prevSet = null; Set<Heuristic> prevSet = null;
int count = 0; int count = 0;
for(Set<Heuristic> currentSet:inversIndex.values()){ for (String key : inversIndex.keySet()) {
if(!currentSet.equals(prevSet)){ Set<Heuristic> currentSet = inversIndex.get(key);
if (!currentSet.equals(prevSet)) {
Integer d = dist.get(key.length());
dist.put(key.length(), 1 + (d == null ? 0 : d));
prevSet = currentSet; prevSet = currentSet;
count++; count++;
for (Heuristic h : currentSet) {
noramlSuffix.add(h);
}
} }
} }
System.out.println("Word with diffirent rules " + count); System.out.println("Word with diffirent rules " + count);
System.out.println("All ivers words " + inversIndex.size());
System.out.println(dist);
System.out.println("Diffirent suffix counts " + noramlSuffix.size());
int maxLegth = Integer.MIN_VALUE;
for (Heuristic n : noramlSuffix) {
if (n.actualNormalSuffix.length() > maxLegth) maxLegth = n.actualNormalSuffix.length();
}
ArrayList<Heuristic> list = new ArrayList<Heuristic>(noramlSuffix);
//new FileWriter()
System.out.println("Max lenght " + maxLegth);
int[][] ints = new int[count][];
count = 0;
prevSet = null;
for (String key : inversIndex.keySet()) {
Set<Heuristic> currentSet = inversIndex.get(key);
if (!currentSet.equals(prevSet)) {
ints[count] = RussianSuffixDecoderEncoder.encodeToArray(key);
count++;
prevSet = currentSet;
}
}
Splitter splitter = new Splitter(ints);
splitter.writeToFile("sep.txt");
} }
private String revertWord(String s){ private String revertWord(String s) {
String result = ""; String result = "";
for (int i = 1; i <= s.length(); i++) { for (int i = 1; i <= s.length(); i++) {
result += s.charAt(s.length() - i); result += s.charAt(s.length() - i);
@ -69,7 +121,7 @@ public class NewModel implements WordProccessor{
} }
private class Heuristic{ private class Heuristic {
Integer actualSuffixLengh; Integer actualSuffixLengh;
String actualNormalSuffix; String actualNormalSuffix;
String formMorphInfo; String formMorphInfo;

View File

@ -1,13 +1,33 @@
/**
* 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; package org.apache.lucene.russian.morphology;
import org.apache.lucene.russian.morphology.dictonary.GrammaReader;
import java.io.IOException; import java.io.IOException;
/**
* Created by IntelliJ IDEA.
* User: akuznetsov
* Date: 15.08.2009
* Time: 16:52:24
* To change this template use File | Settings | File Templates.
*/
public class Test { public class Test {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
GrammaReader grammaReader = new GrammaReader("dictonary/Dicts/Morph/rgramtab.tab"); //Splitter splitter = new Splitter("sep.txt");
//System.out.println(grammaReader.getInversIndex().size()); System.in.read();
} }
} }

View File

@ -58,19 +58,19 @@ public class SuffixHeuristic {
} }
public String getCanonicalForm(String form) { public String getCanonicalForm(String form) {
int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0; int startSymbol = form.length() > RussianSuffixDecoderEncoder.SUFFIX_LENGTH ? form.length() - RussianSuffixDecoderEncoder.SUFFIX_LENGTH : 0;
String suffixS = form.substring(startSymbol); String suffixS = form.substring(startSymbol);
if (!chechSuffix(suffixS)) return form; if (!chechSuffix(suffixS)) return form;
Long suffix = RussianSuffixDecoderEncoder.encode(suffixS); Integer suffix = RussianSuffixDecoderEncoder.encode(suffixS);
int index = Arrays.binarySearch(keys, suffix); int index = Arrays.binarySearch(keys, suffix);
if (index < -1) { if (index < -1) {
System.out.println(" " + form); System.out.println(" " + form);
return form; return form;
} else { } else {
String nSuffix = RussianSuffixDecoderEncoder.decode(values[index]); String nSuffix = RussianSuffixDecoderEncoder.decode((int) values[index]);
return startSymbol > 0 ? form.substring(0, startSymbol) + nSuffix : nSuffix; return startSymbol > 0 ? form.substring(0, startSymbol) + nSuffix : nSuffix;
} }
} }

View File

@ -1,13 +1,29 @@
/**
* 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.dictonary; package org.apache.lucene.russian.morphology.dictonary;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//todo spleet this class on two. //todo spleet this class on two.
public class GrammaReader { public class GrammaReader {

View File

@ -1,77 +0,0 @@
/**
* 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;
import org.apache.lucene.russian.morphology.RussianSuffixDecoderEncoder;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.TreeMap;
public class Heuristic {
private TreeMap<Long, Long> encodedSuffixesPairs = new TreeMap<Long, Long>();
public void addHeuristic(SimpleSuffixHeuristic simpleSuffixHeuristic) {
// Long suffix = RussianSuffixDecoderEncoder.encode(simpleSuffixHeuristic.getFormSuffix());
// Long longs = encodedSuffixesPairs.get(suffix);
// if (longs == null) {
// encodedSuffixesPairs.put(suffix, RussianSuffixDecoderEncoder.encode(simpleSuffixHeuristic.getNormalSuffix()));
// }
}
public String getNormalForm(String form) {
int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0;
Long suffix = RussianSuffixDecoderEncoder.encode(form.substring(startSymbol));
Long normalSuffix = encodedSuffixesPairs.get(suffix);
if (normalSuffix != null) {
String nSuffix = RussianSuffixDecoderEncoder.decode(normalSuffix);
return startSymbol > 0 ? form.substring(0, startSymbol) + nSuffix : nSuffix;
}
return form;
}
public Integer getAmount() {
return encodedSuffixesPairs.size();
}
public void readFromFile(String file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(file));
String s = reader.readLine();
while (s != null) {
String[] sfns = s.split(" ");
if (sfns.length == 2) {
encodedSuffixesPairs.put(Long.valueOf(sfns[0]), Long.valueOf(sfns[0]));
}
s = reader.readLine();
}
reader.close();
}
public void writeToFile(String file) throws IOException {
FileWriter writer = new FileWriter(file);
writer.write(encodedSuffixesPairs.size() + "\n");
for (Long k : encodedSuffixesPairs.keySet()) {
writer.write("" + k + " " + encodedSuffixesPairs.get(k) + "\n");
}
writer.close();
}
}

View File

@ -1,89 +0,0 @@
package org.apache.lucene.russian.morphology.heuristic;
import org.apache.lucene.russian.morphology.RussianSuffixDecoderEncoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class HeuristicBySuffixLegth {
private Map<Long, Set<SimpleSuffixHeuristic>> heuristics = new HashMap<Long, Set<SimpleSuffixHeuristic>>();
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);
}
simpleSuffixHeuristics.add(simpleSuffixHeuristic);
}
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.getNormalSuffix();
Integer suffixLenght = heuristic.getActualSuffixLength();
String normalFormMorphInfo = heuristic.getNormalFormMorphInfo();
Boolean result = true;
for (SimpleSuffixHeuristic ssh : sshs) {
result = result &&
ssh.getActualSuffixLength().equals(suffixLenght) &&
ssh.getNormalSuffix().equals(normalSuffix) &&
ssh.getNormalFormMorphInfo().equals(normalFormMorphInfo);
}
return result;
}
}

View File

@ -1,97 +0,0 @@
/**
* 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;
private String normalFormMorphInfo;
public SimpleSuffixHeuristic(String formSuffix, Integer actualSuffixLength, String normalSuffix, String morphInfoCode, String normalFormMorphInfo) {
this.formSuffix = formSuffix;
this.actualSuffixLength = actualSuffixLength;
this.normalSuffix = normalSuffix;
this.morphInfoCode = morphInfoCode;
this.normalFormMorphInfo = normalFormMorphInfo;
}
public String getFormSuffix() {
return formSuffix;
}
public Integer getActualSuffixLength() {
return actualSuffixLength;
}
public String getNormalSuffix() {
return normalSuffix;
}
public String getMorphInfoCode() {
return morphInfoCode;
}
public String getNormalFormMorphInfo() {
return normalFormMorphInfo;
}
public void setNormalFormMorphInfo(String normalFormMorphInfo) {
this.normalFormMorphInfo = normalFormMorphInfo;
}
@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;
if (normalFormMorphInfo != null ? !normalFormMorphInfo.equals(that.normalFormMorphInfo) : that.normalFormMorphInfo != 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);
result = 31 * result + (normalFormMorphInfo != null ? normalFormMorphInfo.hashCode() : 0);
return result;
}
@Override
public String toString() {
return formSuffix + " " + actualSuffixLength + " " + normalSuffix + " " + morphInfoCode + " nf " + normalFormMorphInfo;
}
}

View File

@ -1,86 +0,0 @@
/**
* 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;
import org.apache.lucene.russian.morphology.RussianSuffixDecoderEncoder;
import org.apache.lucene.russian.morphology.dictonary.FlexiaModel;
import org.apache.lucene.russian.morphology.dictonary.WordCard;
import org.apache.lucene.russian.morphology.dictonary.WordProccessor;
import java.util.HashMap;
import java.util.Map;
public class StatiticsCollectors implements WordProccessor {
Map<SimpleSuffixHeuristic, SuffixCounter> statititics = new HashMap<SimpleSuffixHeuristic, SuffixCounter>();
private Map<String, Double> wordsFreq;
public StatiticsCollectors(Map<String, Double> wordsFreq) {
this.wordsFreq = wordsFreq;
}
private Integer ignoredCount = 0;
public void proccess(WordCard wordCard) {
String normalStringMorph = wordCard.getWordsFroms().get(0).getCode();
for (FlexiaModel fm : wordCard.getWordsFroms()) {
SimpleSuffixHeuristic simpleSuffixHeuristic = createEvristic(wordCard.getBase(), wordCard.getCanonicalSuffix(), fm, normalStringMorph);
if (simpleSuffixHeuristic == null) continue;
SuffixCounter suffixCounter = statititics.get(simpleSuffixHeuristic);
if (suffixCounter == null) {
suffixCounter = new SuffixCounter(simpleSuffixHeuristic);
statititics.put(simpleSuffixHeuristic, suffixCounter);
}
Double freq = wordsFreq.get(wordCard.getCanonicalFrom());
if (freq != null) {
suffixCounter.incrementAmount(1 + Math.log(freq));
} else {
suffixCounter.incrementAmount();
}
}
}
public Map<SimpleSuffixHeuristic, SuffixCounter> getStatititics() {
return statititics;
}
private SimpleSuffixHeuristic createEvristic(String wordBase, String canonicalSuffix, FlexiaModel fm, String normalSuffixForm) {
String form = fm.create(wordBase);
int startSymbol = form.length() > RussianSuffixDecoderEncoder.suffixLength ? form.length() - RussianSuffixDecoderEncoder.suffixLength : 0;
String formSuffix = form.substring(startSymbol);
String normalForm = wordBase + canonicalSuffix;
Integer length = getCommonLength(form, normalForm);
Integer actualSuffixLengh = form.length() - length;
String actualNormalSuffix = normalForm.substring(length);
return new SimpleSuffixHeuristic(formSuffix, actualSuffixLengh, actualNormalSuffix, fm.getCode(), normalSuffixForm);
}
public static Integer getCommonLength(String s1, String s2) {
Integer length = Math.min(s1.length(), s2.length());
for (int i = 0; i < length; i++) {
if (s1.charAt(i) != s2.charAt(i)) return i;
}
return length;
}
public Integer getIgnoredCount() {
return ignoredCount;
}
}

View File

@ -1,64 +0,0 @@
/**
* 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;
/**
* Conains information of freqency of suffix evristic
* in dictionary.
*/
public class SuffixCounter implements Comparable {
private SimpleSuffixHeuristic simpleSuffixHeuristic;
private Double amnout = 0.0;
public SuffixCounter(SimpleSuffixHeuristic simpleSuffixHeuristic) {
this.simpleSuffixHeuristic = simpleSuffixHeuristic;
}
public void incrementAmount() {
amnout++;
}
public void incrementAmount(Double wordFreq) {
amnout += wordFreq;
}
public SimpleSuffixHeuristic getSuffixHeuristic() {
return simpleSuffixHeuristic;
}
public void setSuffixEvristic(SimpleSuffixHeuristic simpleSuffixHeuristic) {
this.simpleSuffixHeuristic = simpleSuffixHeuristic;
}
public Double getAmnout() {
return amnout;
}
public void setAmnout(Double amnout) {
this.amnout = amnout;
}
public int compareTo(Object o) {
if (o instanceof SuffixCounter) return (int) Math.round(Math.signum(((SuffixCounter) o).amnout - amnout));
return -1;
}
@Override
public String toString() {
return "" + amnout + " " + simpleSuffixHeuristic.toString();
}
}

View File

@ -1,10 +0,0 @@
package org.apache.lucene.russian.morphology.heuristic;
public class SuffixHeuristic {
private SuffixTypes suffixType;
private Byte suffixLengh;
private Short indexOfWordTransorm;
private Short indexOfMothInfo;
}

View File

@ -1,8 +0,0 @@
package org.apache.lucene.russian.morphology.heuristic;
public enum SuffixTypes {
SINGLE,
DIFFIRENT_MORPH,
ONONIMS
}

View File

@ -1,16 +1,32 @@
/**
* 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.informations; package org.apache.lucene.russian.morphology.informations;
import java.io.Serializable; import java.io.Serializable;
public class GrammaInfo implements Serializable{ public class GrammaInfo implements Serializable {
private String[] grammaInfo; private String[] grammaInfo;
public GrammaInfo(String[] grammaInfo) { public GrammaInfo(String[] grammaInfo) {
this.grammaInfo = grammaInfo; this.grammaInfo = grammaInfo;
} }
public String getInfo(Integer index){ public String getInfo(Integer index) {
return grammaInfo[index]; return grammaInfo[index];
} }
} }

View File

@ -1,16 +1,32 @@
/**
* 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.informations; package org.apache.lucene.russian.morphology.informations;
import java.io.Serializable; import java.io.Serializable;
public class NormalSuffixCollection implements Serializable{ public class NormalSuffixCollection implements Serializable {
private String[] normalSuffixes; private String[] normalSuffixes;
public NormalSuffixCollection(String[] normalSuffixes) { public NormalSuffixCollection(String[] normalSuffixes) {
this.normalSuffixes = normalSuffixes; this.normalSuffixes = normalSuffixes;
} }
public String getSuffix(Integer index){ public String getSuffix(Integer index) {
return normalSuffixes[index]; return normalSuffixes[index];
} }
} }

View File

@ -0,0 +1,47 @@
package org.apache.lucene.russian.morphology.informations;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Splitter {
int[][] separators;
public Splitter(String fileName) throws IOException {
readFromFile(fileName);
}
public Splitter(int[][] separators) {
this.separators = separators;
}
public void writeToFile(String fileName) throws IOException {
FileWriter writer = new FileWriter(fileName);
writer.write(separators.length + "\n");
for (int[] i : separators) {
writer.write(i.length + "\n");
for (int j : i) {
writer.write(j + "\n");
}
}
writer.close();
}
public void readFromFile(String fileName) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));
String s = bufferedReader.readLine();
Integer amount = Integer.valueOf(s);
separators = new int[amount][];
for (int i = 0; i < amount; i++) {
String s1 = bufferedReader.readLine();
Integer wordLenght = Integer.valueOf(s1);
separators[i] = new int[wordLenght];
for (int j = 0; j < wordLenght; j++) {
separators[i][j] = Integer.valueOf(bufferedReader.readLine());
}
}
bufferedReader.close();
}
}

View File

@ -35,12 +35,25 @@ public class RussianSuffixDecoderEncoderTest {
String s = bufferedReader.readLine(); String s = bufferedReader.readLine();
while (s != null) { while (s != null) {
String[] qa = s.trim().split(" "); String[] qa = s.trim().split(" ");
Long ecodedSuffix = RussianSuffixDecoderEncoder.encode(qa[0]); Integer ecodedSuffix = RussianSuffixDecoderEncoder.encode(qa[0]);
assertThat(RussianSuffixDecoderEncoder.decode(ecodedSuffix), equalTo(qa[1])); assertThat(RussianSuffixDecoderEncoder.decode(ecodedSuffix), equalTo(qa[1]));
s = bufferedReader.readLine(); s = bufferedReader.readLine();
} }
} }
@Test
public void testShouldCorretDecodeEncodeStringToArray() throws IOException {
InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/decoder-test-data-for-array.txt");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
String s = bufferedReader.readLine();
while (s != null) {
String[] qa = s.trim().split(" ");
int[] ecodedSuffix = RussianSuffixDecoderEncoder.encodeToArray(qa[0]);
assertThat(RussianSuffixDecoderEncoder.decodeArray(ecodedSuffix), equalTo(qa[1]));
s = bufferedReader.readLine();
}
}
@Test(expected = SuffixToLongException.class) @Test(expected = SuffixToLongException.class)
public void shouldThrownExeptionIfSuffixToLong() { public void shouldThrownExeptionIfSuffixToLong() {
RussianSuffixDecoderEncoder.encode("1234567890123"); RussianSuffixDecoderEncoder.encode("1234567890123");

View File

@ -1,15 +1,22 @@
/**
* 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; package org.apache.lucene.russian.morphology;
import org.junit.Test; 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; import java.io.IOException;
@ -17,29 +24,29 @@ public class SpeedTest {
@Test @Test
public void getTestOfSpeed() throws IOException { public void getTestOfSpeed() throws IOException {
Long startTime = System.currentTimeMillis(); // Long startTime = System.currentTimeMillis();
RussianMorphlogyAnalayzer morphlogyAnalayzer = new RussianMorphlogyAnalayzer(); // RussianMorphlogyAnalayzer morphlogyAnalayzer = new RussianMorphlogyAnalayzer();
System.out.println("To build analayzer take " + (System.currentTimeMillis() - startTime) + " ms."); // System.out.println("To build analayzer take " + (System.currentTimeMillis() - startTime) + " ms.");
InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/text.txt"); // InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/text.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); // BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
//
//
final Token reusableToken = new Token(); // final Token reusableToken = new Token();
//
Token nextToken; // Token nextToken;
//
//
startTime = System.currentTimeMillis(); // startTime = System.currentTimeMillis();
Integer count = 0; // Integer count = 0;
TokenStream in = morphlogyAnalayzer.tokenStream(null, reader); // TokenStream in = morphlogyAnalayzer.tokenStream(null, reader);
for (; ;) { // for (; ;) {
nextToken = in.next(reusableToken); // nextToken = in.next(reusableToken);
count++; // count++;
if (nextToken == null) { // if (nextToken == null) {
break; // break;
} // }
//
} // }
System.out.println("It takes " + (System.currentTimeMillis() - startTime) + " ms. To proccess " + count + " words." ); // System.out.println("It takes " + (System.currentTimeMillis() - startTime) + " ms. To proccess " + count + " words." );
} }
} }

View File

@ -16,45 +16,38 @@
package org.apache.lucene.russian.morphology.analayzer; package org.apache.lucene.russian.morphology.analayzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import org.junit.Test; import org.junit.Test;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class RussianMorphlogyAnalayzerTest { public class RussianMorphlogyAnalayzerTest {
@Test @Test
public void shouldCorrectProccessText() throws IOException { public void shouldCorrectProccessText() throws IOException {
RussianMorphlogyAnalayzer morphlogyAnalayzer = new RussianMorphlogyAnalayzer(); // RussianMorphlogyAnalayzer morphlogyAnalayzer = new RussianMorphlogyAnalayzer();
InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/analayzer/russian-text.txt"); // InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/analayzer/russian-text.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); // BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
//
InputStream tokeStream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/analayzer/token-of-russian-text.txt"); // InputStream tokeStream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/analayzer/token-of-russian-text.txt");
BufferedReader tokenReader = new BufferedReader(new InputStreamReader(tokeStream, "UTF-8")); // BufferedReader tokenReader = new BufferedReader(new InputStreamReader(tokeStream, "UTF-8"));
//
final Token reusableToken = new Token(); // final Token reusableToken = new Token();
//
Token nextToken; // Token nextToken;
//
//
TokenStream in = morphlogyAnalayzer.tokenStream(null, reader); // TokenStream in = morphlogyAnalayzer.tokenStream(null, reader);
for (; ;) { // for (; ;) {
nextToken = in.next(reusableToken); // nextToken = in.next(reusableToken);
//
if (nextToken == null) { // if (nextToken == null) {
break; // break;
} // }
//
assertThat(nextToken.term(), equalTo(tokenReader.readLine().trim())); // assertThat(nextToken.term(), equalTo(tokenReader.readLine().trim()));
//
} // }
} }
} }

View File

@ -16,28 +16,23 @@
package org.apache.lucene.russian.morphology.analayzer; package org.apache.lucene.russian.morphology.analayzer;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
import org.junit.Test; import org.junit.Test;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class SuffixHeuristicTest { public class SuffixHeuristicTest {
@Test @Test
public void testShouldDefineCorretCononicalWordForm() throws IOException { public void testShouldDefineCorretCononicalWordForm() throws IOException {
SuffixHeuristic suffixHeuristic = new SuffixHeuristic(); // SuffixHeuristic suffixHeuristic = new SuffixHeuristic();
InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/analayzer/suffix-heuristic-test-data.txt"); // InputStream stream = this.getClass().getResourceAsStream("/org/apache/lucene/russian/morphology/analayzer/suffix-heuristic-test-data.txt");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); // BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
String s = bufferedReader.readLine(); // String s = bufferedReader.readLine();
while (s != null) { // while (s != null) {
String[] qa = s.trim().split(" "); // String[] qa = s.trim().split(" ");
assertThat(suffixHeuristic.getCanonicalForm(qa[0]), equalTo(qa[1])); // assertThat(suffixHeuristic.getCanonicalForm(qa[0]), equalTo(qa[1]));
s = bufferedReader.readLine(); // s = bufferedReader.readLine();
} // }
} }
} }

View File

@ -0,0 +1,46 @@
/**
* 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.utils;
import org.junit.Test;
public class UtilsTest {
@Test
public void testCompate() {
System.out.println((byte) 255);
//
// assertThat(Utils.compate((byte)3,(byte)2),equalTo(1));
// assertThat(Utils.compate((byte)2,(byte)3),equalTo(-1));
// assertThat(Utils.compate((byte)200,(byte)2),equalTo(1));
// assertThat(Utils.compate((byte)2,(byte)200),equalTo(-1));
// assertThat(Utils.compate((byte)255,(byte)254),equalTo(1));
// assertThat(Utils.compate((byte)254,(byte)255),equalTo(-1));
// assertThat(Utils.compate((byte)200,(byte)200),equalTo(0));
// assertThat(Utils.compate((byte)2,(byte)2),equalTo(0));
}
@Test
public void testStringTyByteArray() {
// Add your code here
}
@Test
public void testByteArrayToString() {
// Add your code here
}
}

View File

@ -0,0 +1,13 @@
тест тест
ёж еж
естера естера
что-то что-то
а а
яяяяяя яяяяяя
яяяя яяяя
аа аа
аааааа аааааа
аааааааааааа аааааааааааа
аааааааааааааааааа аааааааааааааааааа
ааааааааааааааааа ааааааааааааааааа
йфячыцувс йфячыцувс

View File

@ -1,4 +1,8 @@
тест тест тест тест
ёж еж ёж еж
тестера тестера естера естера
что-то что-то что-то что-то
а а
яяяяяя яяяяяя
яяяя яяяя
аа аа