Русская морфология

berkut

Новичок
Жигaн
не, ну мож я и ламер, но не имбицил. шмоп подключени работает. пхп 5.2.6, апач 1.х. я на соурсфодже отписал поподробнее о баге
 

Farsh

~ on ~ high ~ wave ~
Автор оригинала: Жигaн

[Farsh]
Там используется com объект(он платный у aot, стоит 250$, работает под виндой ;)) В пхп можно использовать при помощи http://de.php.net/manual/ru/book.com.php
Это понятно , но кроме платных исходников под винду , есть бесплатные под юникс .
У меня задача - соединить хотя бы lemmatizer с php , он запускается из cmd таким образом :
------
devPC:~# export RML=/home/AOT/morph
devPC:~# cd $RML
devPC:/home/AOT/morph# Bin/TestLem Russian
Loading..
Input a word..
>
------
После фразы Loading.. есть двухсекундная задержка .
Из php -
PHP:
$command = 'export RML="/home/AOT/morph"; cd $RML; Bin/TestLem Russian';
$output = shell_exec($command);
По смыслу должно быть тоже самое , но в итоге :"Loading.." , и все .. Насколько я понимаю это изза той самой задержки ( во время нее подгружаются словари ) . И у меня просто нет никаких мыслей , как можно это осуществить ..
Прошу помощи ;) Ошенама нужно ;)

-~{}~ 26.05.08 19:43:

Может ли быть это из-за того , что после запуска программы требуется время на подгрузку словарей , идет не весь ответ ?
 

Alexandre

PHPПенсионер
на aot.ru есть утилита синтактичесчкого анализа lemmatizer.tar.gz можно за основу взять ее код.
 

Жигaн

Новичок
Wicked
В первую очередь, отличия в подготовке словаря для предсказания, там сделано упрощенно.
berkut
Понял, действительно есть баг. Проблема в том, что stat() перестал возвращать ino ключ.
Обновил на sf, спасибо.
Farsh
Нее, ты дал пример питоновского скрипта, который использует COM компонент. Попробуй через proc_open открыть процесс... Либо переделай $RML\Source\TestLem\TestLem.cpp, это просто. А зачем тебе это?

-~{}~ 27.05.08 03:43:

Farsh
Кстати TestLem можно использовать так:
TestLem Russian words.txt
вывод идет в файл words.lem

> cat words.txt
ТЕСТИРУЕМ

> TestLem Russian words.txt
Loading..
read words.txt
process words.txt
Count of words = 1
Time = 0 seconds; 0 ticks
too few words to measure the speed
writing to words.lem

> cat words.lem
ТЕСТИРУЕМ -> ТЕСТИРОВАТЬ квпж#

квпж - это анкоды кв и пж, расшифровку смотри в $RML/Dicts/Morph/rgramtab.tab
 

Wicked

Новичок
Жигaн
посмотрел. Возник вопрос: а для патриции действительно нужно сортировать список слов? Я правильно понимаю, что "// find longest common prefix" - это единственное место, где используется выгода от сортировки?
 

Жигaн

Новичок
а для патриции действительно нужно сортировать список слов?
нет, обычно как раз строят без сортировки, на упорядоченных данных построение дерева происходит намного быстрее.
// find longest common prefix" - это единственное место, где используется выгода от сортировки
весь алгоритм требует сортировки.

имхо можно ускорить обход дерева...
 

Rin

*
Жигaн
Есть предложение использовать вместо ПРОПИСНЫХ строчные по умолчанию, они чаще используются, а на конвертирование регистра тоже время нужно.

-~{}~ 06.06.08 14:03:

Планируется в будущих версиях функционал для снятия омонимии?

-~{}~ 06.06.08 16:23:

Пытался "подружить" phpMorphy и свой TextParser

При этом возникли затруднения, которые, конечно, обходятся, но хочется более элегантного и быстрого(?) решения.
Класс TextParser возвращает индексированный массив $alnum_all со списком слов, которые встречаются в тексте.
Ключами массива являются порядковые номера слов, значениями -- сами слова в кодировке UTF-8.
Слово -- последовательность букв (допускаются знаки "#" и "+" в конце для C#, C++) или цифр (но не букв и цифр вперемешку).
Для каждого слова из массива необходимо получить его базовую форму.

В настоящее время phpMorphy может работать одновременно только с одним языком.
Для каждого языка приходится создавать отдельный экземпляр класса, что не очень удобно:

Код:
$dict_bundle_ru = new phpMorphy_FilesBundle($dir, 'rus');
$morphy_ru = new phpMorphy($dict_bundle_ru, $opts);

$dict_bundle_en = new phpMorphy_FilesBundle($dir, 'eng');
$morphy_en = new phpMorphy($dict_bundle_en, $opts);
А при обходе массива $alnum_all для каждого слова дополнительно нужно определять язык, чтобы делать вызов getBaseForm() нужного экзепляра класса.
Если одни и те же буквы используются в разных языках, определять язык уже не просто (english / german / turkish).

Словарь в юникоде, содержащий несколько языков одновременно, решил бы эту проблему (язык вообще не важен будет, как я понимаю).
Кол-во веб-страниц в UTF-8 увеличивается (в виду преимуществ самой кодировки и развития программ, поддерживающих юникод), в однобайтовых кодировках -- уменьшается.
Думаю, это перспективно.

Жигaн:
>Поддержка различных кодировок будет в следующей версии.
utf-8 для кириллицы снизит производительность ~ в два раза, имхо проще и быстрее через iconv текст прогнать.

Почему в 2 раза? Где слабое место?
Если дело в переменной длине кодирования знаков в UTF-8, то можно попробовать UTF-16.
 

phprus

Moderator
Команда форума
Rin
Словарь в юникоде, содержащий несколько языков одновременно, решил бы эту проблему (язык вообще не важен будет, как я понимаю).
Но создал бы очень много новых проблем. Представьте, что в нескольких разных языках есть слово которое в какой-либо форму пишется одинаково, но правила его изменения в разных языках различны. Как в таком случае модуль морфологии должен угадывать правила какого из языков от него хочет увидеть пользователь?

А при обходе массива $alnum_all для каждого слова дополнительно нужно определять язык,
Только вот определение языка для отдельно взятого слова задача практически неразрешимая. А для отдельно взятого текста примерно определить язык можно.

Если дело в переменной длине кодирования знаков в UTF-8, то можно попробовать UTF-16.
Символ в UTF-16 может представляться не только 2-я, но и 4-я байтами.

Жигaн:
>Поддержка различных кодировок будет в следующей версии.
utf-8 для кириллицы снизит производительность ~ в два раза, имхо проще и быстрее через iconv текст прогнать.
А почему скорость должна снизится? Я таких причин не вижу, а вот унификация интерфейса(для разных языков с разными кодировками) и экономия времени на перекодировках может быть существенна. Действительно если волнует переменная длинна символа и utf-8, то можно использовать тот-же utf-16 или utf-32, в первом правда символ тоже может занимать 4 байта, но это довольно редкое явление.
 

Rin

*
phprus
>Представьте, что в нескольких разных языках есть слово которое в какой-либо форму пишется одинаково, но правила его изменения в разных языках различны

Действительно, такое возможно. :)
В таком случае можно явно указать используемые языки и приоритеты, т.к. эта информация в большинстве случаев известна для текста. Например: array('ru', 'ua'), или array('en', 'de', 'it'). В случае коллизии выдавать основную форму слова для более приоритетного языка. Таких случаев не много должно быть и влияние на качество результата будет очень слабым. В существующих для phpMorphy словарях коллизия может возникнуть пока только для en и de. :)

>Только вот определение языка для отдельно взятого слова задача практически неразрешимая. А для отдельно взятого текста примерно определить язык можно.

Это верно. Но сейчас в getBaseForm() массив со словами на разных языках вперемешку не подсунешь. Одно от другого отделять нужно.

>А почему скорость должна снизится?
Как я понимаю, слова в utf-8 разбирать на буквы придется, а буквы переменной длины. Соотв-но дополнительные проверки немного снизят производительность.
Хотя preg_match_all('/./su') должна очень быстро работать для этих целей.
Да и библиотеки iconv и mbstring на Си написаны.
Так что существенных "тормозов" быть не должно.

Для юникода в качестве внутреннего формата можно ограничиться UCS-2, где используется строго 2 байта для кодирования символа, поэтому резать слово на части очень удобно. Для европейских языков этого хватает с избытком. Азиатские языки (арабский, китайский...) вроде не планируются поддерживать в phpMorphy. :)
 

phprus

Moderator
Команда форума
Rin
Как я понимаю, слова в utf-8 разбирать на буквы придется, а буквы переменной длины. Соотв-но дополнительные проверки немного снизят производительность.
То, что немного это понятно, но это немного должны быть очень маленьким, а никак не в 2 раза.

Хотя preg_match_all('/./su') должна очень быстро работать для этих целей.
А я думаю, что нет. Помоему однократный проход по строке с выполнением элементарных битовых операций должен быть быстрее чем построение и исполнение автомата разбирающего регулярное выражение. Но чтобы точно выяснить нужно провести измерения.
 

berkut

Новичок
а можна поинтересоваться, если getPseudoRoot() для англ. языка, на слове Constanza возвращает stanz - это так и должно быть?
 

Rin

*
phprus
>но это немного должны быть очень маленьким, а никак не в 2 раза.

Согласен что оценка завышена, но, возможно, есть еще какие-нибудь "подводные камни", о которых мы пока не знаем. Дерево, кстати, тоже увеличится примерно в 1,5-2 раза + склейка всех языковых словарей в один. В результате чтение дерева будет медленнее.

Вобщем то я и на 2 раза согласен, через год-два производительность компьютеров опять в 2 раза увеличится :)

>Помоему однократный проход по строке с выполнением элементарных битовых операций должен быть быстрее чем построение и исполнение автомата разбирающего регулярное выражение. Но чтобы точно выяснить нужно провести измерения.

В регулярках есть компиляция во внутренний формат, оптимизация и быстрый сишный код. Я в своё время проводил измерения. Рег. выражение оказалось быстрее, cм. is_utf8(), utf8_check(). В большинстве случаев код с использованием грамотно составленных рег. выражений быстрее, чем реализация на чистом PHP.
 

Wicked

Новичок
Жигaн:
>Поддержка различных кодировок будет в следующей версии.
utf-8 для кириллицы снизит производительность ~ в два раза, имхо проще и быстрее через iconv текст прогнать.

Почему в 2 раза? Где слабое место?
Если дело в переменной длине кодирования знаков в UTF-8, то можно попробовать UTF-16.
1) чукча не читатель, чукча писатель? ты пробовал сам разобраться в том, где тут цитированное, а где твое?
2) медленнее в 2 раза будет из-за того, что в среднем на одну русскую букву будет не 1, а 2 байта. Из-за, например, этого придется делать в 2 раза больше итераций в работе с деревом.

-~{}~ 07.06.08 17:10:

В таком случае можно явно указать используемые языки и приоритеты, т.к. эта информация в большинстве случаев известна для текста. Например: array('ru', 'ua'), или array('en', 'de', 'it'). В случае коллизии выдавать основную форму слова для более приоритетного языка. Таких случаев не много должно быть и влияние на качество результата будет очень слабым. В существующих для phpMorphy словарях коллизия может возникнуть пока только для en и de.
Насколько я знаю структуры данных, производительности (по сравнению с работой с несколькими объектами phpMorphy) это не прибавит, а скорее наоборот, отнимет. Так что это тупо делается в виде пристройки на 100 строк к phpMorphy.

-~{}~ 07.06.08 17:24:

cм. is_utf8(), utf8_check()
смысл первой функции от меня вообще ускользает. А вторую прощу сделать в виде
function ($data) {return iconv('UTF-8', 'UTF-8//IGNORE', $data) === $data}, которая примерно в 20 раз быстрее, чем регулярка, и в 80 раз - чем побайтовая обработка.
 

phprus

Moderator
Команда форума
Wicked
2) медленнее в 2 раза будет из-за того, что в среднем на одну русскую букву будет не 1, а 2 байта. Из-за, например, этого придется делать в 2 раза больше итераций в работе с деревом.
А зачем в 2 раза больше итераций? От изменения кодировки что-ли количество символом с строке изменится? Нет. Изменится только размер самого символа в байта, так что просто на каждом узле дерева будет не однобайтный символ хранится, а двухбайтный (или 4-х байтный), а замена сравнения однобайтных символов на двухбайтные, я думаю, не может вызвать падение производительности в 2 раза. (в структуре дерева я могу ошибаться, так как точно не знаю как оно строится)
Или там дерево строится только по байтам вводимой строки, а не по символам?
 

Rin

*
Просто сейчас байты и символы совпадают :)

Wicked:
>function ($data) {return iconv('UTF-8', 'UTF-8//IGNORE', $data) === $data}

Ваш код должен обработать всю строку до конца, чтобы потом возвратить результат. is_utf8(), utf8_check() возвращают FALSE сразу при первой неудаче. Часто об этом становится известно уже на первых нескольких символах.
 

Wicked

Новичок
Ваш код должен обработать всю строку до конца, чтобы потом возвратить результат. is_utf8(), utf8_check() возвращают FALSE сразу при первой неудаче. Часто об этом становится известно уже на первых нескольких символах.
Ага... Посему я делаю такие выводы:
* Ваша функция ориентируется на быструю работу в 1% проблемных пользователей (юзеры, столкнувшиеся с проблемной формой, хакеры, досеры). Для оставшихся 99% честных пользователей она делает свою работу в 80 раз медленней, чем моя.
* Моя функция ориентируется на быструю работу во всех случаях.

-~{}~ 07.06.08 21:06:

надо бы вынести оффтопик .-)
 

phprus

Moderator
Команда форума
Wicked
как-то так, ага
А почему нельзя в случае перехода к многобайтным кодировкам строить дерево по символам, а не по байтам исходной строки? В языке-же базовый (слово не очень удачное, но другое подобрать не могу) элемент - это символ, а не байт.
 

Rin

*
Wicked
Для 99% пользователей Вы правы. :) Я добавлю этот код.
 
Сверху