C# 为什么MultiFieldQueryParser比手工创建查询慢得多?

C# 为什么MultiFieldQueryParser比手工创建查询慢得多?,c#,lucene.net,C#,Lucene.net,我正在使用Lucene.net为产品目录编制索引。我正在使用ANTS Profiler分析我的搜索,我注意到使用MultiFieldQueryParser创建和解析查询所花费的时间几乎与实际搜索所花费的时间一样长(大约100毫秒)。然后我尝试手动创建查询,速度非常快(大约1毫秒)。我宁愿不必手动解析,尽管它确实给了我相同的结果集,但我担心我可能无法处理某些用例或输入(尽管输入来自网站上的文本搜索,用户对Lucene的搜索语法一无所知)。我的代码(使用这两种方法)如下所示: IAp

我正在使用Lucene.net为产品目录编制索引。我正在使用ANTS Profiler分析我的搜索,我注意到使用MultiFieldQueryParser创建和解析查询所花费的时间几乎与实际搜索所花费的时间一样长(大约100毫秒)。然后我尝试手动创建查询,速度非常快(大约1毫秒)。我宁愿不必手动解析,尽管它确实给了我相同的结果集,但我担心我可能无法处理某些用例或输入(尽管输入来自网站上的文本搜索,用户对Lucene的搜索语法一无所知)。我的代码(使用这两种方法)如下所示:

        IApplicationSettings settings = new ApplicationSettingService();
        FSDirectory directory = FSDirectory.Open(new DirectoryInfo(settings.GetSetting<string>("LuceneMainSearchDirectory")));
        RAMDirectory ramDir = new RAMDirectory(directory);
        _Searcher = new IndexSearcher(ramDir, true);        
        string[] searchFields = new string[] { "ProductName", "ProductLongDescription", "BrandName", "CategoryName" };

        //Add a wildcard character to end of search to give broader results 
        if (!searchTerm.EndsWith(" ")) { searchTerm = searchTerm + "*"; }


        //Use query parser...this  block typically takes about 100ms on my machine, roughly 40% on the constructor and 60% on the call to Parse
        MultiFieldQueryParser multiParser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_29, searchFields, _analyzer);
        multiParser.SetDefaultOperator(QueryParser.AND_OPERATOR);
        Query query = multiParser.Parse(searchTerm);



        //Manually create query....this block doesn't even take 1ms on my machine
        BooleanQuery booleanQuery = new BooleanQuery(true);
        var terms = searchTerm.Split(' ');
        foreach (string s in terms)
        {
            BooleanQuery subQuery = new BooleanQuery(true);
            if (!s.EndsWith("*"))
            {
                Query query1 = new TermQuery(new Term("ProductName", s));
                Query query2 = new TermQuery(new Term("ProductLongDescription", s));
                Query query3 = new TermQuery(new Term("BrandName", s));
                Query query4 = new TermQuery(new Term("CategoryName", s));
                subQuery.Add(query1, BooleanClause.Occur.SHOULD);
                subQuery.Add(query2, BooleanClause.Occur.SHOULD);
                subQuery.Add(query3, BooleanClause.Occur.SHOULD);
                subQuery.Add(query4, BooleanClause.Occur.SHOULD);
            }
            else
            {
                Query query1 = new WildcardQuery(new Term("ProductName", s));
                Query query2 = new WildcardQuery(new Term("ProductLongDescription", s));
                Query query3 = new WildcardQuery(new Term("BrandName", s));
                Query query4 = new WildcardQuery(new Term("CategoryName", s));
                subQuery.Add(query1, BooleanClause.Occur.SHOULD);
                subQuery.Add(query2, BooleanClause.Occur.SHOULD);
                subQuery.Add(query3, BooleanClause.Occur.SHOULD);
                subQuery.Add(query4, BooleanClause.Occur.SHOULD);
            }
            booleanQuery.Add(subQuery, BooleanClause.Occur.MUST);
        }


    //Run the search....results are the same for simple multiword text queries
        var result2 = _Searcher.Search(booleanQuery, null, maxResults);
        var result = _Searcher.Search(query, null, maxResults);
iaapplicationsettings settings=newapplicationsettingservice();
FSDirectory=FSDirectory.Open(newdirectoryinfo(settings.GetSetting(“LuceneMainSearchDirectory”));
RAMDirectory ramDir=新的RAMDirectory(目录);
_Searcher=newindexsearcher(ramDir,true);
字符串[]搜索字段=新字符串[]{“ProductName”、“ProductLongDescription”、“BrandName”、“CategoryName”};
//在搜索结束处添加通配符以提供更广泛的结果
如果(!searchTerm.EndsWith(“”){searchTerm=searchTerm+“*”;}
//使用查询解析器…在我的机器上,这个块通常需要大约100毫秒,在构造函数上大约需要40%,在调用解析时需要60%
MultiFieldQueryParser multiParser=新的MultiFieldQueryParser(Lucene.Net.Util.Version.Lucene_29,searchFields,_analyzer);
Multipasser.SetDefaultOperator(QueryParser.AND_运算符);
Query=multiParser.Parse(searchTerm);
//手动创建查询…此块在我的机器上甚至不需要1ms
BooleanQuery BooleanQuery=新的BooleanQuery(true);
var术语=searchTerm.Split(“”);
foreach(字符串s的术语)
{
BooleanQuery子查询=新的BooleanQuery(true);
如果(!s.EndsWith(“*”))
{
Query query1=新术语查询(新术语(“产品名称”),s);
查询查询2=新术语查询(新术语(“ProductLongDescription”,s));
查询查询3=新术语查询(新术语(“品牌名称”),s);
查询查询4=新术语查询(新术语(“CategoryName”,s));
Add(query1,BooleanClause.occure.SHOULD);
Add(query2,BooleanClause.occure.SHOULD);
Add(query3,BooleanClause.occure.SHOULD);
Add(query4,BooleanClause.occure.SHOULD);
}
其他的
{
Query query1=新的通配符查询(新术语(“ProductName”,s));
查询query2=新的通配符查询(新术语(“ProductLongDescription”,s));
查询查询3=新的通配符查询(新术语(“品牌名称”),s);
查询查询4=新的通配符查询(新术语(“CategoryName”,s));
Add(query1,BooleanClause.occure.SHOULD);
Add(query2,BooleanClause.occure.SHOULD);
Add(query3,BooleanClause.occure.SHOULD);
Add(query4,BooleanClause.occure.SHOULD);
}
添加(子查询,BooleanClause.occure.MUST);
}
//运行搜索…对于简单的多词文本查询,结果相同
var result2=_Searcher.Search(booleanQuery,null,maxResults);
var result=\u Searcher.Search(query,null,maxResults);
使用手动查询构建保存我的一个选项可能是共享MultiFieldQueryParser,但我收集到它的解析方法不是线程安全的(尽管我只阅读了与java版本相关的内容……如果我在该假设中出错,请纠正我)


我做错了什么,还是这只是野兽的本性?

多字段查询搜索器只在场景下使用多个常规查询搜索器,它会为您要查询的每个字段创建一个查询搜索器

创建
QueryParser
的成本通常高于手工创建
Query

它处理一个复杂的查询Syntax,如下所述:

它还将使用您指定的
分析器
处理搜索查询。如果在索引时使用
分析器
,则必须在搜索代码中使用相同的
分析器
/逻辑。如果你不这样做,你最终会错过结果

如果使用空白分析器进行索引,那么手动构建布尔查询的代码就可以了