【问题标题】:Apache Lucene fuzzy search for multi-worded phrasesApache Lucene 模糊搜索多词短语
【发布时间】:2018-03-29 10:39:57
【问题描述】:

我有以下 Apache Lucene 7 应用程序:

StandardAnalyzer standardAnalyzer = new StandardAnalyzer();
Directory directory = new RAMDirectory();
IndexWriterConfig config = new IndexWriterConfig(standardAnalyzer);
IndexWriter writer = new IndexWriter(directory, config);
Document document = new Document();

document.add(new TextField("content", new FileReader("document.txt"))); 
writer.addDocument(document);
writer.close();

IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);

Query fuzzyQuery = new FuzzyQuery(new Term("content", "Company"), 2);

TopDocs results = searcher.search(fuzzyQuery, 5);
System.out.println("Hits: " + results.totalHits);
System.out.println("Max score:" + results.getMaxScore())

当我使用它时:

new FuzzyQuery(new Term("content", "Company"), 2);

应用程序运行良好并返回以下结果:

Hits: 1
Max score:0.35161147

但是当我尝试使用多词查询进行搜索时,例如:

new FuzzyQuery(new Term("content", "Company name"), 2);

它返回以下结果:

Hits: 0
Max score:NaN

无论如何,Company name 这个短语存在于源 document.txt 文件中。

在这种情况下如何正确使用FuzzyQuery,以便能够对多词短语进行模糊搜索。

更新

根据提供的解决方案,我已根据以下文本信息对其进行了测试:

Company name: BlueCross BlueShield              Customer Service 
   1-800-521-2227           
                        of Texas                          Preauth-Medical              1-800-441-9188           
                                                          Preauth-MH/CD                1-800-528-7264           
                                                          Blue Card Access             1-800-810-2583     

对于以下查询:

SpanQuery[] clauses = new SpanQuery[2];
clauses[0] = new SpanMultiTermQueryWrapper<FuzzyQuery>(new FuzzyQuery(new Term("content", "BlueCross"), 2));
clauses[1] = new SpanMultiTermQueryWrapper<FuzzyQuery>(new FuzzyQuery(new Term("content", "BlueShield"), 2));
SpanNearQuery query = new SpanNearQuery(clauses, 0, true);

搜索工作正常:

Hits: 1
Max score:0.5753642

但是当我尝试破坏搜索查询时(例如从BlueCrossBlueCros

SpanQuery[] clauses = new SpanQuery[2];
clauses[0] = new SpanMultiTermQueryWrapper<FuzzyQuery>(new FuzzyQuery(new Term("content", "BlueCros"), 2));
clauses[1] = new SpanMultiTermQueryWrapper<FuzzyQuery>(new FuzzyQuery(new Term("content", "BlueShield"), 2));
SpanNearQuery query = new SpanNearQuery(clauses, 0, true);

它停止工作并返回:

Hits: 0
Max score:NaN

【问题讨论】:

    标签: lucene fuzzy-search


    【解决方案1】:

    这里的问题如下,您使用的是TextField,这是标记字段。例如。您的文本 "Company name is working on something" 将被空格(和其他分隔符)有效分割。所以,即使你有文本Company name,在索引期间它也会变成Companynameis等。

    在这种情况下,此 TermQuery 将无法找到您要查找的内容。可以帮助您的技巧如下所示:

    SpanQuery[] clauses = new SpanQuery[2];
        clauses[0] = new SpanMultiTermQueryWrapper(new FuzzyQuery(new Term("content", "some"), 2));
        clauses[1] = new SpanMultiTermQueryWrapper(new FuzzyQuery(new Term("content", "text"), 2));
        SpanNearQuery query = new SpanNearQuery(clauses, 0, true);
    

    但是,我不太推荐这种方法,尤其是当您的负载很大并且您计划搜索 10 个长期公司名称时。应该知道,这些查询执行起来可能很繁重。

    BlueCros 的以下问题如下。默认情况下,Lucene 对 TextField 使用 StandardAnalyzer。所以这意味着它有效地将术语小写,基本上意味着content字段中的BlueCross变成bluecross

    BlueCrosbluecross 之间的模糊差异是 3,这就是你没有匹配的原因。

    简单的建议是将查询中的术语转换为小写,通过类似.toLowerCase()

    一般来说,在查询期间(例如在查询构建期间)也应该更喜欢使用相同的分析器

    【讨论】:

    • 感谢您的回答。我已经用当前结果更新了我的问题。你能检查一下我在哪里做错了吗?
    • @alexanoid 已更新,但是,我建议不要进行进一步的编辑,因为这个问题变得过于广泛和全面
    【解决方案2】:

    对于 Lucene.Net 可以是这样的。

    private string _IndexPath = @"Your Index Path";
    private Directory _Directory;
    private Searcher _IndexSearcher;
    private MultiPhraseQuery _MultiPhraseQuery;
    
    _Directory = FSDirectory.Open(_IndexPath);
    IndexReader indexReader = IndexReader.Open(_Directory, true);
    
    string field = "Name" // Your field name
    string keyword = "big red fox"; // your search term 
    float fuzzy = 0,7f; // between 0-1
    using (_IndexSearcher = new IndexSearcher(indexReader))
    {
        // "big red fox" to [big,red,fox]
        var keywordSplit = keyword.Split();
    
        _MultiPhraseQuery = new MultiPhraseQuery();
        FuzzyTermEnum[] _FuzzyTermEnum = new FuzzyTermEnum[keywordSplit.Length];
        Term[] _Term = new Term[keywordSplit.Length];
    
        for (int i = 0; i < keywordSplit.Length; i++)
        {
            _FuzzyTermEnum[i] = new FuzzyTermEnum(indexReader, new Term(field, keywordSplit[i]),fuzzy);
            _Term[i] = _FuzzyTermEnum[i].Term;
            if (_Term[i] == null)
            {
                _MultiPhraseQuery.Add(new Term(field, keywordSplit[i]));
            }
            else
            {
                _MultiPhraseQuery.Add(_FuzzyTermEnum[i].Term);
            }
        }
    
        var results = _IndexSearcher.Search(_MultiPhraseQuery, indexReader.MaxDoc);
    
        foreach (var loopDoc in results.ScoreDocs.OrderByDescending(s => s.Score))
        {
            //YourCode Here
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-02-22
      • 2013-08-08
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      • 2014-05-04
      • 1970-01-01
      • 2019-05-09
      • 2014-10-22
      相关资源
      最近更新 更多