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

时间:2013-04-07 11:35:59

标签: asp.net lucene lucene.net

所以,我有一个我想构建的简短查询。我正在使用布尔查询来指定从索引匹配的Document的“type”字段必须是“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上的文档所做的那样,如果在doc中找到公司,描述,名称等参数中的任何字段,它将返回匹配。但事实并非如此。例如,在其中一个文档中,我知道我有一个“另一个想法”的名称字段。当我搜索“另一个”/“另一个”/“想法”/等时,它应该返回该特定文档。但它没有...但它确实按类型正确过滤结果。

我需要做些什么才能让这个简短的代码段返回我想要的匹配项?

2 个答案:

答案 0 :(得分:1)

我想出了如何解决这个问题,事实证明这是一个没有道理的(取决于你对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));

当我开始这个时,整个路线都不清楚。

答案 1 :(得分:0)

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

SELECT c.item1 ,c.id, a.id
FROM table_c as c
INNER JOIN table_a as a ON c.id=a.id
WHERE c.id IN
(
   SELECT id
   FROM table_b
   WHERE someinfo = 'active'
)
AND c.id IS NOT NULL

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

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

能够迭代字段并只有一行来添加通配符查询:

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

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