From 80db07b0ca9b44a88069d34210fa1a9d67216f67 Mon Sep 17 00:00:00 2001 From: Daniil Demidko Date: Sun, 19 Sep 2021 08:58:56 +1000 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BB=20=D1=80=D0=B0=D1=81=D1=85?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=BF=D0=B0=D0=BC=D1=8F=D1=82=D0=B8=20=D0=B2=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +-- .../com/github/demidko/aot/BitReader.java | 101 ++++++++++++++++++ .../com/github/demidko/aot/BitWriter.java | 88 +++++++++++++++ ...utableWordList.java => ImmutableList.java} | 2 +- .../github/demidko/aot/WordformMeaning.java | 32 +++++- .../demidko/aot/HashDictionaryTest.java | 5 +- .../demidko/aot/WordformMeaningTest.java | 1 + 7 files changed, 230 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/github/demidko/aot/BitReader.java create mode 100644 src/main/java/com/github/demidko/aot/BitWriter.java rename src/main/java/com/github/demidko/aot/{ImmutableWordList.java => ImmutableList.java} (93%) diff --git a/README.md b/README.md index 046d6a3..b65f0ca 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Java библиотека для быстрого (!) получения лем [![](https://jitpack.io/v/demidko/aot.svg)](https://jitpack.io/#demidko/aot) -## Пример +## Как использовать? ```java import static java.lang.System.out; @@ -27,15 +27,15 @@ class Example { public static void main(String[] args) { var meanings = lookupForMeanings("люди"); - + out.println(meanings.size()); - /* 1 */ + /* 1 */ out.println(meanings.get(0).getMorphology()); - /* [С, мр, им, мн] */ + /* [С, мр, им, мн] */ out.println(meanings.get(0).getLemma()); - /* человек */ + /* человек */ for (var t : meanings.get(0).getTransformations()) { out.println(t.toString() + " " + t.getMorphology()); @@ -105,7 +105,7 @@ class Example { наконец, третий смысл, это вторая лемма, замокнуть (он что сделал? Он замок под дождем). Для нее слово замок характеризуется лишь одним набором грамматической информации. -## Источник данных +## Откуда данные? Используется словарь бинарной морфологии из проекта [aot-binary](https://github.com/demidko/aot-binary). diff --git a/src/main/java/com/github/demidko/aot/BitReader.java b/src/main/java/com/github/demidko/aot/BitReader.java new file mode 100644 index 0000000..b1a6a07 --- /dev/null +++ b/src/main/java/com/github/demidko/aot/BitReader.java @@ -0,0 +1,101 @@ +package com.github.demidko.aot; + +import static java.util.BitSet.valueOf; + +import java.util.BitSet; + +/** + * Класс предназначен для побитового чтения из примитивов + */ +public class BitReader { + + private final BitSet bs; + private int pos = -1; + + public BitReader(long... n) { + bs = valueOf(n); + } + + public BitReader(byte... b) { + bs = valueOf(b); + } + + public BitReader(BitReader other) { + bs = (BitSet) other.bs.clone(); + pos = other.pos; + } + + /** + * @return метод читает следующий по порядку бит + */ + public boolean readBit() { + return bs.get(++pos); + } + + /** + * Метод читает следующие N бит по порядку + * + * @param size количество бит + * @return биты сохраненные в длинное целое число + */ + public long readLong(int size) { + BitWriter w = new BitWriter(); + for (int i = 0; i < size; ++i) { + w.write(readBit()); + } + return w.toLong(); + } + + /** + * @return прочитать следующее длинное целое + */ + public long readLong() { + return readLong(64); + } + + /** + * Метод читает следующие N бит по порядку + * + * @param size количество бит + * @return биты сохраненные в целое число + */ + public int readInt(int size) { + return (int) readLong(size); + } + + /** + * @return прочитать следующее целое + */ + public int readInt() { + return readInt(32); + } + + + /** + * Метод читает следующие N бит по порядку + * + * @param size количество бит + * @return биты сохраненные в короткое целое число + */ + public short readShort(int size) { + return (short) readLong(size); + } + + public short readShort() { + return readShort(16); + } + + /** + * Метод читает следующие N бит по порядку + * + * @param size количество бит + * @return биты сохраненные в байт + */ + public byte readByte(int size) { + return (byte) readLong(size); + } + + public byte readByte() { + return readByte(8); + } +} diff --git a/src/main/java/com/github/demidko/aot/BitWriter.java b/src/main/java/com/github/demidko/aot/BitWriter.java new file mode 100644 index 0000000..2f45073 --- /dev/null +++ b/src/main/java/com/github/demidko/aot/BitWriter.java @@ -0,0 +1,88 @@ +package com.github.demidko.aot; + +import static java.util.BitSet.valueOf; + +import java.util.BitSet; + +/** + * Класс предназначен для побитовой записи в примитивы + */ +public class BitWriter { + + private final BitSet bs; + private int pos = -1; + + public BitWriter(byte... b) { + bs = valueOf(b); + } + + public BitWriter(long... l) { + bs = valueOf(l); + } + + public BitWriter() { + this(new byte[8]); + } + + public BitWriter(BitWriter other) { + bs = (BitSet) other.bs.clone(); + pos = other.pos; + } + + /** + * Метод записывает следующий по порядку бит + */ + public void write(boolean bit) { + bs.set(++pos, bit); + } + + /** + * Метод сохраняет результат записи в long + * + * @return результат записи + */ + public long toLong() { + return bs.toLongArray().length == 0 ? 0 : bs.toLongArray()[0]; + } + + public int toInt() { + return (int) toLong(); + } + + public short toShort() { + return (short) toLong(); + } + + public byte toByte() { + return (byte) toLong(); + } + + /** + * Метод записывает по порядку заданное количество бит + * + * @param bits набор бит + * @param len количество бит из набора + */ + public void write(long bits, int len) { + BitReader r = new BitReader(bits); + for (int i = 0; i < len; ++i) { + write(r.readBit()); + } + } + + public void writeLong(long l) { + write(l, 64); + } + + public void writeInt(int i) { + write(i, 32); + } + + public void writeShort(short s) { + write(s, 16); + } + + public void writeByte(byte b) { + write(b, 8); + } +} diff --git a/src/main/java/com/github/demidko/aot/ImmutableWordList.java b/src/main/java/com/github/demidko/aot/ImmutableList.java similarity index 93% rename from src/main/java/com/github/demidko/aot/ImmutableWordList.java rename to src/main/java/com/github/demidko/aot/ImmutableList.java index 59c4f7c..331f33e 100644 --- a/src/main/java/com/github/demidko/aot/ImmutableWordList.java +++ b/src/main/java/com/github/demidko/aot/ImmutableList.java @@ -6,7 +6,7 @@ import java.util.ListIterator; /** - * Чтобы не копировать лишний раз массивы + * Класс позволяет создать список меньшего размера, на основе массива большего размера, без копирования. */ class ImmutableList implements List { diff --git a/src/main/java/com/github/demidko/aot/WordformMeaning.java b/src/main/java/com/github/demidko/aot/WordformMeaning.java index 45ab713..28aefa6 100644 --- a/src/main/java/com/github/demidko/aot/WordformMeaning.java +++ b/src/main/java/com/github/demidko/aot/WordformMeaning.java @@ -22,7 +22,9 @@ public class WordformMeaning { * нужно использовать {@link WordformMeaning#getDictionary()}. */ private static HashDictionary dictionary; + private final int lemmaId; + private final int flexionIndex; private WordformMeaning(int lemmaId, int flexionIndex) { @@ -31,7 +33,19 @@ private WordformMeaning(int lemmaId, int flexionIndex) { } /** - * @return Исходная текстовая запись слова (может быть общей с другими смыслами, напр. "замок" и "замок"). + * @return Уникальный идентификатор, по которому можно восстановить словоформу, даже после перезапуска приложения. + * Идентификатор состоит из 48 бит (32 бита индекс леммы, 16 бит смещение трансформации) записанных по порядку в + * long. + */ + public long getId() { + BitWriter w = new BitWriter(); + w.write(lemmaId, 4); + w.write(flexionIndex, 4); + return w.toLong(); + } + + /** + * @return Текстовая запись слова (может быть общей с другими смыслами, напр. "замок" и "замок"). */ @Override public String toString() { @@ -80,9 +94,23 @@ public static List lookupForMeanings(String w) throws IOExcepti } /** + * @param id идентификатор полученный ранее при помощи {@link WordformMeaning#getId()} + * @return словоформа смысла + */ + public static WordformMeaning lookupForMeaningById(long id) throws IOException { + BitReader reader = new BitReader(id); + int lemmaId = reader.readInt(); + int flexionIndex = reader.readShort(); + getDictionary(); + return new WordformMeaning(lemmaId, flexionIndex); + } + + /** + * Инициализация {@link WordformMeaning#dictionary} + * * @return словарь лемм и морфологии (низкоуровневое API) */ - private static HashDictionary getDictionary() throws IOException { + static HashDictionary getDictionary() throws IOException { if (dictionary == null) { dictionary = new HashDictionary(); } diff --git a/src/test/java/com/github/demidko/aot/HashDictionaryTest.java b/src/test/java/com/github/demidko/aot/HashDictionaryTest.java index 4275648..c5f2714 100644 --- a/src/test/java/com/github/demidko/aot/HashDictionaryTest.java +++ b/src/test/java/com/github/demidko/aot/HashDictionaryTest.java @@ -1,5 +1,6 @@ package com.github.demidko.aot; +import static com.github.demidko.aot.WordformMeaning.getDictionary; import static java.util.stream.Collectors.toList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -12,11 +13,11 @@ public class HashDictionaryTest { - private static HashDictionary d = null; + private static HashDictionary d; static { try { - d = new HashDictionary(); + d = getDictionary(); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/test/java/com/github/demidko/aot/WordformMeaningTest.java b/src/test/java/com/github/demidko/aot/WordformMeaningTest.java index f53350b..a5f5143 100644 --- a/src/test/java/com/github/demidko/aot/WordformMeaningTest.java +++ b/src/test/java/com/github/demidko/aot/WordformMeaningTest.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.util.List; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test;