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

时间:2014-04-19 21:07:23

标签: c# asp.net lucene.net lucene

我在ASP.NET项目搜索中使用Lucene.net标准分析器。但是该搜索不会返回C#,.NET等关键字的结果。但如果我键入C或NET(删除。和#),它就可以工作。在Stackoverflow(也使用Lucene)上,我注意到当我输入.NET时它会在搜索时将其更改为[.NET],我得到的链接表示标准分析器无法处理特殊字符搜索,而且White Space Analyzer不会为我们工作,因为它没有给出预期的结果。任何人都可以帮助SO管理搜索吗?

1 个答案:

答案 0 :(得分:2)

我将在这里更详细地描述SO的作用:

虽然我并不真正了解StackOverflow的实现细节,但在搜索" java"时,您会注意到相同的行为。或者" hibernate",即使它们与标准分析仪没有任何问题。它们将被转化为" [java]"和" [休眠]"。这只是表示标签搜索。在寻找" lucene"的地方不会发生这种情况。或" junit"所以它可能与标签的流行有关。我肯定会怀疑标签标题会以未经分析的形式编入索引。

有趣的例子,请试试" j ++"。这个死胡同的java实现只有8个问题使用SO上的标记,因此它不会触发自动标记搜索。搜索" [j ++]",然后你会看到那些8.搜索" j ++",你会发现任何与那种特殊的语言,但你会发现很多引用

继续,解决问题:

是的,StandardAnalyzer将(不准确地说,请参阅UAX-29了解准确的规则)摆脱所有标点符号。典型的方法是在查询时使用相同的分析器。如果您使用StandardAnalyzer分析您的查询以及索引文档,则您搜索的字词将匹配,上述两个查询字词将缩减为netc,您应该得到结果。

但是现在,您可能会使用StandardAnalyzer来解决问题的 经典示例。这意味着cc++c#将在索引中完全相同地表示,没有办法搜索其中一个而不匹配其他两个!

在我看来,有几种方法可以解决这个问题:

  1. 用洗澡水将宝宝扔出去:使用WhitespaceAnalyzer或其他类似的东西,并失去所有漂亮,花哨的东西StandardAnalyzer来帮助你。

  2. 只需处理那几个小边缘情况:好的,所以Lucene不喜欢标点符号,而且你有一些已知的术语有问题。幸运的是,你有String.Replace。用一些更友好的东西替换它们,比如" c"," cplusplus"和" csharp"。同样,确保它在查询和索引时都完成。 问题是:由于您在分析仪之外进行此操作,因此转换也会影响字段的存储版本,在您向用户显示结果之前强制您将其反转。

  3. 和#2一样,但只是有点发烧友:所以#2可能会正常工作,但是你已经让这些分析器处理转换数据以供消费lucene,它只影响字段的索引版本,而不是存储的字段。为什么不使用它们? Analyzer有一个调用initReader,你可以在分析器堆栈的前面拍一个CharFilter(参见the Analysis package documentation底部的示例向下)。通过分析器运行的文本将在CharFilter之前被StandardTokenizer转换(除了其他东西之外,它可以摆脱标点符号)。例如MappingCharFilter

  4. 你不能继承StandardAnalyzer,但是,你应该实现Analyzer,而不是继承它的实现(参见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方法时用它包装它

相关问题