1

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

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 上的文档所说的那样做,如果在文档中找到公司、描述、名称等参数中的任何字段,它将返回匹配项. 但事实并非如此。例如,在其中一个文档中,我知道我有一个“另一个想法”的名称字段。当我搜索“另一个”/“另一个”/“想法”/ 等时,它应该返回那个特定的文档。但它没有......但是,它确实按类型正确过滤了结果。

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

4

2 回答 2

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));

当我开始这样做时,我并不清楚整条路线。

于 2013-04-07T18:59:49.537 回答
0

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

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);
}

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

于 2015-12-03T20:08:58.967 回答