URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID11
Нить номер: 18
[ Назад ]

Исходное сообщение
"Реализация поиска, стемминг и выделение существительных"

Отправлено stk , 08-Янв-04 13:32 
Решил написать собственый скрипт для поиска на сайте.
Для сокращения объема базы слов, первое, что пришло в глову использование русского стиммера (http://snowball.tartarus.org/russian/stemmer.html) перед помещением слов в индекс и в момент ввода ключевой фразы. Т.е. имеем в базе только обрезанные корни слов.

Но возникла мысль, что неплохо вообще оставить в базе только существительные. Есть ли способ, определить какой частью речи является слово (не важно в английском языке или русском). Есть ли алгоритмы по определнию является ли слово существиельным с определенной долей вероятности, путем анализа суффиксов и окончаний ? Или такое невозможно впринципе ?

Думал найти признак части речи в ispell базах Лебедева, но там нет такой инфомрации.

Буду признателен за любую информацию по этому вопросу.


Содержание

Сообщения в этом обсуждении
"Реализация поиска, стемминг и выделение существительных"
Отправлено Maxim Chirkov , 08-Янв-04 22:17 
Морфологический анализ отнюдь не тривиальная тема. Я как-то пытался прикрутить стеммер (snowball) к htdig, который обеспечивает поиск на opennet, вместо далеко не оптимального выделения словоформ используя ispell словари.

Написал небольшой скрипт на perl для тестирования работы стеммера (английский и русский язык). Анализ результатов дал неутешительный результат, особенно для английских текстов изобилующих терминами. Поэтому оставил все неизменным, хотя уйти от htdig меня давно тянет, только некуда.... Для объема индексируемого материала в примерно 1.5 Гб, mnogosearch не потянет (ОЗУ нехватит), OpenFTS по отзывам в usenet слишком медленный при больших объемах базы, к тому же использовать SQL сервер для организации поиска у меня рука не поднимается.

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

PS. Неплохую статью по морфологическому анализу с открытым кодом стеммера можно найти здесь: http://linguist.nm.ru/stemka/stemka.html


"Реализация поиска, стемминг и выделение существительных"
Отправлено Гусев М.Н. , 02-Мрт-04 12:28 
Добрый день!

У меня есть небольшая (и пока не завершенная)
разработка - пока только под Вин, (http://gusev.inp.kz)
Объем индексной базы - 30%, скорость поиска практически не зависит от объема базы, потребности в ОЗУ при поиске невелики.
Морфологический анализ пока прост, но работает сравнительно неплохо.

Имеет ли смысл и ценность перенос ее алгоритмов на другие платформы?

Максим.

>Морфологический анализ отнюдь не тривиальная тема.
>выделения словоформ используя ispell словари.
>Написал небольшой скрипт на perl для тестирования работы стеммера
>(английский и русский
>язык).

>терминами. Поэтому оставил все неизменным, хотя
>уйти от htdig меня давно тянет, только некуда....
> Для объема индексируемого материала в примерно 1.5 Гб,
> mnogosearch не потянет (ОЗУ нехватит),
> OpenFTS по отзывам в usenet слишком
>медленный при больших объемах базы,



"Реализация поиска, стемминг и выделение существительных"
Отправлено autoua , 13-Дек-04 13:39 
>терминами. Поэтому оставил все неизменным, хотя уйти от htdig меня давно
>тянет, только некуда.... Для объема индексируемого материала в примерно 1.5 Гб,
>mnogosearch не потянет (ОЗУ нехватит), OpenFTS по отзывам в usenet слишком

Что-то смогли подобрать? Т.к. проблема похожая. mnogosearch почти два гига базу наиндексировал. Я пока ни на чем окончательно не остановился. На очереди буду пробовать http://www.perlfect.com/freescripts/search/


"Реализация поиска, стемминг и выделение существительных"
Отправлено Maxim Chirkov , 13-Дек-04 14:47 
>Что-то смогли подобрать? Т.к. проблема похожая. mnogosearch почти два гига базу наиндексировал.

Нет. Чуть запатчил htdig на предмет расчета релевантности при запросе по нескольким ключам и еще несколько мелочей для собственного удобства добавил.
Что касается индексации, то у меня после индексации запускаются два perl скрипта для чистки htdig-овских индексов на предмет мусора в базе слов (режутся несуществующие и ошибочные русские слова) и вычищения лишних URL'ей (индексные и дублирующие друг-друга страницы, изменение веса для некоторых разделов).

> На очереди буду пробовать http://www.perlfect.com/freescripts/search/

Судя по предупреждениям в их FAQ, больше пары тысяч индексируемых страниц от него не вытянуть.


"Реализация поиска, стемминг и выделение существительных"
Отправлено dev , 09-Янв-04 00:52 
>Но возникла мысль, что неплохо вообще оставить в базе только существительные. Есть
>ли способ, определить какой частью речи является слово (не важно в
>английском языке или русском). Есть ли алгоритмы по определнию является ли
>слово существиельным с определенной долей вероятности, путем анализа суффиксов и окончаний
>? Или такое невозможно впринципе ?

Обязательно использовать словарь. При этом в анлийском есть слова, которые могут являются и глаголами, и существительными (например, test).
Для английского такой словарик можно сделать из http://wftp.tu-chemnitz.de/pub/Local/urz/ding/ger-eng/ - список соответствия немецких и анлийских слов в простейшем формате. Глаголы можно определить по 'to ' перед словом.


"Реализация поиска, стемминг и выделение существительных"
Отправлено one , 22-Дек-04 20:10 
#!/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>


"Реализация поиска, стемминг и выделение существительных"
Отправлено idle , 16-Дек-05 15:18 
Да, да побольше длиннющих, некомментированных скриптов, народ это обожает.