Skip to main content

Высокопроизводительный морфологический анализатор для Python

Project description

steosmorphy: Руководство пользователя

steosmorphy — это высокопроизводительный морфологический анализатор для русского языка, предоставляющий Python-интерфейс к ядру, написанному на Go.

Исходный код:

Ключевые особенности

  • Знакомый API: Интерфейс и возможности во многом вдохновлены pymorphy2.
  • Полный функционал: Включает разбор, лемматизацию, генерацию всех словоформ и предсказание несловарных слов.
  • Корректная обработка супплетивизма: Правильно генерирует все формы для слов вроде хороший -> лучший.
  • Высокая производительность: Скорость анализа составляет ~100 микросекунд на слово (~10 000 слов/сек на одном ядре CPU).
  • При использовании пакетной обработки слов скорость достигает до ~20 микросекунд за одно слово

Оглавление


1. Установка

Библиотека устанавливается из PyPI стандартной командой:

pip install steosmorphy

Пакет содержит уже скомпилированные бинарные файлы для операционных систем (Windows, Linux, macOS), поэтому установка Go не требуется.


2. Быстрый старт

Использовать библиотеку очень просто.

from steosmorphy import MorphAnalyzer

# 1. Инициализируем анализатор.
# Словарь загружается автоматически при первом создании объекта.
analyzer = MorphAnalyzer()

# 2. Анализируем слово
word = "стали"
result = analyzer.analyze(word)

# 3. Работаем с результатом
print(f"Варианты разбора для слова '{word}':")

# `result.parses` - это список всех возможных разборов
for p in result.parses:
    print(f"  - Лемма: {p.lemma:<10} Часть речи: {p.part_of_speech:<15} Падеж: {p.case}")

# `result.forms` - это список всех словоформ (лексема)
print(f"\nПримеры словоформ для '{word}':")
for p in result.forms[:5]: # Ограничим вывод
    print(f"  - {p.word}")

3. API и объекты результата

3.1. Метод analyze

Он принимает на вход слово и возвращает объект AnalysisResult, содержащий полный анализ. Если слово не найдено в словаре и не может быть предсказано, метод вернет None.

analyzer.analyze(word: str) -> AnalysisResult | None

3.2. Метод (parse_list)

Для достижения максимальной производительности при обработке большого количества слов используйте метод parse_list.

analyzer.parse_list(words: list[str]) -> list[Parsed]

Этот метод принимает на вход список слов, передает его целиком в ядро на Go, где он обрабатывается в многопоточном режиме, и возвращает единый список всех возможных разборов.

Почему это важно? Каждый вызов analyze из Python несет в себе накладные расходы на "пересечение границы" между Python и Go. Метод parse_list пересекает эту границу всего один раз для всего списка, что приводит к многократному (в 5-10 раз) ускорению по сравнению с вызовом analyze в цикле.

Пример использования:

words = ["мама", "мыла", "раму", "стали", "программистка", "хороший"]

# Вызываем пакетную обработку
all_parses = analyzer.parse_list(words)

# `all_parses` - это плоский список всех разборов
# (для "стали" будет два объекта, итого 7)
for p in all_parses:
    print(f"Слово: {p.word:<15} Лемма: {p.lemma:<15} ЧР: {p.part_of_speech}")

Рекомендация: Всегда используйте parse_list, если вам нужно обработать более одного слова. Вызов analyze в цикле следует применять только для анализа единичных, интерактивно вводимых слов.

ОСТОРОЖНО Передача на вход метода слишком большого числа слов может потребовать большого объема оперативной памяти во время работы метода. Например, использование списка из 1 000 000 может использовать свыше 5ГБ ОЗУ!

3.3. Метод (inflect_list)

Работает аналогичным образом с методом parse_list, но возвращает список всех словоформ для каждого слова из входного списка.

analyzer.inflect_list(words: list[str]) -> list[Parsed]

3.4. Объект AnalysisResult

Это контейнер для всего результата анализа.

  • .parses (list[Parsed]) Список объектов Parsed, представляющих все возможные варианты разбора для исходного слова.

  • .forms (list[Parsed]) Список объектов Parsed, представляющих все словоформы (полную лексему) для исходного слова.

  • .first (Parsed | None) Удобный доступ к первому (самому вероятному) варианту разбора из списка .parses. Эквивалентно result.parses[0].

3.5. Объект Parsed

Каждый *Parsed — это объект, содержащий полный разбор одной словоформы с доступом к полям через точку.

  • .word (str): Сама словоформа.
  • .lemma (str): Нормальная (словарная) форма.
  • .tags (str): "Сырая" строка тегов для отладки.
  • .part_of_speech (str): Часть речи.
  • .animacy (str): Одушевленность.
  • .aspect (str): Вид глагола.
  • .case (str): Падеж.
  • .gender (str): Род.
  • .mood (str): Наклонение.
  • .number (str): Число.
  • .person (str): Лицо.
  • .tense (str): Время.
  • .transitivity (str): Переходность.
  • .voice (str): Залог.
  • .other_tags (set[str]): Множество прочих тегов.

4. Примеры использования

4.1. Разбор неоднозначности

Многие слова в русском языке неоднозначны. analyze вернет все варианты в списке .parses.

result = analyzer.analyze("стекла")

for p in result.parses:
    if p.part_of_speech == "Глагол":
        print(f"Это глагол '{p.lemma}' в форме {p.gender} рода, {p.tense} времени.")
        # -> Это глагол 'стечь' в форме Средний рода, Прошедшее времени.
    elif p.part_of_speech == "Существительное":
        print(f"Это существительное '{p.lemma}' в {p.case} падеже.")
        # -> Это существительное 'стекло' в Родительный падеже.

4.2. Генерация словоформ и супплетивизм

Список .forms содержит полную лексему слова, включая формы, образованные от разных корней.

result = analyzer.analyze("хорошая")

# `result.forms` будет содержать *полную* лексему
all_forms = {p.word for p in result.forms}

print("лучший" in all_forms)  # -> True
print("хорошую" in all_forms) # -> True

4.3. Работа с несловарными словами

Если слово не найдено в словаре, анализатор автоматически пытается его предсказать.

result = analyzer.analyze("нейросеть")
p = result.first

print(p.lemma)          # -> нейросеть
print(p.part_of_speech) # -> Существительное
print(p.gender)         # -> Женский

# Будут также сгенерированы все предсказанные словоформы
forms = {f.word for f in result.forms}
print("нейросетей" in forms) # -> True

5. Производительность

steosmorphy спроектирован для высокой производительности.

  • Скорость (одно слово): Среднее время анализа одного слова через analyze() составляет около ~100 микросекунд.
  • Память: Потребление оперативной памяти остается стабильно низким (~100-150 МБ).
  • Пакетная обработка: При использовании методов parse_list() / inflect_list() среднее время на слово приближается к нативным ~20 микросекундам, что позволяет обрабатывать до 50 000 слов в секунду на одном ядре CPU.

---

## 6. Тестирование

#### Требования для тестов Python

Перед запуском убедитесь, что вы установили все необходимые зависимости для разработки:
```bash
pip install pytest pytest-benchmark

Также убедитесь, что ваш пакет steosmorphy установлен, желательно в режиме редактирования:

pip install -e .

Юнит- и интеграционные тесты

Файл tests/test_analyzer.py содержит тесты, которые проверяют корректность разбора и генерации словоформ.

Как запустить: Находясь в корне проекта, выполните команду:

pytest

pytest автоматически найдет и запустит все тесты. Для подробного вывода используйте флаги -v (verbose) и -s (чтобы видеть вывод print).

Нагрузочные тесты и бенчмарки

  • Микро-бенчмарки (tests/test_benchmark.py): Измеряют точное время выполнения одного вызова analyze для разных типов слов. Запускаются с помощью плагина pytest-benchmark.

    Как запустить:

    pytest --benchmark-only
    

    Вы увидите подробную статистическую таблицу со средним, медианным, минимальным и максимальным временем выполнения.

  • Нагрузочные тесты (tests/test_load.py): Эмулируют реальную нагрузку, прогоняя через анализатор сотни тысяч и миллионы случайных слов. Эти тесты измеряют общую "пропускную способность" (слов в секунду) и помогают выявить утечки памяти или деградацию производительности под нагрузкой.

    Как запустить:

    pytest -v -s tests/test_load.py
    

Наличие такой всеобъемлющей тестовой системы позволяет гарантировать высокое качество и надежность библиотеки steosmorphy.


7. Зависимости и окружение

Для работы библиотеки (Runtime)

Конечный пользователь, устанавливающий ваш пакет через pip, не нуждается ни в каких внешних зависимостях, так как все необходимое встроено в Python.

  • Python: Требуется версия Python 3.7 или новее.
  • Используемые стандартные библиотеки:
    • ctypes: Для взаимодействия со скомпилированной Go-библиотекой (.dll/.so).
    • json: Для десериализации результатов, полученных от Go.
    • platform: Для определения операционной системы и выбора правильного файла библиотеки.
    • importlib.resources: Для надежного поиска файлов (.dll, .dawg) внутри установленного пакета.

Для разработки и тестирования (Development)

Если вы хотите вносить изменения или запускать тесты, вам понадобятся следующие инструменты:

  • pytest: Мощный фреймворк для написания и запуска юнит-тестов и интеграционных тестов.
  • pytest-benchmark: Плагин для pytest для проведения тестов производительности (микро-бенчмарков).

Установить их можно командой:

pip install pytest pytest-benchmark

8. Справочник по граммемам

Каждый успешный разбор слова возвращается в виде объекта Parsed. Этот раздел подробно описывает каждое поле этого объекта и возможные значения, которые оно может принимать.

Основные поля

  • word (str) Исходная словоформа, которая была передана на анализ или сгенерирована. Пример: "коту", "стали", "хорошая".

  • lemma (str) Нормальная форма слова. Для существительных — именительный падеж, единственное число. Для глаголов — инфинитив. Для прилагательных — именительный падеж, единственное число, мужской род. Пример: "кот", "стать", "хороший".

  • tags (string) Все грамматические теги в виде строки, разделенных запятой. Полезна для отладки или для случаев, когда требуется полный набор граммем в одной строке. Пример: "Существительное,Одушевленное,Мужской,Единственное число,Дательный".

Грамматические категории

  • part_of_speech (str) Часть речи. Это основная категория слова.

    • Существительное
    • Прилагательное
    • Глагол
    • Наречие
    • Причастие
    • Деепричастие
    • Местоимение
    • Числительное
    • Предлог
    • Частица
    • Союз
    • Междометие
    • Вводное слово
  • animacy (str) Одушевленность. Категория, присущая существительным и согласующимся с ними частям речи.

    • Одушевленное
    • Неодушевленное
  • aspect (str) Вид. Характеристика глаголов, причастий и деепричастий.

    • Совершенный
    • Несовершенный
    • Двувидовой
  • case (str) Падеж. Одна из ключевых характеристик для склоняемых частей речи.

    • Именительный
    • Родительный
    • Дательный
    • Винительный
    • Творительный
    • Предложный
    • Звательный (для обращений, напр., "боже")
    • Местный (напр., "в лесу")
    • Счетный (напр., "два часа")
    • Партитивный (напр., "чашка чаю")
    • Ждательный (специфический падеж, напр., "ждать письма")
    • Несклоняемый (для несклоняемых слов, напр., "пальто")
  • gender (str) Род.

    • Мужской
    • Женский
    • Средний
    • Общий (напр., "сирота", "умница")
    • Парный (используется для обозначения парных предметов, но редко встречается)
  • mood (str) Наклонение. Характеристика глагола.

    • Повелительное (indc - изъявительное - обычно опускается)
  • number (str) Число.

    • Единственное число
    • Множественное число
  • person (str) Лицо. Характеристика глаголов в настоящем/будущем времени и личных местоимений.

    • 1-е лицо (я, мы)
    • 2-е лицо (ты, вы)
    • 3-е лицо (он, она, оно, они)
    • нет лица (для безличных глаголов)
  • tense (str) Время. Характеристика глагола.

    • Прошедшее
    • Настоящее
    • Будущее
  • transitivity (str) Переходность. Способность глагола сочетаться с дополнением в винительном падеже без предлога.

    • Переходный
    • Непереходный
    • Лабильный (может быть и переходным, и непереходным)
  • voice (str) Залог. Характеристика причастий.

    • Действительный
    • Страдательный
  • other_tags (set[str]) Множество для всех остальных граммем, которые не попали в основные поля. Это позволяет сохранить всю информацию из исходного словаря. Примеры: "Краткая форма", "Сравнительная степень", "Имя собственное", "Фамилия", "Сокращение", "Разговорное" и т.д.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

steosmorphy-1.0.1.tar.gz (102.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

steosmorphy-1.0.1-py3-none-any.whl (102.9 MB view details)

Uploaded Python 3

File details

Details for the file steosmorphy-1.0.1.tar.gz.

File metadata

  • Download URL: steosmorphy-1.0.1.tar.gz
  • Upload date:
  • Size: 102.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for steosmorphy-1.0.1.tar.gz
Algorithm Hash digest
SHA256 411149a4340b94b23d2600377f6d6fbd0735af32492153a41578f711f26db8d2
MD5 78172ec5d484572b8dea5fcbce0c229d
BLAKE2b-256 90b7c5f464087449d430911dbff13a874f158398b2eff792d89fb75e8b9dee76

See more details on using hashes here.

File details

Details for the file steosmorphy-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: steosmorphy-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 102.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for steosmorphy-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3e06f93c773828fdb40e5af814108c9a85b98365ddda52ed79288b9f9de54c4b
MD5 44116f22d0b6d7def5b163918516ffb6
BLAKE2b-256 a672f9b234bf642080fad33d61f8e5dfb6cc9b94205ac22fb8e69fef69361455

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page