2014-01-18 52 views
0

我有一个简单的自定义分析器,似乎正确地在SQL服务器的索引中生成语音哈希。它似乎大多数尝试查询使用我的自定义分析器生成的索引不返回结果。我一直无法找到类似的情况,所以我一定会做错的。用自定义分析器/过滤器搜索返回没有结果

自定义过滤器:

internal class SoundexFilter : TokenFilter 
{ 
    private readonly ITermAttribute _termAttr; 

    private Queue<Token> soundexTokenQueue 
     = new Queue<Token>(); 

    public SoundexFilter(TokenStream input) 
     : base(input) 
    { 
     _termAttr = AddAttribute<ITermAttribute>(); 
    } 

    public override bool IncrementToken() 
    { 
     if (input.IncrementToken()) 
     { 
      string currentTerm = _termAttr.Term; 
      var hash = Soundex.For(currentTerm); 
      Console.WriteLine("Original: {0}, Hash: {1}", currentTerm, hash); 
      soundexTokenQueue.Enqueue(new Token(hash, 0, hash.Length)); 
      return true; 
     } 
     else if (soundexTokenQueue.Count > 0) 
     { 
      var token = soundexTokenQueue.Dequeue(); 

      _termAttr.SetTermBuffer(token.Term); 
      _termAttr.SetTermLength(token.TermLength()); 
      return true; 
     } 

     return false; 
    } 
} 

定制分析器:

public class SoundexAnalyzer : Analyzer 
{ 
    public override TokenStream TokenStream(string fieldName, TextReader reader) 
    { 
     //create the tokenizer 
     TokenStream result = new StandardTokenizer(Version.LUCENE_30, reader); 

     //add in filters 
     result = new StandardFilter(result); 

     // Add soundex filter 
     result = new SoundexFilter(result); 

     return result; 
    } 
} 

简单的测试程序:

public class Program 
{ 
    private const string NAME = "John Smith"; 
    private const string SEARCH_NAME = "John Smith"; 

    private Analyzer _analyzer = new SoundexAnalyzer(); 
    private Directory _directory = new RAMDirectory(); 

    internal void Run(string[] args) 
    { 
     using (var writer = new IndexWriter(_directory, _analyzer, IndexWriter.MaxFieldLength.UNLIMITED)) 
     { 
      var field = new Field("Name", NAME, Field.Store.YES, Field.Index.ANALYZED); 

      var document = new Document(); 

      document.Add(field); 

      writer.AddDocument(document); 

      // Unnecessary but helps imply intent 
      writer.Commit(); 
     } 

     using (var searcher = new IndexSearcher(_directory)) 
     { 
      var parser = new QueryParser(Version.LUCENE_30, "Name", _analyzer); 
      var query = parser.Parse(SEARCH_NAME); 
      var docs = searcher.Search(query, 10); 

      Console.WriteLine("\nReturned Docs:"); 

      foreach (var scoreDoc in docs.ScoreDocs) 
      { 
       var doc = searcher.Doc(scoreDoc.Doc); 

       Console.WriteLine(doc.Get("Name")); 
      } 
     } 
    } 

    private static void Main(string[] args) 
    { 
     new Program().Run(args); 
    } 
} 

该成功使用此代码是唯一的搜索完全匹配像NAME = "John"SEARCH_NAME = "John"

奇怪的是,在Luke中搜索标准分析器的语音哈希工作正常,因此写入必须按预期工作(或者至少是我的期望)。

我已经做了相当多的研究,没有什么帮助。任何想法我失踪?

回答

0

我想出了什么解决了问题,但还没有完全弄清楚为什么这是一个问题。

基本上,我的TokenFilter包含在问题中的实现是试图做太多,似乎不符合Lucene的期望。

通过限制IncrementToken实现只执行语音散列并将ITermAttribute.Term值替换为生成的散列,它的工作原理非常好。

TokenFilter实现:

public class SoundexFilter : TokenFilter 
{ 
    private readonly ITermAttribute _termAttr; 

    public SoundexFilter(TokenStream input) 
     : base(input) 
    { 
     _termAttr = AddAttribute<ITermAttribute>(); 
    } 

    public override bool IncrementToken() 
    { 
     if (input.IncrementToken()) 
     { 
      string currentTerm = _termAttr.Term; 
      // Any phonetic hash calculation will work here. 
      var hash = Soundex.For(currentTerm); 
      _termAttr.SetTermBuffer(hash); 
      return true; 
     } 

     return false; 
    } 
} 

结果,需要在两个索引和查询时间要应用相同的过滤器,但它工作得非常好。

作为一个侧面说明,此过滤器的性能看起来不符合我的预期,所以我将分析解决方案以确定可能的增强功能。我建议任何希望使用这个解决方案的人,如果他们希望有超过200万份文档的索引需要秒以上的响应时间,他们也会这样做。

相关问题