【问题标题】:Using a Combination of Wildcards and Stemming使用通配符和词干的组合
【发布时间】:2012-02-24 14:03:52
【问题描述】:

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

例子:

搜索“valv”、“valve”或“valves”会返回相同数量的结果。这是有道理的,因为雪球分析仪将所有内容简化为“阀门”。

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

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    我更喜欢解决方案 #2。

    【讨论】:

    • +1 表示第二种解决方案,这是最自然的方式。
    • Lucene 4.7.2+(2014 年发布)的 KeywordRepeatFilter 完全符合解决方案 2 的描述,并且与官方的词干过滤器兼容。
    【解决方案2】:

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

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

    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 中调用您的分析仪,而不是在PrefixQuerys 中调用

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

    【讨论】:

    • 我真的很想找到一种方法来合并两个令牌流,这样我就可以拥有一组词干和非词干的令牌......我将对此进行一些研究。如果我有办法,我会更新。
    【解决方案3】:

    这是最简单的解决方案,它会起作用 -

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

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

    还要在“索引”分析器的末尾添加 RemoveDuplicatesTokenFilterFactory

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-08
        • 2012-09-24
        • 2015-01-28
        相关资源
        最近更新 更多