【问题标题】:How to remove plurals in Lucene.NET?如何在 Lucene.NET 中删除复数?
【发布时间】:2026-01-03 15:05:01
【问题描述】:

我正在尝试从文本中提取一些关键字。它工作得很好,但我需要删除复数。

由于我已经在使用 Lucene 进行搜索,因此我正在尝试使用它从索引词中提取关键字。

第一,我在 RAMDirectory 索引中索引文档,

RAMDirectory idx = new RAMDirectory();
using (IndexWriter writer = 
    new IndexWriter(
        idx,
        new CustomStandardAnalyzer(StopWords.Get(this.Language),
        Lucene.Net.Util.Version.LUCENE_30, this.Language),
        IndexWriter.MaxFieldLength.LIMITED))
{
    writer.AddDocument(createDocument(this._text));
    writer.Optimize();
}

然后,我提取关键字:

var list = new List<KeyValuePair<int, string>>();
using (var reader = IndexReader.Open(directory, true))
{
    var tv = reader.GetTermFreqVector(0, "text");
    if (tv != null)
    {
        string[] terms = tv.GetTerms();
        int[] freq = tv.GetTermFrequencies();

        for (int i = 0; i < terms.Length; i++)
            list.Add(new KeyValuePair<int, string>(freq[i], terms[i]));
    }
}

在术语列表中,我可以使用“总统”和“总统”等术语
我怎样才能删除它?
我的 CustomStandardAnalyzer 使用这个:

public override TokenStream TokenStream(string fieldName, System.IO.TextReader reader)
{
    //create the tokenizer
    TokenStream result = new StandardTokenizer(this.version, reader);

    //add in filters
    result = new Lucene.Net.Analysis.Snowball.SnowballFilter(result, this.getStemmer()); 
    result = new LowerCaseFilter(result);
    result = new ASCIIFoldingFilter(result);
    result = new StopFilter(true, result, this.stopWords ?? StopWords.English);

    return result;
}

所以我已经使用了 SnowballFilter(带有正确的语言特定词干分析器)。 如何删除复数?

【问题讨论】:

  • 它必须是您未显示的部分代码中的某些内容,如果您使用 Porter Stemmer,您向我们展示的内容应该可以工作。我会把一些基本上属于你的代码和一些我硬编码的东西(词干)放在一起,它可以工作。

标签: c# .net lucene.net stemming lemmatization


【解决方案1】:

以下程序的输出是:

text:and
text:presid
text:some
text:text
text:with
class Program
{
    private class CustomStandardAnalyzer : Analyzer
    {
        public override TokenStream TokenStream(string fieldName, System.IO.TextReader reader)
        {
            //create the tokenizer
            TokenStream result = new StandardTokenizer(Lucene.Net.Util.Version.LUCENE_30, reader);
            //add in filters
            result = new Lucene.Net.Analysis.Snowball.SnowballFilter(result, new EnglishStemmer()); 
            result = new LowerCaseFilter(result);
            result = new ASCIIFoldingFilter(result);
            result = new StopFilter(true, result, new HashSet<string>());
            return result;
        }
    }

    private static Document createDocument(string text)
    {
        Document d = new Document();
        Field f = new Field("text", "", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS);
        f.SetValue(text);
        d.Add(f);
        return d;
    }

    static void Main(string[] args)
    {

        RAMDirectory idx = new RAMDirectory();
        using (IndexWriter writer =
            new IndexWriter(
                idx,
                new CustomStandardAnalyzer(),
                IndexWriter.MaxFieldLength.LIMITED))
        {
            writer.AddDocument(createDocument("some text with president and presidents"));
            writer.Commit();
        }

        using (var reader = IndexReader.Open(idx, true))
        {
            var terms = reader.Terms(new Term("text", ""));
            if (terms.Term != null)
                do
                    Console.WriteLine(terms.Term);
                while (terms.Next());
        }
        Console.ReadLine();

    }
}

【讨论】:

  • 感谢您的帮助。问题是我要检索关键字,而“presid”不是关键字,它应该返回“president”。我尝试使用 SnowballFilter,但它阻止了这个词,这与“只是”删除复数不同。关键字必须是现有字词,因为用户可以看到它
  • 嗯好的,现在我明白了。我不知道在 .NET 中是否已经做过类似的事情,但是 Solr (java) 有 solr.EnglishMinimalStemFilterFactory,它是一个只处理复数形式的词干分析器
  • 我去看看这个类的代码源,看看能不能转换成c#。我还在 c# 中找到了另一个复数删除器代码。但两者都只适用于英语,我的包必须支持至少 3 种语言(en、fr、nl)。