В принципе, если есть школьная книга Русский Язык и php.net - нет ничего сложного.
Жаль только одного - времени...

Если кто-то что-то знает по этому поводу, ОГРОМНАЯ просьба помочь!
THNX
Дай пример, pleezzzz....!zg писал(а):я решал такую задачу, вполне успешно, тут есть три пути:
1. пытаться вы**нуться и сделать разбор слова (что практически невозможно)
2. сделать поиск по "созвучным" словам
3. сделать синонимическую связь
Последние два варианта я с успехом реализовывал, результат - очень быстрый и прикольный поиск.
это очень даже возможно. и для русского языка не так сложно. включая исключение.zg писал(а):1. пытаться вы**нуться и сделать разбор слова (что практически невозможно)
Согласен. Но, думаю, что перед тем как начать изобретать "велосипед", лучше (на всяк случай) спросить, может кто-то когда-то уже написал и забыл, и не пожалеет свои наработки во благо человечества!?MAK писал(а):это очень даже возможно. и для русского языка не так сложно. включая исключение.zg писал(а):1. пытаться вы**нуться и сделать разбор слова (что практически невозможно)
поищите про морфологию русского языка, эти правила, и способы работы с ними должны быть и нете.
та ладна воздух молоть, ты код выложиMAK писал(а):это очень даже возможно. и для русского языка не так сложно. включая исключение.zg писал(а):1. пытаться вы**нуться и сделать разбор слова (что практически невозможно)
человечество, последуй примеру MS и не парься с падежами склонениями, сделай на синонимах, это проще и на много эффективней, а самое главное убережёт от многих глупых ситуаций.VladB писал(а):и не пожалеет свои наработки во благо человечества!?![]()
код выложить не могу. во-первых писан не мной(мной был прикручен к проекту). во-вторых уже наверно не найду его. :)zg писал(а):та ладна воздух молоть, ты код выложи ;-)MAK писал(а):это очень даже возможно. и для русского языка не так сложно. включая исключение.zg писал(а):1. пытаться вы**нуться и сделать разбор слова (что практически невозможно)
-))) ну да, чистейший пхпMAK писал(а):ну вот что нарыл на скорую руку http://aot.ru/docs/rusmorph.html
ну... так ты это восстанови в памятиMAK писал(а):код выложить не могу. во-первых писан не мной(мной был прикручен к проекту). во-вторых уже наверно не найду его.хотя реализован был и на сях и на пхп.
может быть я действительно ошибаюсь и мы с тобой забацаем фрифарный проект посвящённый лингвистическому поиску на пхп?MAK писал(а):это очень даже возможно. и для русского языка не так сложно. включая исключение.
Расскажу как я реализовывал: есть три таблицыVladB писал(а):Дай пример, pleezzzz....!
Код: Выделить всё
1. объекты (object_id, ...)
2. Слова с привязкой к синонимам (word_id, syn_id,strong_level)
3. привязка синонимов к объектам (object_id, syn_id)
Код: Выделить всё
function create_temporary_result_table ( $search_words, $firm_rubric_id = null )
{
if ( $firm_rubric_id === null ) $firm_rubric_id = false;
if ( $firm_rubric_id )
{
if ( count(split(',', $firm_rubric_id, 2)) > 1 ) $srch_rubrics = ' IN ('. $firm_rubric_id .')'; else $srch_rubrics = '=' . $firm_rubric_id;
}
DB::QUERY
(
'CREATE TEMPORARY TABLE `'. TBL_TMP_RESULTS .'` (
`firm_id` int(1) NOT NULL default 0,
`score` int(1) NOT NULL default 0,
`found_words` int(1) NOT NULL default 0,
PRIMARY KEY (`firm_id`),
INDEX (`score`),
INDEX (`found_words`)
) ENGINE=MyISAM
');
$i = 0;
$hg_words = array();
foreach ($search_words as $word)
{
$score = pow(2, COUNT_SEARCH_WORDS - $i - 1);
$i += 1;
$sql = 'SELECT `sinonym_for` FROM `'. TBL_KEYWORDS .'` WHERE keyword_name=\''. mysql_escape_string($word) .'\' LIMIT 0,1';
$result = DB::QUERY($sql);
if ( mysql_affected_rows() )
{
$row = mysql_fetch_assoc($result);
$hg_words[] = $row['sinonym_for'];
$sql =
'INSERT INTO `'. TBL_TMP_RESULTS .'`
SELECT
i.firm_id, i.score+'. $score .', 1
FROM
`'. TBL_INDEX .'` AS i
'. ( $firm_rubric_id ? ', `'. TBL_FIRMS .'` as f' : '' ) .'
WHERE
i.keyword_id='. $row['sinonym_for'] .'
'. ( $firm_rubric_id ? 'AND f.rubric_id'. $srch_rubrics . ' AND i.firm_id=f.firm_id' : '' ) .'
ON DUPLICATE KEY UPDATE `'. TBL_TMP_RESULTS .'`.score=`'. TBL_TMP_RESULTS .'`.score+i.score+'. $score .', found_words=found_words+1
';
DB::QUERY($sql);
}
}
define('KEYWORDS_ID', join(',', $hg_words));
}
function select_from_temporary_results_table ( $min_count_found_words = null, $start_item = null, $limit = null )
{
if ( $min_count_found_words === null ) $min_count_found_words = STRICT_SEARCH ? COUNT_SEARCH_WORDS : 0;
if ( $start_item === null ) $start_item = DEFAULT_START_ITEM;
if ( $limit === null ) $limit = DEFAULT_LIMIT;
$sql =
'SELECT SQL_CALC_FOUND_ROWS
rub.rubric_name,
f.rubric_id,
f.firm_name,
f.firm_site,
f.firm_email,
f.firm_addr_ext,
f.firm_keywords,
f.firm_house,
f.firm_id,
f.firm_telephones,
s.street_name,
r.score,
r.found_words
FROM
`'. TBL_FIRMS .'` AS f,
`'. TBL_STREETS .'` AS s,
`'. TBL_TMP_RESULTS .'` as r,
`'. TBL_RUBRICS .'` as rub
WHERE
'. ($min_count_found_words ? 'r.found_words>='. $min_count_found_words . ' AND' : '') .'
f.firm_id=r.firm_id
AND f.rubric_id=rub.rubric_id
AND f.street_id=s.street_id
ORDER BY r.found_words DESC, r.score DESC, f.firm_name ASC
LIMIT '. $start_item .',' . $limit;
$result = DB::QUERY($sql);
define('FOUND_ROWS', array_pop(mysql_fetch_array(DB::QUERY('SELECT FOUND_ROWS()'))));
return $result;
}
ну да, это самый простой вариант. У меня друг диплом писал на эту тему, дак сделал очень хитро - взял список всех окончаний из нета и просто их отбрасывал при поиске. Выглядело интересно. Если прикрутить будет ещё и морфологический разбор слова -)))MAK писал(а):zg, скажи, а в таблице слов у тебя должны находится по возможности все словоформы слов?
ну в данной реализации нетMAK писал(а):например при запросе "столов" нельзя будет найти синосимы если в этой таблице не будет точно этого слова?
я и не спорю, просто уровень сложности несравнимо разный. А результат примерно одинаков. Для веба чем проще тем лучше.MAK писал(а):морфологический разбор слова и синонимайзер - несколько разные вещи, взаимно дополняющие друг друга.
гут, только надо чтобы в итоге оказалось что-то вменяемое, а не просто набор буквациферMAK писал(а):Так что мы можем с тобой скооперироваться, и решить эту насущную проблему. ж)
-))) у меня тож жена в роддоме, правда это первый.MAK писал(а):Я принимаю вызов. Но прямо сейчас в бой я не готов - мелкого вторые сутки несет после ДР, и жена вот-вот родит. Еще одного спиногрыза.
1 секунда много... Да и вобщем-то я хотел увидеть код на пхп и желательно твой.MAK писал(а):Результаты для веба неприемлимые - ~1 сек. Но есть над чем работать! Да, zg?
я не испольюзу чужой код (особенно на пхп) по двум причинам:MAK писал(а):почти копи/паст питоновского модуля. зачем велик изобретать?
гм.. штука интересная, но не пашет со словами с ошибкой. Исходники надаMAK писал(а):http://makmap.net/tmp/morph/test.php?wo ... 1%83%D0%B9
жестоко... если б они только знали, что можно выставить локаль, а magic_quotes не является обязательной директивой....MAK писал(а):вот сырец
Код: Выделить всё
$sql = "SELECT base, rule_id from Morph.Lemmas_".$this->_language." where base like '".mb_substr($word, 0, $c, MORPH_MB_ENCODING)."%'";
$sql = "SELECT prefix, suffix FROM Morph.Rules_".$this->_language." WHERE id=".$rule_id;
Код: Выделить всё
mysqldump ИМЯ_БАЗЫ -O extended-insert=false -Q --insert-ignore -pПАРОЛЬ --set-charset --default-character-set=КОДИРОВКА | bzip2 > /ПУТЬ/ДО/АРХИВА.dump.sql.bz2
очень даже возможно. более того уже давно было реализовано в открытом доступе. :)zg писал(а):1. пытаться вы**нуться и сделать разбор слова (что практически невозможно)
гм....zg писал(а):Нда.. нобелевской премией тут не пахнет
может я вправду слишком требователенMAK писал(а):более того уже давно было реализовано в открытом доступе.
Синоним - это близкое по значению слово, которое пишется и произностится по разному. Так что это не синонимайзер вообще.zg писал(а):мне думалось реализовать морфологический разбор слова по всем правилам...
Это всего лишь умный синонимайзер, но не полноценный парсер. Я про это и говорил.
Код: Выделить всё
/*
Функция склонения существительных
получает строку с существительным (в имен падеже), род существительного, падеж в который следует
преобразовать слово
gender = 1 Муж род
2 Жен род
3 Ср род
case = 1 Имен
2 Род
3 Дат
4 Винит
5 Творит
6 Предл
*/
function lang_decline_noun($str='',$gender=0,$case=0){
$str = trim($str);
if ($str=='' || !$gender || $case<1 || $case>6) return '';
if ($case==1) return $str;
$strl = strtolower($str); // переводим строку в нижний регистр (для удобства проверок)
$decl = 0; // склонение
$spec = 0; // специальное (слова исключения)
// Определение склонения
if ( ($gender==1 || $gender==2) && in_array(substr($strl,-1),array('а','я')) ){ // Жен или муж род, на -а или -я
$decl = 1; // 1е склонение
}elseif ( $gender==3 && in_array(substr($strl,-1),array('о','е')) ){ // Ср. род, на -о или -е
$decl = 2; // 2е склонение
}elseif( $gender==1 && lang_check_noun_zero_ending($str) ){ // Муж род, нулевое окончание
$decl = 2; // 2е склонение
}elseif( $gender==2 && lang_check_noun_zero_ending($str) ){ // Жен род, нулевое окончание
$decl = 3; // 3е склонение
}
if(!$decl) return $str;
// Определение является ли слово - исключением
if($decl==1 && substr($strl,-2)=='ия') $spec=1;
if($decl==2 && in_array(substr($strl,-2),array('ий','ие')) ) $spec=1;
// склонение
switch($decl){
case 1: // 1е склонение
$last = substr($strl,-1); // Получаем последний символ
$str = substr($str,0,-1); // Укорачиваем строку на 1 символ
$ending['а'] = array('','','ы','е','у','ой','е'); // массив окончаний
$ending['я'] = array('','','и','е','ю','ей','е');
if( $spec && ($case==3 || $case==6) ) $str.='и';
elseif( $case==5 && in_array(substr($str,-1),array('ж','ш','Ж','Ш')) ) $str.='ей';
else $str.=$ending[$last][$case];
break;
case 2: // 2е склонение
$last = substr($strl,-1); // Получаем последний символ
if($gender==3){ // Ср род, на -о, -е
$str = substr($str,0,-1); // Укорачиваем строку на 1 символ
$ending['о'] = array('','','а','у','о','ом','е'); // массив окончаний
$ending['е'] = array('','','я','ю','е','ем','и');
if($case==6 && lang_check_noun_zero_ending($str)) $str.='е';
else $str.=$ending[$last][$case];
}else{ // Муж род
if($last=='ь' || $last=='й'){
$str = substr($str,0,-1); // Укорачиваем строку на 1 символ
$ending = array('','','я','ю','я','ем','е'); // массив окончаний
if($spec && $case==6) $str.='и';
else $str.=$ending[$case];
}else{
$ending = array('','','а','у','','ом','е');
$str.=$ending[$case];
}
}
break;
case 3: // 3е склонение
$str = substr($str,0,-1); // Укорачиваем строку на 1 символ
$ending = array('','','и','и','ь','ью','и');
if(!in_array(substr($str,-1),array('ч','Ч','ш','Ш','ж','Ж')) && $case!=4) $str.='ер';
$str.=$ending[$case];
break;
}
// Проверка на жи, ши
if( substr($str,-1)=='ы' && in_array(substr($str,-2,-1),array('ж','ш','Ж','Ш','ч','Ч')) ){ $str[strlen($str)-1]='и'; }
return $str;
}
/*
Функция склонения качественных и относительных прилагательных
Внимание!!! Притяжательные прилагательные склоняются подругому
получает строку с прилагательным (в имен падеже), и падеж в который следует преобразовать слово
case = 1 Имен
2 Род
3 Дат
4 Винит
5 Творит
6 Предл
*/
function lang_decline_adjective($str='',$case=0){
$str = trim($str);
if ($str=='' || $case<1 || $case>6) return '';
if ($case==1) return $str;
$strl = strtolower($str); // переводим строку в нижний регистр (для удобства проверок)
switch(substr($strl,-2)){ // Определяем по окончанию род
case 'ый': $ending = array(1,'ый','ого','ому','ый','ым','ом'); break; // Мужской род
case 'ий': $ending = array(1,'ий','его','ему','ий','им','ем'); break;
case 'ое': $ending = array(2,'ое','ого','ому','ое','ым','ом'); break; // Средний род
case 'ее': $ending = array(2,'ее','его','ему','ее','им','ем'); break;
case 'ая': $ending = array(3,'ая','ой','ой','ую','ой','ой'); break; // Женский род
case 'яя': $ending = array(3,'яя','ей','ей','юю','ей','ей'); break;
default: return $str; // Не смогли определить род
}
$str = substr($str,0,-2).$ending[$case]; // Замена падежного окончания
return $str;
}
// Проверяет является ли окончание существительного в
// именительном падеже нулевым
function lang_check_noun_zero_ending($str=''){
$str = strtolower($str);
$ends = array('б','в','г','д','ж','з','й','к','л','м','н','п','р','с','т','ф','х','ц','ч','ш','щ','ь');
if (in_array(substr($str,-1),$ends)) return TRUE;
return FALSE;
}
да никто не мешаетMAK писал(а):И кто мешает тебе добавить это слово(как отдельное) в словарь?
гм.. вроде как морфологический рзабор слова в школе проходят -))) При чём не один годMAK писал(а):Я сам не лингвист - так что не знаю как слова "съел" и "ел" должны разбираться с точки зрения морфологии.
ладна, спорить не буду. А то мы с тобой два таких лингвиста, что можем доспориться до чего угодно.MAK писал(а):Синоним - это близкое по значению слово, которое пишется и произностится по разному.
ага. и прямо со школьной скамьи в доктора и академики. ))zg писал(а):гм.. вроде как морфологический рзабор слова в школе проходят -))) При чём не один год :roll:
дальше.zg писал(а):куда теперь?
кстати, насчёт utf8, ты базу выложил в неверной кодировке... там русский текст нечитаемый, по крайне мере муся его не понимает. Сделай плиз правильный дам.MAK писал(а):можно отказаться от utf8.
зачем? достаточно создать один индекс на две или три начальные буквы, этого вполне будет достаточноMAK писал(а): соответственно добавить 5 и более полей с индексами.
гут, но сначала сделай дампMAK писал(а):сделать инстумент добавления слов в словарь.
Действительно. Правда ключи, которые ты привел выше приводят к точно таким же закорючкам. Хотя нецкий нормально отображается.zg писал(а):ты базу выложил в неверной кодировке... там русский текст нечитаемый, по крайне мере муся его не понимает. Сделай плиз правильный дам.
немного изменил запрос(см сырец). теперь средний результат ~0.1ms. мне этого вполне достаточно.zg писал(а):достаточно создать один индекс на две или три начальные буквы, этого вполне будет достаточно
хм... а ты как делал? у меня работаетMAK писал(а):Правда ключи, которые ты привел выше приводят к точно таким же закорючкам.
даже не сомневаюсь -)) но выложи плиз не дамп, а файлы таблиц, я потом их сам обработаю как надоMAK писал(а):%) zg, может у тебя получится?
лебедевский декодер упорно определяет исходную кодировку как 1252.... конечно правильно всё равно не декодится, но я склолен ему верить.. ладна ещё пиграюсь, может найду чёкавоMAK писал(а):вот неправильний дамп муси
MAK писал(а):немного изменил запрос(см сырец).
Код: Выделить всё
where '".$word."' like base";
делал как ты сказал, каюсь, без пайпа с бзипом.zg писал(а):хм... а ты как делал? у меня работаетMAK писал(а):Правда ключи, которые ты привел выше приводят к точно таким же закорючкам.
Morph.tgzzg писал(а):выложи плиз не дамп, а файлы таблиц, я потом их сам обработаю как надо
выше писал, что есть читаемый дамп sqlite - 2 замены приводят к дампу mysqlzg писал(а): ладна ещё пиграюсь, может найду чёкаво
разница существенная. я сначала тоже не понял что к чему. в поле base последный символ % - вот тут собака зарыта. )zg писал(а):MAK писал(а):немного изменил запрос(см сырец).а что есть разница? то что процент убрал вижу, но тут есть одна заковырка, про которую скажу как только база будет у меня. А какой смысл переставлять поле и условие?Код: Выделить всё
where '".$word."' like base";