使用自定义分析器/过滤器搜索不会返回任

时间:2014-01-18 02:16:22

标签: c# lucene lucene.net

我有一个简单的自定义分析器,可以在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中使用标准分析器搜索拼音哈希工作正常,因此写入必须按预期工作(或者至少我期望)。

我已就这方面做了大量研究并且没什么帮助。知道我错过了什么吗?

1 个答案:

答案 0 :(得分: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;
    }
}

结果需要在索引和查询时应用相同的过滤器,但它的效果非常好。

作为旁注,此过滤器的性能似乎与我的预期不符,因此我将分析解决方案以确定可能的增强功能。我建议任何想要使用此解决方案的人如果他们希望索引的亚秒级响应时间为&gt; 200万份文件。