【问题标题】:Lucene .NET search resultsLucene .NET 搜索结果
【发布时间】:2012-01-25 15:03:14
【问题描述】:

我正在使用此代码进行索引:

public void IndexEmployees(IEnumerable<Employee> employees)
{
    var indexPath = GetIndexPath();
    var directory = FSDirectory.Open(indexPath);

    var indexWriter = new IndexWriter(directory, new StandardAnalyzer(Version.LUCENE_29), true, IndexWriter.MaxFieldLength.UNLIMITED);

    foreach (var employee in employees)
    {
        var document = new Document();
        document.Add(new Field("EmployeeId", employee.EmployeeId.ToString(), Field.Store.YES, Field.Index.NO, Field.TermVector.NO));
        document.Add(new Field("Name", employee.FirstName + " " + employee.LastName, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO));
        document.Add(new Field("OfficeName", employee.OfficeName, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO));
        document.Add(new Field("CompetenceRatings", string.Join(" ", employee.CompetenceRatings.Select(cr => cr.Name)), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO));

        indexWriter.AddDocument(document);
    }

    indexWriter.Optimize();
    indexWriter.Close();

    var indexReader = IndexReader.Open(directory, true);
    var spell = new SpellChecker.Net.Search.Spell.SpellChecker(directory);
    spell.ClearIndex();

    spell.IndexDictionary(new LuceneDictionary(indexReader, "Name"));
    spell.IndexDictionary(new LuceneDictionary(indexReader, "OfficeName"));
    spell.IndexDictionary(new LuceneDictionary(indexReader, "CompetenceRatings"));
}

public DirectoryInfo GetIndexPath()
{
    return new DirectoryInfo(HttpContext.Current.Server.MapPath("/App_Data/EmployeeIndex/"));
}

以及此代码查找结果(以及建议):

public SearchResult Search(DirectoryInfo indexPath, string[] searchFields, string searchQuery)
{
    var directory = FSDirectory.Open(indexPath);

    var standardAnalyzer = new StandardAnalyzer(Version.LUCENE_29);

    var indexReader = IndexReader.Open(directory, true);
    var indexSearcher = new IndexSearcher(indexReader);

    var parser = new MultiFieldQueryParser(Version.LUCENE_29, searchFields, standardAnalyzer);
    //parser.SetDefaultOperator(QueryParser.Operator.OR);
    var query = parser.Parse(searchQuery);

    var hits = indexSearcher.Search(query, null, 5000);

    return new SearchResult
                {
                    Suggestions = FindSuggestions(indexPath, searchQuery),
                    LuceneDocuments = hits
                        .scoreDocs
                        .Select(scoreDoc => indexSearcher.Doc(scoreDoc.doc))
                        .ToArray()
                };
}

public string[] FindSuggestions(DirectoryInfo indexPath, string searchQuery)
{
    var directory = FSDirectory.Open(indexPath);

    var spell = new SpellChecker.Net.Search.Spell.SpellChecker(directory);

    var similarWords = spell.SuggestSimilar(searchQuery, 20);

    return similarWords;
}

var searchResult = Search(GetIndexPath(), new[] { "Name", "OfficeName", "CompetenceRatings" }, "admin*");

简单的查询,如:admin 或 admin* 不会给我任何结果。我知道有一个员工叫这个名字。如果我搜索 James,我希望能够找到 James Jameson。

谢谢!

【问题讨论】:

  • 除非您向我们展示您调用 Search() 的代码,否则我们应该如何知道您的搜索方式?更具体地说,您传递了哪些参数。
  • jishi:对不起,我在问题中包含了对搜索方法的调用: var searchResult = Search(GetIndexPath(), new[] { "Name", "OfficeName", "CompetenceRatings" }, "管理员*");

标签: c# c#-4.0 lucene lucene.net


【解决方案1】:

第一件事。您必须提交对索引的更改。

indexWriter.Optimize();
indexWriter.Commit(); //Add This
indexWriter.Close();

编辑#2 另外,保持简单,直到你得到一些有用的东西。

注释掉这些东西。

//var indexReader = IndexReader.Open(directory, true);
//var spell = new SpellChecker.Net.Search.Spell.SpellChecker(directory);
//spell.ClearIndex();

//spell.IndexDictionary(new LuceneDictionary(indexReader, "Name"));
//spell.IndexDictionary(new LuceneDictionary(indexReader, "OfficeName"));
//spell.IndexDictionary(new LuceneDictionary(indexReader, "CompetenceRatings"));

编辑#3

您正在搜索的字段可能不会经常更改。我会将它们包含在您的搜索功能中。

string[] fields = new string[] { "Name", "OfficeName", "CompetenceRatings" };

我建议这样做的最大原因是字段区分大小写,有时您不会得到任何结果,这是因为您搜索“名称”字段(不存在)而不是“名称”字段。这样更容易发现错误。

【讨论】:

  • 正是这种“错误”让人头撞桌子。
  • 太好了,现在我得到了结果。我会做一些测试,看看它现在是否按预期工作。谢谢!
  • 稍微说明一下,close() 方法实际上会将所有更改提交到索引,所以这里的commit调用没有什么帮助
  • API 声明 commit()“提交所有未决更改”和 close()“提交所有更改”什么是未决更改与非未决更改?
  • 感谢 SharpBarb。我的代码正在运行。我还有一个问题,因为 SpellChecker 索引覆盖了我原来的索引。我也解决了这个问题。我想将字段保留为参数,因为我想使用该方法搜索多个索引。
【解决方案2】:

在我使用 Lucene 的(有限)经验中,我发现您必须建立自己的查询才能获得类似“google”的行为。这是我所做的,YMMV,但它会在我的应用程序中产生预期的结果。基本思想是结合一个词条查询(完全匹配)、一个前缀查询(任何以该词条开头的东西)和对搜索字符串中每个词条的模糊查询。下面的代码不会编译,但会给你思路

Query GetQuery(string querystring)
{

   Search.Search.BooleanQuery query = new Search.Search.BooleanQuery();

   Search.Analysis.TokenStream tk = StandardAnalyzerInstance.TokenStream(null, new StringReader(querystring));
   Search.Analysis.Tokenattributes.TermAttribute ta = tk.GetAttribute(typeof(Search.Analysis.Tokenattributes.TermAttribute)) as Search.Analysis.Tokenattributes.TermAttribute;

    while (tk.IncrementToken())
    {
         string term = ta.Term();
         Search.Search.BooleanQuery bq = new Search.Search.BooleanQuery();
         bq.Add(new Search.Search.TermQuery(new Search.Index.Term("fieldToQuery", term)), Search.Search.BooleanClause.Occur.SHOULD);
         bq.Add(new Search.Search.PrefixQuery(new Search.Index.Term("fieldToQuery", term)), Search.Search.BooleanClause.Occur.SHOULD);
         bq.Add(new Search.Search.FuzzyQuery(new Search.Index.Term("fieldToQuery", term)), Search.Search.BooleanClause.Occur.SHOULD);
         query.Add(bq, Search.Search.BooleanClause.Occur.MUST);
    }

    return query;
}

【讨论】:

  • 我已经重写了您的代码:pastebin.com/Kt4VqAtA(此处粘贴时间过长)。但是它没有给我任何结果。调用该方法的行如下所示: var query = BuildQuery(standardAnalyzer, searchFields, searchQuery);并替换 var parser = new MultiFieldQueryParser(Version.LUCENE_29, searchFields, standardAnalyzer); var query = parser.Parse(searchQuery);部分来自上面的示例。
  • 试试这个:pastebin.com/M2cpHrQe。我唯一能想到的改变取决于我们的应用程序 - 添加子查询时,我使用 MUST,这意味着每个术语的某种形式必须在每个字段中。这对您的应用程序可能过于严格,在这种情况下,您可以将查询修改为不那么严格。
  • 乔,谢谢你的建议。我仍然无法得到任何结果。
  • Joe,我最终使用了您的示例中稍微修改过的方法。它给了我更好的结果。谢谢!
【解决方案3】:

Parse() 方法是继承的。您是否尝试过使用返回 Query 对象的静态方法?

Parse(Version matchVersion, String[] queries, String[] fields, Analyzer analyzer)

【讨论】:

  • 我已将代码更新为: var query = MultiFieldQueryParser.Parse(Version.LUCENE_29, Enumerable.Repeat(searchQuery, searchFields.Length).ToArray(), searchFields, standardAnalyzer);我仍然没有得到任何结果。
  • 然后首先使用 Luke 或等效工具检查您的索引,并确保您的索引实际上返回任何查询的任何结果。
猜你喜欢
  • 2011-09-26
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 2013-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多