pymorphy2
pymorphy2 copied to clipboard
Теги на кириллице
Немного обсуждения тут: https://github.com/kmike/pymorphy2/issues/6
Хорошо бы понять, делать их или не делать; если не делать, то выпилить CyrillicOpencorporaTag; если делать - то как именно.
Мне кажется, хорошим вариантом было бы создание т. н. бэкендов для тегов.
Базовый бэкенд и он же по-умолчанию - OpencorporaTag
Национальные бэкенды - наследники OpencorporaTag или даже некие Прокси-классы.
В конфиге указываем путь к файлу/модулю-бэкенду. При инициализации скрипта оный импортируется и выполняет все необходимые преобразования - маппинг тегов в частности.
Бэкенд занимается только тем, что транслирует национальное представление граммем во внутреннее (латиница) на входе и обратно на выходе - а функции разбора уже выполняет OpencorporaTag
У такого метода есть огромный плюс - не нужно дублировать функционал. Но есть и минус - дополнительная сущность несколько снизит производительность.
В принципе что-то подобное, на сколько я понял, сейчас и сделано в CyrillicOpencorporaTag.
Но делать однозначно надо - ибо запоминать всю ту абракадабру в тегах нереально. Я кириллические-то постоянно с документацией сверяю в pymorphy, а латиница - вообще мрак.
UPD Почитал обсуждение и что-то меня терзают смутные сомненья...
Я в итоге конвертирую всё сам между "внутренним" английским и "внешним" русским: запоминать всё действительно нереально, и хочется, чтобы всё работало быстро, а постоянно конвертировать всё, а, тем более, доверять CyrillicOpencorporaTag это делать совершенно не хочется. Единственным быстрым выходом было бы хранить таблицу анкодов для разных языков непосредственно в словаре ancodes ( который содержит отображение id тега -> тег ) , генерируя этот словарь один раз после своего создания класса Tag-ов. А в идеале сделать нативную таблицу преобразований FastTag, позволяющую хранить основное морфологическое описание слова в типе int64 вместо frozenset и быстро вычислять свойства, чтобы, например, найти общий род и падеж для двух слов (если он выражен), или быстро сменить род и число на заданные. Тогда разные языки станут наследниками от FastTag.
Задумка с CyrillicOpencorporaTag была в том, что он ничего не конвертирует - там просто набор тегов другой (причем взятый тоже прямо из XML словаря), и производительность не страдает совсем.
Но текущая реализация архитектурно очень плохая, т.к. если ее использовать "на полную катушку", то мы уже не можем написать tag.gender == 'masc', ведь граммема будет зависеть от того, какой "бэкенд" ("класс тегов") активен. Получается, что граммемо-зависимый код писать нельзя (в.т.ч. в коде pymorphy2) - а как тогда, например, метод make_agree_with_number реализовывать. Мне кажется, это основная проблема с несколькими наборами граммем, и как-то ее красиво бы решить. Можно сделать, чтоб и для masc, и для мр возвращалось True, но это очень много магии, которая может сломаться в неожиданном для пользователя библиотеки месте (например, gender=str(tag.gender); gender == 'мр').
Если нужна только трансляция eng <-> cyr, то это просто сделать; мэппинг граммем уже сейчас парсится (и доступен как CyrillicOpencorporaTag._GRAMMEME_ALIAS_MAP, который генерируется при загрузке словаря). Один вариант - просто утащить этот мэппинг в класс OpencorporaTag (возможно, какой-то хелпер сделать еще для преобразования тегов целиком). Плохо в этом то, что тогда tag.gender == 'мр' и т.п. работать не будет - выйдет, что разработчику оба набора граммем нужно будет в голове держать.
С int64 - правда сильно быстрее множества что-ли? Это C/Cython расширение нужно, чтоб работало быстро, или из питона тоже? Я как-то настороженно к этой идее сейчас отношусь пока. У нас сейчас 4 тыс. frozenset'ов, которые создаются при первом обращении и потом кешируются, мне все кажется, что они быстрые должны быть и тормозить там особо нечему. И что менять у тегов число или род не нужно никогда, что иммутабельные теги (как сейчас) - это правильно. Есть какие-то конкретные примеры кусков кода, которые тормозят, или где нужны мутабельные теги?
С этим тикетом есть еще такая фишка: как начинаешь что-то про него делать, общаешься больше с английскими граммемами, и запоминаешь их поэтому более-менее, и делать тикет уже мотивации меньше :)
т.к. если ее использовать "на полную катушку", то мы уже не можем написать tag.gender == 'masc'
А зачем так писать? Прикладной код будет использовать или один бэкенд, или второй. Но вообще, если хочется, чтобы оба работали, то нужно независимое представление. И оно должно позволять любую комбинацию тегов. Получаем снова FastTag.
магии, которая может сломаться в неожиданном для пользователя библиотеки месте (например, gender=str(tag.gender); gender == 'мр')
Правильно это делается возвратом FastTag, который реализует операции equals и hash. Простейшая реализация FastTag -- это просто id записи в таблице ancodes, которых, как ты говоришь, порядка 4000. Внутренняя запись может быть на английском языке, но тогда нужно реализовать способ быстрого получения перевода.
Есть какие-то конкретные примеры кусков кода, которые тормозят, или где нужны мутабельные теги?
Почему, пусть они будут иммутабельные, операция создания другой формы может возвращать новый иммутабельный тег.
Ну, в общем, да, ты понимаешь ситуацию даже лучше нас, просто хотелось бы лучшую реализацию, которая позволяла бы забыты про английские теги совсем, если хочется, и не терять в скорости.
А зачем так писать?
Например, чтоб зашить правила согласования существительных с числительными. Хм, ну сейчас там все так отрефакторено, что нужные для этого граммемы сам класс OpencorporaTag возвращает. Но ограничиваться тем, что "явно указанные граммемы может использовать только OpencorporaTag" не хочется. Что делать с предсказателями, например, которые свои граммемы добавляют - они же не могут знать, какие классы для тегов есть, а классы для тегов не могут знать о всех предсказателях.
Правильно это делается возвратом FastTag, который реализует операции equals и hash.
Это не будет работать вот тут: gender=str(tag.gender); gender == 'мр', или вот тут будет неожиданный результат: "%s" % tag.gender. Граммемы уже сейчас магично-умные возвращаются (чтоб с опечатками бороться при сравнениях). Но несработавшая защита от опечаток vs неправильно отработавшее сравнение - это две большие разницы.
вот тут FastGrammeme тоже не будет работать, как ни пиши __hash__:
grammemes = {tag.gender, tag.voice}
'мр' in grammemes
upd: вру, будет
Это не будет работать вот тут: gender=str(tag.gender); gender == 'мр', или вот тут будет неожиданный результат: "%s" % tag.gender.
А оно должно там работать вообще? :)
Что делать с предсказателями, например, которые свои граммемы добавляют
А вот про это можно поподробнее? А то очень хотелось пару дней назад, чтобы прилагательное "один" стало числительным, а у всех числительных кроме "два", "три" и "четыре" была граммема множественного числа. Как раз согласование числительных и существительных описывать, да.
Ну gender=str(tag.gender); gender == 'masc' ведь сработает. Мало ли как все использоваться будет, магия она такая, сложно сказать, где аукнется.
С предсказателями - я с API до конца не определился, но MorphAnalyzer сейчас - "глупый" класс, весь разбор делается "юнитами", и некоторые из них свои граммемы добавляют. Например, во эти: https://github.com/kmike/pymorphy2/blob/master/pymorphy2/units/by_shape.py . Вот тут в ветке еще немного информации: http://habrahabr.ru/post/176575/#comment_6142869
Я почему не определился (и не документирую все): неясно, достаточно ли все гибко; неясно, где нужно проводить границу между токенизатором и морф. анализатором; неясно, нельзя ли проще сделать.
Я пока смерджил достаточно простую штуку - в классе OpencorporaTag теперь есть методы для преобразования строковых представлений тегов между кириллицей и латиницей (на основе данных из словаря).
Подразумевается, что кириллические названия граммем будут использоваться только в пользовательском интерфейсе, а "внутри" будут все те же латинские граммемы.
В TODO - удалить класс CyrillicOpencorporaTag.
А что насчет добавления "многих представлений"? Например в мультиязычном проекте я использую polyglot, а в нем части речи иногда названы не так как в pymorphy, например ADVB vs ADV
http://polyglot.readthedocs.org/en/latest/POS.html
И круто было бы добавить "имя собственное", которое в polyglot судя по всем определяется как proper noun (PROPN)
@imposeren тегсеты никогда не удается сматчить 1-к-1, с этим все очень плохо :) У меня ни разу не вышло. Мне кажется, лучше такие преобразования в библиотеки утаскивать. Для русского я https://github.com/kmike/russian-tagsets делал; там есть небольшой движок, чтоб правила в духе этого писать - может, поможет как-то.
Да, я пытался!
Могу поделиться решением для LanguageTool -> OpenCorpora.
2016-04-20 14:15 GMT+03:00 Mikhail Korobov [email protected]:
@imposeren https://github.com/imposeren тегсеты никогда не удается сматчить 1-к-1, с этим все очень плохо :) У меня ни разу не вышло. Мне кажется, лучше такие преобразования в библиотеки утаскивать. Для русского я https://github.com/kmike/russian-tagsets делал; там есть небольшой движок, чтоб правила в духе этого https://github.com/kmike/russian-tagsets/blob/194a02088cd28bcc948af9aa83d7b8aa61297553/russian_tagsets/ruscorpora.py#L30 писать - может, поможет как-то.
— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/kmike/pymorphy2/issues/9#issuecomment-212384605