.NET Lucene:为什么BooleanQuery中的MultiFieldQueryParser和WhitespaceAnalyzer查询不能产生正确的结果,如何解决?



所以,我有一个简短的查询,我想构造。我使用布尔查询来指定与索引匹配的文档的"类型"字段必须是"Idea",然后我有一个由用户给出的搜索字符串,可以是一个或多个单词。我希望能够以编程方式限制结果,以便客户端仅包含索引中字段"type"等于"index"的文档,但我也希望它们的搜索词能够将搜索短语中的任何单词与结果中的单词相匹配。我认为我下面的代码解释了我到底想要什么。

WhitespaceAnalyzer analyzer = new WhitespaceAnalyzer();
MultiFieldQueryParser parser = new MultiFieldQueryParser(
    Version.LUCENE_30, new string[] { "company", "description", 
    "name", "posterName"},
    analyzer);
parser.AllowLeadingWildcard = true;
Lucene.Net.Search.Query query = parser.Parse(searchParam); 
BooleanQuery bq = new BooleanQuery(); 
TermQuery tQuery = new TermQuery(new Lucene.Net.Index.Term("type", "Idea"));
bq.Add(tQuery, Lucene.Net.Search.Occur.MUST);
bq.Add(query, Lucene.Net.Search.Occur.MUST);

我索引数据的方式在下面的简短的相关代码中描述:

Document doc = new Document();
doc.Add(new Field("type",
    "Idea",
    Field.Store.YES,
    Field.Index.ANALYZED));
doc.Add(new Field("company",
    (_idea.Company==null ?
      "Company Not Set for Idea" 
      : _idea.Company.Name),
    Field.Store.YES,
    Field.Index.ANALYZED));
doc.Add(new Field("description",
    _idea.Description,
    Field.Store.YES,
    Field.Index.ANALYZED));
doc.Add(new Field("name",
    _idea.Name,
    Field.Store.YES,Field.Index.ANALYZED));
if (_idea.Poster != null)
{
    doc.Add(new Field("posterName",
      _idea.Poster.FirstName + " " + _idea.Poster.LastName,
      Field.Store.YES, Field.Index.ANALYZED));
}
doc.Add(new Field("ID",
    _idea.ID.ToString(), Field.Store.YES,
    Field.Index.NOT_ANALYZED));
iWriter.AddDocument(doc);

我不明白的是,当我搜索一个我知道存在于索引中的给定单词时,它没有返回任何结果。只有当我用通配符"*"或其他东西搜索时,我才能得到任何结果。我想的是,如果代码完全按照MultiFieldQueryParser上的文档所说的那样做,那么如果在文档中找到公司,描述,名称等参数中的任何字段的任何部分,它将返回匹配。但事实并非如此。例如,在其中一个文档中,我知道我有一个名为"Another Idea"的名称字段。当我搜索"另一个"/"另一个"/"想法"等时,它应该返回特定的文档。但它没有……但是,它可以按类型正确地过滤结果。

我需要做什么才能得到这个短代码片段来返回我想要的匹配?

我想出了如何解决这个问题,结果证明这是一个不需要动脑筋的问题(取决于你对lucene和使用Visual Studio asp项目的了解程度,我不太熟悉)。这是我第一次。

结果表明,您可以使用BooleanQuery对象将不同的查询添加到一起,并指定您希望它们如何一起操作。然后,您可以将所有查询的最终和传递给搜索器。

事实证明,我只是没有分裂对象并创建查询:我已经附上了下面为我工作的示例解决方案:

    StandardAnalyzer analyzer =
        new StandardAnalyzer(Version.LUCENE_30);
    MultiFieldQueryParser mfqp = new MultiFieldQueryParser(
         Version.LUCENE_30, new string[] {"company", "description", 
         "name", "posterName"},
         analyzer);
    mfqp.DefaultOperator = MultiFieldQueryParser.OR_OPERATOR;
         mfqp.AllowLeadingWildcard = true;
         BooleanQuery innerExpr = new BooleanQuery();
         foreach (string s in searchParam.Split(new char[] {' '})) {
             innerExpr.Add(mfqp.Parse(s), Occur.SHOULD);
         }
   innerExpr.Add(new WildcardQuery(new Term("company", searchParam)), Occur.SHOULD);
   innerExpr.Add(new WildcardQuery(new Term("description", searchParam)), Occur.SHOULD);
   innerExpr.Add(new WildcardQuery(new Term("name", searchParam)), Occur.SHOULD);
   innerExpr.Add(new WildcardQuery(new Term("posterName", searchParam)), Occur.SHOULD);
   TermQuery tQuery = new TermQuery(new Term("type", "Idea"));
   //bq.Add(mfqp.Parse(searchParam), Lucene.Net.Search.Occur.MUST);
   TopDocs hits = sharedIndex.Search(innerExpr,
       new QueryWrapperFilter(tQuery), 1000, 
       new Sort(SortField.FIELD_DOC));

当我开始做这个的时候,整个路线对我来说并不清楚。

您可以对该解决方案进行改进,以便适应将来对索引的更改,可以创建一个字符串数组变量来保存字段名称,例如:

string[] allFields = new string[] {"company", "description", 
     "name", "posterName"};

,它反过来会给你一个值,让你把它放入你的解析器:

MultiFieldQueryParser mfqp = new MultiFieldQueryParser(
     Version.LUCENE_30, allFields, analyzer);

和遍历字段的能力,并有单行添加通配符查询:

foreach (string searchField in allFields) {
    innerExpr.Add(new WildcardQuery(new Term(searchField, searchParam)), Occur.SHOULD);
}

然后,在将来,您只需要添加/更改/删除字段名称到数组,而不必管理您的查询列表

最新更新