Search 使用通配符和词干分析的组合

Search 使用通配符和词干分析的组合,search,lucene,full-text-search,lucene.net,Search,Lucene,Full Text Search,Lucene.net,我正在使用雪球分析器来阻止多个文档的标题。一切都很好,但他们的一些怪癖 例如: 搜索“valv”、“valve”或“valves”会返回相同数量的结果。这是有意义的,因为雪球分析仪将所有东西降低到“阀门” 我在使用通配符时遇到问题。搜索“阀*”或“阀*”不会返回任何结果。搜索“valv*”按预期工作 我理解为什么会发生这种情况,但我不知道如何解决它 我考虑编写一个分析器来存储词干标记和非词干标记。基本上应用两个分析器并组合两个令牌流。但我不确定这是否是一个切实可行的解决方案 我还考虑过使用Ana

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

例如:

搜索“valv”、“valve”或“valves”会返回相同数量的结果。这是有意义的,因为雪球分析仪将所有东西降低到“阀门”

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

我理解为什么会发生这种情况,但我不知道如何解决它

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

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


是否有一种“首选”方法可以同时使用通配符和词干算法?

我认为没有一种简单(和正确的)方法可以做到这一点

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

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
s调用的

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在使用通配符时不考虑分析器的原因。

我以前使用了两种不同的方法来解决这个问题

  • 使用两个字段,一个包含词干术语,另一个包含由
    StandardAnalyzer
    生成的术语。解析搜索查询时,如果在“标准”字段中是通配符搜索,则使用带有词干的术语的字段。如果您让用户直接在Lucene的QueryParser中输入他们的查询,那么这可能更难使用

  • 编写自定义分析器并索引重叠标记。它基本上包括使用
    PositionIncrementAttribute
    为索引中相同位置的原始术语和词干编制索引。您可以查看一些示例,了解如何正确使用
    PositionIncrementAttribute


  • 我更喜欢解决方案#2。

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

    这是最简单的解决方案,它可以工作-

    在“索引”分析器中添加solr.KeywordRepeatFilterFactory

    在“索引”分析器的末尾添加RemovedUpplicateStokenFilterFactory


    现在,在索引中,每个标记的词干形式和非词干形式将始终位于同一位置,您可以开始了。

    我真的很想找到一种方法来合并两个标记流,这样我就可以拥有一组词干和非词干的标记。。。我要调查一下这件事。如果找到方法,我会更新。+1对于第二个解决方案,这是最自然的方法。Lucene 4.7.2+的
    关键字RepeatFilter
    (2014年发布)完全符合解决方案2的描述,并且与官方的词干过滤器兼容。