Решил написать собственый скрипт для поиска на сайте.
Для сокращения объема базы слов, первое, что пришло в глову использование русского стиммера (http://snowball.tartarus.org/russian/stemmer.html) перед помещением слов в индекс и в момент ввода ключевой фразы. Т.е. имеем в базе только обрезанные корни слов.Но возникла мысль, что неплохо вообще оставить в базе только существительные. Есть ли способ, определить какой частью речи является слово (не важно в английском языке или русском). Есть ли алгоритмы по определнию является ли слово существиельным с определенной долей вероятности, путем анализа суффиксов и окончаний ? Или такое невозможно впринципе ?
Думал найти признак части речи в ispell базах Лебедева, но там нет такой инфомрации.
Буду признателен за любую информацию по этому вопросу.
Морфологический анализ отнюдь не тривиальная тема. Я как-то пытался прикрутить стеммер (snowball) к htdig, который обеспечивает поиск на opennet, вместо далеко не оптимального выделения словоформ используя ispell словари.Написал небольшой скрипт на perl для тестирования работы стеммера (английский и русский язык). Анализ результатов дал неутешительный результат, особенно для английских текстов изобилующих терминами. Поэтому оставил все неизменным, хотя уйти от htdig меня давно тянет, только некуда.... Для объема индексируемого материала в примерно 1.5 Гб, mnogosearch не потянет (ОЗУ нехватит), OpenFTS по отзывам в usenet слишком медленный при больших объемах базы, к тому же использовать SQL сервер для организации поиска у меня рука не поднимается.
Что касается выделение частей речи (ключевых терминов), то здесь задача разрешима только с использованием словарей. Но я бы посоветовал, не пытаться определить нужное, а заняться отсеиванием лишнего, так будет значительно проще.
PS. Неплохую статью по морфологическому анализу с открытым кодом стеммера можно найти здесь: http://linguist.nm.ru/stemka/stemka.html
Добрый день!У меня есть небольшая (и пока не завершенная)
разработка - пока только под Вин, (http://gusev.inp.kz)
Объем индексной базы - 30%, скорость поиска практически не зависит от объема базы, потребности в ОЗУ при поиске невелики.
Морфологический анализ пока прост, но работает сравнительно неплохо.Имеет ли смысл и ценность перенос ее алгоритмов на другие платформы?
Максим.
>Морфологический анализ отнюдь не тривиальная тема.
>выделения словоформ используя ispell словари.
>Написал небольшой скрипт на perl для тестирования работы стеммера
>(английский и русский
>язык).>терминами. Поэтому оставил все неизменным, хотя
>уйти от htdig меня давно тянет, только некуда....
> Для объема индексируемого материала в примерно 1.5 Гб,
> mnogosearch не потянет (ОЗУ нехватит),
> OpenFTS по отзывам в usenet слишком
>медленный при больших объемах базы,
>терминами. Поэтому оставил все неизменным, хотя уйти от htdig меня давно
>тянет, только некуда.... Для объема индексируемого материала в примерно 1.5 Гб,
>mnogosearch не потянет (ОЗУ нехватит), OpenFTS по отзывам в usenet слишкомЧто-то смогли подобрать? Т.к. проблема похожая. mnogosearch почти два гига базу наиндексировал. Я пока ни на чем окончательно не остановился. На очереди буду пробовать http://www.perlfect.com/freescripts/search/
>Что-то смогли подобрать? Т.к. проблема похожая. mnogosearch почти два гига базу наиндексировал.Нет. Чуть запатчил htdig на предмет расчета релевантности при запросе по нескольким ключам и еще несколько мелочей для собственного удобства добавил.
Что касается индексации, то у меня после индексации запускаются два perl скрипта для чистки htdig-овских индексов на предмет мусора в базе слов (режутся несуществующие и ошибочные русские слова) и вычищения лишних URL'ей (индексные и дублирующие друг-друга страницы, изменение веса для некоторых разделов).> На очереди буду пробовать http://www.perlfect.com/freescripts/search/
Судя по предупреждениям в их FAQ, больше пары тысяч индексируемых страниц от него не вытянуть.
>Но возникла мысль, что неплохо вообще оставить в базе только существительные. Есть
>ли способ, определить какой частью речи является слово (не важно в
>английском языке или русском). Есть ли алгоритмы по определнию является ли
>слово существиельным с определенной долей вероятности, путем анализа суффиксов и окончаний
>? Или такое невозможно впринципе ?Обязательно использовать словарь. При этом в анлийском есть слова, которые могут являются и глаголами, и существительными (например, test).
Для английского такой словарик можно сделать из http://wftp.tu-chemnitz.de/pub/Local/urz/ding/ger-eng/ - список соответствия немецких и анлийских слов в простейшем формате. Глаголы можно определить по 'to ' перед словом.
#!/usr/bin/perl
#######################################
#######################################
@dirs=('lists/'); ###
$base_dir="/www/htdocs"; ###
$base_ssi=""; ###
$base_url="http://dom.com/"; &n...
@searchtypes=(''); ###
$subdirs="yes"; ###
$coef=100; ###
#######################################
#######################################
$buffer = "$ENV{'QUERY_STRING'}";
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
if ($name eq "words") { $firstwords=$value; }
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$name =~ s/<!--(.|\n)*-->//g;
$name =~ s/<([^>]|\n)*>//g;
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s/<!--(.|\n)*-->//g;
$value =~ s/<([^>]|\n)*>//g;
$value =~ s/\.//g;
$value =~ s/\://g;
$value =~ s/\,//g;
$value =~ s/\?//g;
$value =~ s/\!//g;
$value =~ s/\&//g;
$value =~ s/\|//g;
$value =~ s/\"//g;
$value =~ tr/ / /s;
$FORM{$name} = $value;
}$words=$FORM{'words'};
$bigeqsmall=$FORM{'bigeqsmall'};
$whatsearch=$FORM{'whatsearch'};
$logics=$FORM{'logics'};
$findstr=0;
$page=$FORM{'page'};
$pcoef=$FORM{'pcoef'};if ($logics eq "and") { @word=$words; }
else { @word=split(/ /,$words); }
if ($page eq '') { $page=1; }if ($whatsearch eq "yes") {
$i=0;
foreach $str (@word) {
$str="$str ";
$word[$i]=$str;
$i++;
}
}
else { $whatsearch="no"; }foreach $type (@dirs) {
chomp($type);
$dir="$base_dir/$type";
chdir($dir);
opendir(CURDIR, $dir) || &cgiError ("Opening dirs '$dir' failed:", "$!");
@allfiles=readdir(CURDIR);
$totalnum=@allfiles;
closedir(CURDIR);
for($i=1; $i<$totalnum; $i++) {
if (-d $allfiles[$i]) {
if ($allfiles[$i] ne '.' && $allfiles[$i] ne ".." && $type ne '' && $subdirs eq "yes") {
push(@dirs,"$type$allfiles[$i]/");
}
}
if (-f $allfiles[$i]) {
($file,$ext) = split(/\./, $allfiles[$i]);
$ext =~ tr/A-Z/a-z/;
foreach $searchtype (@searchtypes) {
if ($ext =~ /$searchtype/i) {
$search="0";
$temp="0";
$normal_string="0";
open (SRH,"$allfiles[$i]") || &cgiError ("Reading file '$allfiles[$i]' failed:", "$!");
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)=stat($allfiles[$i]);
read(SRH,$search,$size);
close(SRH);
$search =~ s/\n/ /g;
if ($search =~ /<title>(.*)<\/title>/i) { $title="$1"; }else { $title="$allfiles[$i]"; }
$search =~ s/<([^>]|\n)*>//g;
$search =~ s/&([^;])*;//g;
$search =~ s/<!--([^-->])*-->//g;
$search =~ tr/ / /s;
$normal_string=$search;
$search =~ s/\./ /g;
$search =~ s/\:/ /g;
$search =~ s/\,/ /g;
$search =~ s/\?/ /g;
$search =~ s/\!/ /g;
if ($bigeqsmall eq "yes") {
$search =~ tr/А-Я/а-я/;
$search =~ tr/A-Z/a-z/;
}
$doublesearch=$search;
foreach $str (@word) {
$search=$doublesearch;
if ($bigeqsmall eq "yes") {
$str =~ tr/А-Я/а-я/;
$str =~ tr/A-Z/a-z/;
}
if ($search =~ /$str/i) {
$allsymbols=0;
$lensword=length($str);
while ($search ne '') {
($temp,$search)=split(/$str/,$search,2);
$allsymbols=$allsymbols+length($temp);
if ($allsymbols < $coef) {
$rstart=substr($normal_string,0,$allsymbols);
}
else {
$rstart=substr($normal_string,$allsymbols-$coef,$coef);
}
$rword=substr($normal_string,$allsymbols,$lensword);
$rend=substr($normal_string,$allsymbols+$lensword,$coef);
$allsymbols=$allsymbols+$lensword;
if ($search ne '') {
$findstr++;
$allsymbolsr=substr("00000000",length($allsymbols),8-length($allsymbols));
$allsymbolsr="$allsymbolsr$allsymbols";
$isize=int($size/1024);
$allstrfile{"$allfiles[$i]\&$allsymbolsr"}=<< "[END]";
<p class="lr"><u>header:</u> $title<br><u>URL:</u> <a href=\"$base_url$type$allfiles[$i]\"
target=\"_blank\">$base_url$type$allfiles[$i]</a><br><u>size:</u> $isize Кб<br>
<i> ---> $rstart<b>$rword</b>$rend <--- </i></p>
[END]
}
}
}
}
}
}
}
}
}&print_head;
print "<p><br><u>search:</u> <b>$words</b><br>";
if ($bigeqsmall eq "yes") {
print "<u>with no register var=no.</u><br>";
}
if ($whatsearch eq "yes") {
print "<u>compleatly var=yes.</u><br>";
}
if ($logics eq "and") {
print "<u>logic <b>and</b>.</u><br>";
}
else {
print "<u>logic <b>or</b>.</u><br>";
}
print "</p><hr width=\"100%\">";if ($findstr eq 0) {
print "<p align=center><br><font size=4><b>File does not exist.</b></font></p><p> </p>";
}
else {
print "<p><u>result:</u> <b>$findstr</b> shtuk =).</p>";
}if ($pcoef ne 100 && $findstr>$pcoef) {
$fr=0;
foreach $key (sort (keys %allstrfile)) {
if (($fr<$pcoef*$page) && ($fr>=$pcoef*($page-1))) { print "$allstrfile{$key}\n"; }
$fr++;
}
print "<p><font size=\"2\"><u>page:</u> ";
for($i=1; $i<($findstr/$pcoef)+1; $i++) {
if ($i ne $page) {
print "<a href=\"/cgi-bin/search.pl?words=$firstwords&bigeqsmall=$bigeqsmall&whatsearch=$whatsearch&pcoef=$pcoef&logics=$FO
}
else {
print "<b>$i</b> ";
}
}
print "</font></p>";
}
else {
foreach $key (sort (keys %allstrfile)) {
print "$allstrfile{$key}";
}
}
&print_end;exit;
sub cgiError {
my ($error_cause,$error) = @_;
if ($error_cause eq "") { $error_cause = "Error:"; }
if ($error eq "") { $error = "The script encountered problems and terminated"; }
&print_head;
print "<br><br><p align=center><font size=3><b>$error_cause $error</b></font></p><p> </p>";
&print_end;
exit;
}sub print_head {
chdir($base_ssi);
open(DB,"head.txt");
@totals=<DB>;
close(DB);
print "Content-type: text/html\n\n";
print @totals;
}sub print_end {
open(DB,"end.txt");
@totals=<DB>;
close(DB);
print @totals;
}--index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Search</title>
<!--
-->
<body>
<body text="#000000" bgcolor="#FFFFFF" link="#000080" vlink="#008000" alink="#000080">
<div align="center"><center>
<form action="/cgi-bin/search.pl" method="GET">
<table border="1" cellpadding="1" cellspacing="1" width="39%"><tr>
<td>
<input type="text" name="words" size="39%" class="forms"</td>
<td align="right"><input type="submit" value=" search " class="forms"></td>
</tr><td>
<input type="checkbox" name="bigeqsmall" value="yes" checked>with no register</td><td>
<input type="checkbox" name="whatsearch" value="yes">completely</td><tr>
<td align="left">logic
<input type="radio" value="or" name="logics" checked>OR
<input type="radio" value="and" name="logics">AND</td>
<td align="left">result
<input type="radio" value="10" name="pcoef"checked>10
<input type="radio" value="20" name="pcoef">20
<input type="radio" value="100" name="pcoef">all</td>
</tr>
</table>
</form>
</div>
</center>
<center></body>
</html>
Да, да побольше длиннющих, некомментированных скриптов, народ это обожает.