使用通配符和词干的组合

时间:2012-02-01 21:17:09

标签: search lucene full-text-search lucene.net

我正在使用雪球分析器来阻止多个文档的标题。一切都运作良好,但他们是一些怪癖。

示例:

搜索“valv”,“valve”或“valve”会返回相同数量的结果。这是有道理的,因为雪球分析仪将所有内容减少到“valv”。

使用通配符时遇到问题。搜索“valve *”或“valve *”不会返回任何结果。搜索“valv *”按预期工作。

我理解为什么会这样,但我不知道如何解决它。

我考虑过编写一个存储词干和非词干标记的分析器。基本上应用两个分析器并组合两个令牌流。但我不确定这是否是一个实用的解决方案。

我还考虑过使用AnalyzingQueryParser,但我不知道如何将它应用于多字段查询。此外,使用AnalyzingQueryParser会在搜索“valve *”时返回“valve”的结果,这不是预期的行为。

是否有一种利用通配符和词干算法的“首选”方式?

4 个答案:

答案 0 :(得分:8)

之前我使用了两种不同的方法来解决这个问题
  1. 使用两个字段,一个包含词干术语,另一个包含由StandardAnalyzer生成的术语。解析搜索查询时,如果在“标准”字段中进行通配符搜索,则不使用带有词干术语的字段。如果您让用户直接在Lucene的QueryParser中输入查询,则可能更难使用。

  2. 编写自定义分析器和索引重叠标记。它基本上包括使用PositionIncrementAttribute索引原始术语和索引中相同位置的词干。您可以查看SynonymFilter以获取有关如何正确使用PositionIncrementAttribute的示例。

  3. 我更喜欢解决方案#2。

答案 1 :(得分:1)

我认为没有一种简单的方法(且正确)。

我的解决方案是编写一个自定义查询解析器,找到索引中的术语和搜索条件所共有的最长字符串。

class MyQueryParser : Lucene.Net.QueryParsers.QueryParser
{
    IndexReader _reader;
    Analyzer _analyzer;

    public MyQueryParser(string field, Analyzer analyzer,IndexReader indexReader) : base(field, analyzer)
    {
        _analyzer = analyzer;
        _reader = indexReader;
    }

    public override Query GetPrefixQuery(string field, string termStr)
    {
        for(string longestStr = termStr; longestStr.Length>2; longestStr = longestStr.Substring(0,longestStr.Length-1))
        {
            TermEnum te = _reader.Terms(new Term(field, longestStr));
            Term term = te.Term();
            te.Close();
            if (term != null && term.Field() == field && term.Text().StartsWith(longestStr))
            {
                return base.GetPrefixQuery(field, longestStr);
            }
        }

        return base.GetPrefixQuery(field, termStr);
    }
}

您还可以尝试在GetPrefixQuery中调用您的分析器,而不是PrefixQuery

TokenStream ts = _analyzer.TokenStream(field, new StringReader(termStr));
Lucene.Net.Analysis.Token token = ts.Next();
var termstring = token.TermText();
ts.Close();
return base.GetPrefixQuery(field, termstring);

但是,请注意,您始终可以找到返回结果不正确的情况。这就是Lucene在使用通配符时不考虑分析器的原因。

答案 2 :(得分:1)

这是最简单的解决方案,它可行 -

在'index'分析器中添加solr.KeywordRepeatFilterFactory。

http://lucene.apache.org/core/4_8_0/analyzers-common/org/apache/lucene/analysis/miscellaneous/KeywordRepeatFilterFactory.html

在'index'分析器末尾添加RemoveDuplicatesTokenFilterFactory

现在在您的索引中,您将始终拥有同一位置上每个标记的词干和非词干形式,您可以继续使用。

答案 3 :(得分:0)

除了其他答案之外,我唯一的潜在想法是对两个字段使用dismax,因此您可以设置两个字段的相对权重。唯一需要注意的是,某些版本的dismax没有处理通配符,而且有些解析器是特定于Solr的。