c# - 哪个Lucene SearchAnalyzer用于特殊字符搜索

标签 c# asp.net lucene.net lucene

我在ASP.NET项目搜索中使用Lucene.net标准分析器。但是该搜索不会返回诸如C#、. NET等关键字的结果。但是,如果我键入C或NET(删除。和#),它将起作用。在Stackoverflow(也使用Lucene)上,我注意到当我键入.NET时,它将在搜索时将其更改为[.NET]。我得到的链接说Standard Analyzer无法处理特殊字符搜索,而White Space Analyzer无法处理为我们工作,因为它无法带来预期的结果。谁能帮忙SO如何管理搜索?

最佳答案

在这里,我将更详细地描述SO正在做什么:

尽管我并不真正了解StackOverflow的实现细节,但是即使在标准分析器中没有问题的情况下,在搜索“ java”或“休眠”时您也会注意到相同的行为。它们将被转换为“ [java]”和“ [hibernate]”。这仅表示标签搜索。搜索“ lucene”或“ junit”不会发生这种情况,因此可能与标签的普及程度有关。我肯定会怀疑标记标题将以未经分析的形式被索引。

对于一个有趣的示例,请尝试“ j ++”。这个死胡同的Java实现在SO上使用标记只有8个问题,因此不会触发自动标记搜索。搜索“ [j ++]”,您将看到这8个。搜索“ j ++”,您将很难找到与该特定语言相关的任何内容,但您会发现很多引用的内容。

接下来,要解决您的问题:

是的,StandardAnalyzer(确切地说,请参见UAX-29)将消除所有标点符号。典型的解决方法是在查询时使用相同的分析器。如果使用StandardAnalyzer分析查询和索引文档,则搜索到的术语将匹配,上面提到的两个查询术语将被简化为netc,您应该会得到结果。

但是现在,您已经遇到了StandardAnalyzer问题的经典示例。这意味着cc++c#在索引中都将完全相同地表示,如果不匹配其他两个,就无法搜索一个!

我认为有几种方法可以解决此问题:


用洗澡水把婴儿扔出去:使用WhitespaceAnalyzer或类似的东西,并丢掉StandardAnalyzer帮助您摆脱困境的所有美好事物。
只需处理一些小问题:好的,Lucene不喜欢标点符号,并且您有一些已知的术语对此有问题。幸运的是,您有String.Replace。用更友好的Lucene代替它们,例如“ c”,“ cplusplus”和“ csharp”。再次,确保它在查询和索引时都完成。问题是:由于您是在分析器外部执行此操作,因此转换也会影响该字段的存储版本,从而迫使您在向用户显示结果之前将其反转。
这样做与#2相同,但有点儿幻想:所以#2可能工作正常,但是您已经使这些分析器处理由Lucene消耗的转换数据,这仅影响字段的索引版本,而不影响字段的索引版本。存储一个。为什么不使用它们?分析器有一个调用initReader,您可以在分析器堆栈的前面打一个CharFilter(请参见the Analysis package documentation底部的示例方法)。通过分析器运行的文本将由CharFilter转换,然后再移至StandardTokenizer(除掉标点符号之外的其他内容)。例如,MappingCharFilter


但是,您不能将StandardAnalyzer子类化,以为您应该实现分析器,而不是将其实现子类化(请参见the discussion here,如果您对其中的思维过程更完整的讨论感兴趣)。因此,假设我们要确保在交易中获得StandardAnalyzer的所有功能,只需复制粘贴源代码,并添加initReaders方法的覆盖:

public class ExtraFancyStandardAnalyzer extends StopwordAnalyzerBase {

    public static final int DEFAULT_MAX_TOKEN_LENGTH = 255;

    private int maxTokenLength = DEFAULT_MAX_TOKEN_LENGTH;

    public static final CharArraySet STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET;

    public ExtraFancyStandardAnalyzer(Version matchVersion,
            CharArraySet stopWords) {
        super(matchVersion, stopWords);
        buildMap();
    }

    public ExtraFancyStandardAnalyzer(Version matchVersion) {
        this(matchVersion, STOP_WORDS_SET);
    }

    public ExtraFancyStandardAnalyzer(Version matchVersion, Reader stopwords)
            throws IOException {
        this(matchVersion, loadStopwordSet(stopwords, matchVersion));
    }

    public void setMaxTokenLength(int length) {
        maxTokenLength = length;
    }

    public int getMaxTokenLength() {
        return maxTokenLength;
    }


    // The following two methods, and a call to buildMap() in the ctor
    // are the only things changed from StandardAnalyzer

    private NormalizeCharMap map;

    public void buildMap() {
        NormalizeCharMap.Builder builder = new NormalizeCharMap.Builder();
        builder.add("c++", "cplusplus");
        builder.add("c#", "csharp");
        map = builder.build();
    }

    @Override
    protected Reader initReader(String fieldName, Reader reader) {
        return new MappingCharFilter(map, reader);
    }

    @Override
    protected TokenStreamComponents createComponents(final String fieldName,
            final Reader reader) {
        final StandardTokenizer src = new StandardTokenizer(matchVersion,
                reader);
        src.setMaxTokenLength(maxTokenLength);
        TokenStream tok = new StandardFilter(matchVersion, src);
        tok = new LowerCaseFilter(matchVersion, tok);
        tok = new StopFilter(matchVersion, tok, stopwords);
        return new TokenStreamComponents(src, tok) {
            @Override
            protected void setReader(final Reader reader) throws IOException {
                src.setMaxTokenLength(ExtraFancyStandardAnalyzer.this.maxTokenLength);
                super.setReader(reader);
            }
        };
    }
}


注意:这是用Java Lucene 4.7版编写和测试的。 C#的实现应该没有太大的不同。复制StandardAnalyzer,构建一个MappingCharFilter(实际上,在3.0.3版本中,这只是一个简单的处理),然后将阅读器包装在initReader方法的替代中。

关于c# - 哪个Lucene SearchAnalyzer用于特殊字符搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23175560/

相关文章:

c# - 有条件的分组、求和、相减

c# - ASP、Server.CreateObject、MTS 和 C# 对象池——重用问题?

asp.net - 将网页上的第二个按钮设为默认的 Enter 键

c# - 更改 DateTimePicker 日历运行时

c# - 如何在 WinForms 中将字典绑定(bind)到列表框

c# - .Net 表单 POST

c# - 在 ASP.NET Core WebAPI 中获取 OData 计数

indexing - Lucene支持多级索引吗?

.net - Lucene.Net最佳实践

c# - Lucene.NET(字符串模糊匹配)