MultiFieldQueryParser 和通配符
MultiFieldQueryParser and wildcards
我正在尝试设置 lucene.net 3 以便能够在两个字段中搜索一个词组,但遇到问题。这是我想要查询 return:
我希望查询 return 精确短语匹配,例如:
短语:"CHING WAN HUNG SOOTHING HERBAL BALM"
结果:"CHING WAN HUNG SOOTHING HERBAL BALM"
以及通配符匹配:
短语:"CHING WAN HUNG SOO" 或 "CHING WAN HUN"
结果:"CHING WAN HUNG SOOTHING HERBAL BALM" 和其他可能与该短语或该短语的任何其他不完整变体匹配的其他人。
我最初的解决方案是创建一个布尔查询,其中包含短语查询和解析每个单词并使用通配符的查询。
但是这个 return 匹配以及太多不接近适用的结果。 (它会 return "HERBAL TEA" 因为 "HERBAL" 是解析的术语之一......)由于解析的 OR 查询。
这与我拥有的原始 post 有关:How to set up a query to return phrases and parts of phrases in lucene.net? 想知道我是否可以在标准 Lucene.net 中执行此操作而不求助于提到的 Java 端口.
有人可以给我任何指导吗?
谢谢!
public override List<TT> ExecuteSearch(string searchQuery, string searchField = "")
{
if (string.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", ""))) return new List<TT>();
using (var searcher = new IndexSearcher(Directory, false))
{
var hits_limit = 1000;
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30, new HashSet<string>());
var fields = new[] {"CompositeName", "SubstanceName"};
var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, fields, analyzer);
parser.AllowLeadingWildcard = true;
parser.PhraseSlop = 0;
var query = ParseWholeQueryWc(searchQuery, fields, parser);
searcher.SetDefaultFieldSortScoring(true, true);
var hits = searcher.Search(query, null, hits_limit, Sort.RELEVANCE).ScoreDocs;
var results = MapLuceneToDataList(hits, searcher);
analyzer.Close();
searcher.Dispose();
return results;
}
}
public Query ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser)
{
Query query = new PhraseQuery();
Query query2 = new PhraseQuery();
Query mq = new BooleanQuery();
try
{
var bld = ParseTermWithWildcards(searchQuery);
// phrase
query = parser.Parse("\"" + searchQuery.Trim() + "\"");
// or
query2 = parser.Parse(searchQuery + "*");
// main
((BooleanQuery)mq).Add(query, Occur.SHOULD);
((BooleanQuery)mq).Add(query2, Occur.SHOULD);
}
catch (ParseException ex)
{
throw;
}
return mq;
}
更新
public BooleanQuery ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser)
{
BooleanQuery mq = new BooleanQuery();
try
{
string[] qrArr = searchQuery.Split(null);
SpanQuery[] compNmQ = new SpanQuery[qrArr.Length];
SpanQuery[] subsNmQ = new SpanQuery[qrArr.Length];
for (var i = 0; i < qrArr.Length; i++)
{
//CompositeName", "SubstanceName
if (i == qrArr.Length - 1)
{
compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i] + "*"));
subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i] + "*"));
}
else
{
compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i]));
subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i]));
}
}
SpanQuery compNameQ = new SpanNearQuery(compNmQ, 0, true);
SpanQuery subsNameQ = new SpanNearQuery(subsNmQ, 0, true);
// main
((BooleanQuery) mq).Add(compNameQ, Occur.SHOULD);
((BooleanQuery)mq).Add(subsNameQ, Occur.SHOULD);
}
catch (ParseException ex)
{
throw new ArgumentException("BaseLuceneStrategy:ParseWholeQueryWc():" + ex.Message);
}
return mq;
}
这现在 return 零命中。
如果您只想要求所有条款,而不管它们出现的顺序或接近程度,这是一个简单的解决方法。只需添加:
parser.setDefaultOperator(QueryParser.Operator.AND);
如果您的所有查询都将从您希望匹配的字段的开头开始,那么您可以将该字段更改为未分析。如果不对其进行分析,那么一个简单的通配符查询就可以完成这项工作。但是,如果您希望能够查询类似以下内容,这将不是一个好的解决方案:"HUNG SOOTHING HERBAL"
或者,SpanQueries 来拯救。这在 Java 中肯定更好,因为在 v3.1 中我们可以使用 SpanMultiTermQueryWrapper
,但在 v3.0.3 中(以及 .Net 端口),您可以使用 SpanRegexQuery
:
SpanQuery[] subqueries = new SpanQuery[4];
subqueries[0] = new SpanTermQuery(new Term("field", "CHING"));
subqueries[1] = new SpanTermQuery(new Term("field", "WAN"));
subqueries[2] = new SpanTermQuery(new Term("field", "HUNG"));
subqueries[3] = new SpanRegexQuery(new Term("field", "SOO.*"));
SpanQuery finalQuery = new SpanNearQuery(subqueries, 0, true)
对任何其他字段执行相同的操作,并将它们组合成 BooleanQuery
。
我正在尝试设置 lucene.net 3 以便能够在两个字段中搜索一个词组,但遇到问题。这是我想要查询 return:
我希望查询 return 精确短语匹配,例如:
短语:"CHING WAN HUNG SOOTHING HERBAL BALM"
结果:"CHING WAN HUNG SOOTHING HERBAL BALM"
以及通配符匹配:
短语:"CHING WAN HUNG SOO" 或 "CHING WAN HUN"
结果:"CHING WAN HUNG SOOTHING HERBAL BALM" 和其他可能与该短语或该短语的任何其他不完整变体匹配的其他人。
我最初的解决方案是创建一个布尔查询,其中包含短语查询和解析每个单词并使用通配符的查询。
但是这个 return 匹配以及太多不接近适用的结果。 (它会 return "HERBAL TEA" 因为 "HERBAL" 是解析的术语之一......)由于解析的 OR 查询。
这与我拥有的原始 post 有关:How to set up a query to return phrases and parts of phrases in lucene.net? 想知道我是否可以在标准 Lucene.net 中执行此操作而不求助于提到的 Java 端口.
有人可以给我任何指导吗? 谢谢!
public override List<TT> ExecuteSearch(string searchQuery, string searchField = "")
{
if (string.IsNullOrEmpty(searchQuery.Replace("*", "").Replace("?", ""))) return new List<TT>();
using (var searcher = new IndexSearcher(Directory, false))
{
var hits_limit = 1000;
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30, new HashSet<string>());
var fields = new[] {"CompositeName", "SubstanceName"};
var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, fields, analyzer);
parser.AllowLeadingWildcard = true;
parser.PhraseSlop = 0;
var query = ParseWholeQueryWc(searchQuery, fields, parser);
searcher.SetDefaultFieldSortScoring(true, true);
var hits = searcher.Search(query, null, hits_limit, Sort.RELEVANCE).ScoreDocs;
var results = MapLuceneToDataList(hits, searcher);
analyzer.Close();
searcher.Dispose();
return results;
}
}
public Query ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser)
{
Query query = new PhraseQuery();
Query query2 = new PhraseQuery();
Query mq = new BooleanQuery();
try
{
var bld = ParseTermWithWildcards(searchQuery);
// phrase
query = parser.Parse("\"" + searchQuery.Trim() + "\"");
// or
query2 = parser.Parse(searchQuery + "*");
// main
((BooleanQuery)mq).Add(query, Occur.SHOULD);
((BooleanQuery)mq).Add(query2, Occur.SHOULD);
}
catch (ParseException ex)
{
throw;
}
return mq;
}
更新
public BooleanQuery ParseWholeQueryWc(string searchQuery, string[] fields, QueryParser parser)
{
BooleanQuery mq = new BooleanQuery();
try
{
string[] qrArr = searchQuery.Split(null);
SpanQuery[] compNmQ = new SpanQuery[qrArr.Length];
SpanQuery[] subsNmQ = new SpanQuery[qrArr.Length];
for (var i = 0; i < qrArr.Length; i++)
{
//CompositeName", "SubstanceName
if (i == qrArr.Length - 1)
{
compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i] + "*"));
subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i] + "*"));
}
else
{
compNmQ[i] = new SpanTermQuery(new Term("CompositeName", qrArr[i]));
subsNmQ[i] = new SpanTermQuery(new Term("SubstanceName", qrArr[i]));
}
}
SpanQuery compNameQ = new SpanNearQuery(compNmQ, 0, true);
SpanQuery subsNameQ = new SpanNearQuery(subsNmQ, 0, true);
// main
((BooleanQuery) mq).Add(compNameQ, Occur.SHOULD);
((BooleanQuery)mq).Add(subsNameQ, Occur.SHOULD);
}
catch (ParseException ex)
{
throw new ArgumentException("BaseLuceneStrategy:ParseWholeQueryWc():" + ex.Message);
}
return mq;
}
这现在 return 零命中。
如果您只想要求所有条款,而不管它们出现的顺序或接近程度,这是一个简单的解决方法。只需添加:
parser.setDefaultOperator(QueryParser.Operator.AND);
如果您的所有查询都将从您希望匹配的字段的开头开始,那么您可以将该字段更改为未分析。如果不对其进行分析,那么一个简单的通配符查询就可以完成这项工作。但是,如果您希望能够查询类似以下内容,这将不是一个好的解决方案:"HUNG SOOTHING HERBAL"
或者,SpanQueries 来拯救。这在 Java 中肯定更好,因为在 v3.1 中我们可以使用 SpanMultiTermQueryWrapper
,但在 v3.0.3 中(以及 .Net 端口),您可以使用 SpanRegexQuery
:
SpanQuery[] subqueries = new SpanQuery[4];
subqueries[0] = new SpanTermQuery(new Term("field", "CHING"));
subqueries[1] = new SpanTermQuery(new Term("field", "WAN"));
subqueries[2] = new SpanTermQuery(new Term("field", "HUNG"));
subqueries[3] = new SpanRegexQuery(new Term("field", "SOO.*"));
SpanQuery finalQuery = new SpanNearQuery(subqueries, 0, true)
对任何其他字段执行相同的操作,并将它们组合成 BooleanQuery
。