使用Lucene对英语单词进行词干提取

29
我是一名有用的助手,可以为您翻译文本。以下是需要翻译的内容:

我正在一个Java应用程序中处理一些英文文本,并且我需要对它们进行词干提取。 例如,从文本“amenities/amenity”中,我需要得到“amenit”。

该函数的样子如下:

String stemTerm(String term){
   ...
}

我找到了Lucene分析器,但它看起来对我所需的太复杂了。 http://lucene.apache.org/java/2_2_0/api/org/apache/lucene/analysis/PorterStemFilter.html 有没有一种方法可以使用它来提取词干而不必构建分析器?我不理解所有这些分析器的业务...
编辑:实际上我需要进行提取词干和词形还原。Lucene能做到吗?

5
为什么需要自己对单词进行词干提取?Lucene有一个叫做SnowballAnalyzer的分析器,你只需要用词干提取器的名称实例化它,例如 new SnowballAnalyzer("English"); - Thomas
Knuth-Pratt算法实现 http://www.fmi.uni-sofia.bg/fmi/logic/vboutchkova/sources/KMPMatch_java.html - Dead Programmer
7个回答

29

SnowballAnalyzer 已经被弃用,你可以使用 Lucene Porter Stemmer 替代:

 PorterStemmer stem = new PorterStemmer();
 stem.setCurrent(word);
 stem.stem();
 String result = stem.getCurrent();

希望这可以帮到您!


3
PorterStemmer不再是公共的(很愚蠢)-请参见https://dev59.com/3G_Xa4cB1Zd3GeqP3q20。 - 8bitjunkie

23
import org.apache.lucene.analysis.PorterStemmer;
...
String stemTerm (String term) {
    PorterStemmer stemmer = new PorterStemmer();
    return stemmer.stem(term);
}

查看这里获取更多详细信息。如果你只想进行词干提取,那么你应该使用这个而不是Lucene。

编辑:在传递给stem()之前,请将term转换为小写。


1
能否将停用词过滤器与词干提取器结合使用? - Mulone
你想从一个包含多个单词的字符串中过滤停用词,还是已经将单词分词并只想检查单个单词?如果只是像上面那样一个单独的术语,那么只需创建一个所有停用词的“Set”并执行“.contains()”操作即可。 - nikhil500
1
截至目前的Lucene版本(3.5),PorterStemmer虽然存在,但不是公开的。我不确定谁/什么在使用它,但我们不能使用。 - Rob Cranfill
PorterStemmer不再是公共的(非常愚蠢)-请参见https://dev59.com/3G_Xa4cB1Zd3GeqP3q20。 - 8bitjunkie

7

为什么你不使用“EnglishAnalyzer”?它很容易使用,我认为它可以解决你的问题:

EnglishAnalyzer en_an = new EnglishAnalyzer(Version.LUCENE_34);
QueryParser parser = new QueryParser(Version.LUCENE_34, "your_field", en_an);
String str = "amenities";
System.out.println("result: " + parser.parse(str)); //amenit

希望能对您有所帮助!

2
这个 "your_field" 是做什么的? 文档上说它是一个神秘的“查询术语的默认字段”。 - André van Schoubroeck
这将其切分为单词,但不进行词干处理。至少对我来说不是。 - alianos-
它只进行非常基本的词干提取。它不会将"began"转换为"begin"。 - Whitecat

5

前面的例子将词干处理应用于搜索查询,因此如果您有兴趣对完整文本进行词干处理,可以尝试以下方法:

import java.io.*;
import org.apache.lucene.analysis.*;
import org.apache.lucene.analysis.tokenattributes.*;
import org.apache.lucene.analysis.snowball.*;
import org.apache.lucene.util.*;
...
public class Stemmer{
    public static String Stem(String text, String language){
        StringBuffer result = new StringBuffer();
        if (text!=null && text.trim().length()>0){
            StringReader tReader = new StringReader(text);
            Analyzer analyzer = new SnowballAnalyzer(Version.LUCENE_35,language);
            TokenStream tStream = analyzer.tokenStream("contents", tReader);
            TermAttribute term = tStream.addAttribute(TermAttribute.class);

            try {
                while (tStream.incrementToken()){
                    result.append(term.term());
                    result.append(" ");
                }
            } catch (IOException ioe){
                System.out.println("Error: "+ioe.getMessage());
            }
        }

        // If, for some reason, the stemming did not happen, return the original text
        if (result.length()==0)
            result.append(text);
        return result.toString().trim();
    }

    public static void main (String[] args){
        Stemmer.Stem("Michele Bachmann amenities pressed her allegations that the former head of her Iowa presidential bid was bribed by the campaign of rival Ron Paul to endorse him, even as one of her own aides denied the charge.", "English");
    }
}

TermAttribute类已被弃用并将不再受到Lucene 4的支持,但文档没有明确说明要使用什么替代。

此外,在第一个示例中,PorterStemmer不可用作类(隐藏),因此您无法直接使用它。

希望这有所帮助。


Giancarlo的答案是正确的,只需将TermAttribute更改为CharTermAttribute,因为TermAttribute已被弃用。 - amas

3

以下是您如何在JAVA中使用Snowball Stemmer:

import org.tartarus.snowball.ext.EnglishStemmer;

EnglishStemmer english = new EnglishStemmer();
String[] words = tokenizer("bank banker banking");
for(int i = 0; i < words.length; i++){
        english.setCurrent(words[i]);
        english.stem();
        System.out.println(english.getCurrent());
}

0

由于PorterStemmer不是公共的,我们无法调用PorterStemmer的词干函数。

相反,我们可以使用KStemmer/KStemFilter将单词变成其根词。

下面是一个Scala代码片段,它接受一个字符串并将其转换为词干字符串:

import org.apache.lucene.analysis.core.WhitespaceTokenizer import org.apache.lucene.analysis.en.KStemFilter

import java.io.StringReader

对象Stemmer { def stem(input:String):String={

val stemmed_string = new StringBuilder()

val inputReader = new StringReader(input.toLowerCase)

val whitespaceTokenizer = new WhitespaceTokenizer()
whitespaceTokenizer.setReader(inputReader)

val kStemmedTokenStream = new KStemFilter(whitespaceTokenizer)
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute

val charTermAttribute = kStemmedTokenStream.addAttribute(classOf[CharTermAttribute])

kStemmedTokenStream.reset
while (kStemmedTokenStream.incrementToken) {
  val term = charTermAttribute.toString
  stemmed_string.append(term+" ")
}
stemmed_string.toString().trim.toUpperCase

}

}


0

Ling pipe 提供了许多分词器。它们可以用于词干提取和停用词去除。这是一种简单而有效的词干提取方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接