【发布时间】:2011-10-25 21:35:07
【问题描述】:
给定一个 Lucene 搜索查询,例如:+(letter:A letter:B letter:C) +(style:Capital),我如何判断这三个字母中的哪一个实际上与任何给定文档匹配?我不在乎它们在哪里匹配,或者它们匹配了多少次,我只需要知道它们是否匹配。
目的是获取初始查询(“A B C”),删除成功匹配的术语(A和B),然后对剩余的(C)进行进一步处理。
【问题讨论】:
标签: lucene
给定一个 Lucene 搜索查询,例如:+(letter:A letter:B letter:C) +(style:Capital),我如何判断这三个字母中的哪一个实际上与任何给定文档匹配?我不在乎它们在哪里匹配,或者它们匹配了多少次,我只需要知道它们是否匹配。
目的是获取初始查询(“A B C”),删除成功匹配的术语(A和B),然后对剩余的(C)进行进一步处理。
【问题讨论】:
标签: lucene
虽然示例是用 c# 编写的,但 Lucene API 非常相似(一些大小写差异)。我认为翻译成java并不难。
这是用法
List<Term> terms = new List<Term>(); //will be filled with non-matched terms
List<Term> hitTerms = new List<Term>(); //will be filled with matched terms
GetHitTerms(query, searcher,docId, hitTerms,terms);
这是方法
void GetHitTerms(Query query,IndexSearcher searcher,int docId,List<Term> hitTerms,List<Term>rest)
{
if (query is TermQuery)
{
if (searcher.Explain(query, docId).IsMatch() == true)
hitTerms.Add((query as TermQuery).GetTerm());
else
rest.Add((query as TermQuery).GetTerm());
return;
}
if (query is BooleanQuery)
{
BooleanClause[] clauses = (query as BooleanQuery).GetClauses();
if (clauses == null) return;
foreach (BooleanClause bc in clauses)
{
GetHitTerms(bc.GetQuery(), searcher, docId,hitTerms,rest);
}
return;
}
if (query is MultiTermQuery)
{
if (!(query is FuzzyQuery)) //FuzzQuery doesn't support SetRewriteMethod
(query as MultiTermQuery).SetRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE);
GetHitTerms(query.Rewrite(searcher.GetIndexReader()), searcher, docId,hitTerms,rest);
}
}
【讨论】:
作为@L.B 给出的答案,这是适用于我的 JAVA 转换代码:
void GetHitTerms(Query query,IndexSearcher searcher,int docId,List<Term> hitTerms,List<Term>rest) throws IOException
{
if(query instanceof TermQuery )
{
if (searcher.explain(query, docId).isMatch())
hitTerms.add(((TermQuery) query).getTerm());
else
rest.add(((TermQuery) query).getTerm());
return;
}
if(query instanceof BooleanQuery )
{
for (BooleanClause clause : (BooleanQuery)query) {
GetHitTerms(clause.getQuery(), searcher, docId,hitTerms,rest);
}
return;
}
if (query instanceof MultiTermQuery)
{
if (!(query instanceof FuzzyQuery)) //FuzzQuery doesn't support SetRewriteMethod
((MultiTermQuery)query).setRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE);
GetHitTerms(query.rewrite(searcher.getIndexReader()), searcher, docId,hitTerms,rest);
}
}
【讨论】:
我基本上使用了与@L.B 相同的方法,但更新了它以用于最新的 Lucene 版本 7.4.0。注意:FuzzyQuery 现在支持 .setRewriteMethod(这就是我删除 if 的原因)。
我还包括了对 BoostQuerys 的处理,并将 Lucene 找到的单词保存在 HashSet 中以避免重复而不是条款。
private void saveHitWordInList(Query query, IndexSearcher indexSearcher,
int docId, HashSet<String> hitWords) throws IOException {
if (query instanceof TermQuery)
if (indexSearcher.explain(query, docId).isMatch())
hitWords.add(((TermQuery) query).getTerm().toString().split(":")[1]);
if (query instanceof BooleanQuery) {
for (BooleanClause clause : (BooleanQuery) query) {
saveHitWordInList(clause.getQuery(), indexSearcher, docId, hitWords);
}
}
if (query instanceof MultiTermQuery) {
((MultiTermQuery) query)
.setRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_REWRITE);
saveHitWordInList(query.rewrite(indexSearcher.getIndexReader()),
indexSearcher, docId, hitWords);
}
if (query instanceof BoostQuery)
saveHitWordInList(((BoostQuery) query).getQuery(), indexSearcher, docId,
hitWords);
}
【讨论】:
这是 Lucene.NET 4.8 的简化和非递归版本。
未经验证,但这也应该适用于 Lucene.NET 3.x
IEnumerable<Term> GetHitTermsForDoc(Query query, IndexSearcher searcher, int docId)
{
//Rewrite query into simpler internal form, required for ExtractTerms
var simplifiedQuery = query.Rewrite(searcher.IndexReader);
HashSet<Term> queryTerms = new HashSet<Term>();
simplifiedQuery.ExtractTerms(queryTerms);
List<Term> hitTerms = new List<Term>();
foreach (var term in queryTerms)
{
var termQuery = new TermQuery(term);
var explanation = searcher.Explain(termQuery, docId);
if (explanation.IsMatch)
{
hitTerms.Add(term);
}
}
return hitTerms;
}
【讨论】:
query.Rewrite 和query.ExtractTerms。这两种方法都存在于 Lucene.net 3.0.3
您可以为每个单独的术语使用cached filter,并根据BitSets 快速检查每个文档ID。
【讨论】: