如何找到基本的,未反思的单词进行搜索?

时间:2011-05-31 17:30:34

标签: perl search nlp stemming lemmatization

我在尝试编写一个搜索引擎时遇到了麻烦,该搜索引擎将一个单词的所有变形视为相同的基本单词。

  1. 因此,对于动词,这些都是相同的词根,
    • 数字/人( 例如 am;是;
    • 紧张/情绪,如过去或将来时( 例如 是;是;将
    • 过去分词( 例如 ;
    • 现在分词和动名词( 例如 正在; 不是有趣; 正在早期
    • 虚拟语气( 例如 可能;关键 已完成;我希望< EM>是) ⁠⁠ ⁠

  2. 然后对于名词,单数形式和复数形式都应算作相同的基本单词[ᴇᴅɪᴛᴏʀɴᴏᴛᴇɴᴏᴛᴇ:这通常被称为引用形式 ]
  3. 例如,使用“ enable ”,我不希望将“启用”和“启用”打印为单独的条目。所有这三个都应该算作相同的基本单词,动词 enable

    我可以使用类似的哈希来阻止打印重复项:

    unless ($seenmatches{ $headmatches[$l] }++)
    
    1. 有人可以解释一下吗?在下面的评论中解释。

    2. 这并不能阻止复数/过去继续。有没有办法做到这一点,或者一些完全不同的方法,也许一个涉及正则表达式和/或替换,然后是一个unub?

    3. 我不能用替换修改单词,因为那时打印不能正确打印出来。虽然我还没有进入舞台,但最终我还想包括不规则的过去时期[ᴇᴅɪᴛᴏʀɴᴏᴛᴇand:和不规则的名词,以及]以及

      我不确定你还需要什么来回答我的问题,所以请让我知道任何我无意中遗漏的内容,并且我会填写任何遗漏的内容以帮助更清楚。

4 个答案:

答案 0 :(得分:5)

典型搜索引擎的工作方式如下:

  • 输入字符串被标记化,在字边界处被切断 - 字符偏移开始/结束与每个标记相关联
  • 然后阻止每个令牌 - 我使用Lingua::Stem(或更好,Lingua::Stem::Snowball)这些是Porter词干分析器的略微更新版本
  • 在标记之前,每个标记及其原始字符偏移开始/结束将被保留并编入索引,通常与原始文本的副本一起。这基本上是一个表格,它将术语文本与其原始文档(通常作为标识符)相关联

现在,当一个查询到达时,它也被标记化并且每个标记都被阻止,但这次我们并不关心这些位置。我们查找每个令牌与我们索引的那些令牌,以找到帖子(匹配文档标识符)。我们现在可以检索存储的开始/结束偏移以确定术语在原始文本中的位置。

因此,您确实丢失了索引的后缀(这是用于查找匹配文档的内容),但您保留了原始文本和这些文档的偏移量,因此您可以执行查询突出显示和你应该需要很好的显示东西。

绝对是这项工作的正确工具。主要技巧是确保以相同的方式处理查询和文档。您可以修改原始文档,但实际上,您希望将其转换为类似书籍索引的内容,而不是将其转换为使用正则表达式的字符串 - 如果您确实在使用搜索引擎,那就是。如果您愿意,请查看CPAN上的优秀KinoSearch模块,或查看最初派生自的Apache Lucene项目。

答案 1 :(得分:1)

Text::English模块包含一个Porter词干分析器,这是将相同单词的不同形式视为相同用于匹配目的的常用方法。

答案 2 :(得分:1)

查看verbTenseChanger.pl(http://cogcomp.cs.illinois.edu/page/tools_view/1) 这是自述文件:

##codes for the various tenses are:
#0 - Base Form
#1 - Past Simple
#2 - Past Participle
#3 - 3rd Person Singular
#4 - Present Participle

##Example use:
##my $newTense = changeVerbForm("see",0,4);
##changes tense from base form to the present participle

我通过创建不同的形式来使用它(我猜这包括一个词干分析器):

my @changeverbforms = map changeVerbForm( $search_key, 0, $_ ), 1..4;
my @verbforms;
push (@verbforms, $changeverbforms[0]) unless ($changeverbforms[0] eq "");
push (@verbforms, $changeverbforms[1]) unless ($changeverbforms[1] eq "");
push (@verbforms, $changeverbforms[2]) unless ($changeverbforms[2] eq "");
push (@verbforms, $changeverbforms[3]) unless ($changeverbforms[3] eq "");

然后循环遍历@verbforms(围绕整个搜索引擎perl代码)和我$search_key的所有地方,我也放了or $verbform。还有一些额外的事情要解决,但这是一般的实施(尽管根据我的具体情况)

有关错误在线代码的一些调试,请参阅:https://stackoverflow.com/questions/6459085/need-help-understanding-this-verb-tense-changing-code-please

答案 3 :(得分:0)

我尝试过Lingua :: Stem,Lingua :: Stem :: Snowball和WordNet :: stem,它们都无法阻止最常见的单词。要获得这些简单的单词,您可以在之后运行这个简单的词干分析器,它使用WordNet的.exc(例外?)文件:

1. Download and install WordNet.
2. export WNHOME='/usr/lib/wnres' (if that is the directory containing the dict directory; that's where Cygwin puts it. You'll need that to install Wordnet::QueryData.)
3. cat $WNHOME/dict/*.exc > wordnet.exc  (combine all the .exc files)
4. Make this perl file:

$ cat > stem.pl
use strict;
use warnings;

# Read in WordNet exception files
my $ExcFile = "wordnet.exc";
my %Stems;
open(my $FILE, "<$ExcFile") or die "Could not read $ExcFile: $!";
while (my $line = <$FILE>) {
        chomp($line);
        my ($word, $stem) = split(/\s+/, $line);
        $Stems{$word} = $stem;
}
close($FILE);

while (defined(my $in = <>)) {
        chomp($in); $in =~ s/\r$//;
        $in =~ s/^\s+//;
        $in =~ s/\s+$//;
        next if $in eq '';
        my @words = split(/\s+/, $in);
        foreach my $w (@words) {
                $w = $Stems{$w} if $Stems{$w};
        }
        print "@words\n";
}
<ctrl-D>

然后你可以用

来阻止foo.txt
perl stem.pl < foo.txt

你可能想要在此之前而不是在这一步之后运行其他词干分析器,因为如果他们聪明并且使用词语上下文来阻止(虽然我怀疑他们这样做),他们需要完整的不受限制的行使用,而stem.pl逐字工作。