我正在使用 Lucene.Net 3.0.3 并且需要在特定字段中搜索(忽略查询中指定的任何字段)。我得到了一个已解析的 Lucene 查询,因此我无法使用我的必填字段生成已解析的查询。
Lucene 中是否有任何功能可以让我遍历查询的条款并更改字段?给定的查询将是一个复杂的查询,其中会有跨度、子句等。
或者也许有一些方法可以强制 Lucene 忽略解析查询中给出的字段并只使用指定的字段。
我正在使用 Lucene.Net 3.0.3 并且需要在特定字段中搜索(忽略查询中指定的任何字段)。我得到了一个已解析的 Lucene 查询,因此我无法使用我的必填字段生成已解析的查询。
Lucene 中是否有任何功能可以让我遍历查询的条款并更改字段?给定的查询将是一个复杂的查询,其中会有跨度、子句等。
或者也许有一些方法可以强制 Lucene 忽略解析查询中给出的字段并只使用指定的字段。
如果我理解正确,您需要一个类似的查询
+body:hello +(+body:test -header:xy)
解释为
+body:hello +(body:test -body:xy)
.
为此,您可以编写一个替换器方法,该方法遍历解析树并在到达包含字段名称的对象时替换字段(例如 Term、PhraseQuery、SpanNearQuery 或任何您拥有的)。
在 Java 中,您只能通过反射更改这些类中对象的字段名称。另一种选择是使用其他字段名称克隆已解析的树。
您可以编写一个“替换方法”,它接受一个查询对象并根据查询类型(即布尔查询、短语查询、术语查询……)处理它。
如果您选择克隆方式,您的方法将改为返回一个新对象。
编辑:
这是具有 4 种查询类型的 Java 示例代码(未考虑提升):
public static Query forceField(Query q, String field) {
if(q instanceof BooleanQuery) {
BooleanQuery newQ = new BooleanQuery();
for (BooleanClause clause : (BooleanQuery)q) {
newQ.add(forceField(clause.getQuery(), field), clause.getOccur());
}
return newQ;
}else if(q instanceof TermQuery) {
return new TermQuery(new Term(field, ((TermQuery)q).getTerm().text()));
}else if(q instanceof PhraseQuery) {
PhraseQuery phraseQuery = new PhraseQuery();
Term[] terms = ((PhraseQuery)q).getTerms();
for (int i = 0; i < terms.length; i++) {
phraseQuery.add(new Term(field, terms[i].text()), ((PhraseQuery)q).getPositions()[i]);
}
return phraseQuery;
}else if(q instanceof WildcardQuery) {
return new WildcardQuery(new Term(field, ((WildcardQuery)q).getTerm().text()));
} else {
throw new UnsupportedOperationException("Query type not known: " + q.getClass());
}
}
另一个不太干净的选项是使用整个查询的 toString 并替换其中的所有字段并再次解析它。
万一将来有人遇到这种情况,更简洁的解决方案将是创建一个新的查询解析器并使用该字段重新解析查询
public class FieldInjectQueryParser extends QueryParser {
private final String field;
public FieldInjectQueryParser(String field, Analyzer analyzer) {
super(field, analyzer);
this.field = field;
}
@Override
protected Query newTermQuery(Term term) {
return super.newTermQuery(createInjectTerm(term));
}
@Override
protected Query newPrefixQuery(Term prefix) {
return super.newPrefixQuery(createInjectTerm(prefix));
}
@Override
protected Query newRegexpQuery(Term regexp) {
return super.newRegexpQuery(createInjectTerm(regexp));
}
@Override
protected Query newFuzzyQuery(Term term, float minimumSimilarity, int prefixLength) {
return super.newFuzzyQuery(createInjectTerm(term), minimumSimilarity, prefixLength);
}
@Override
protected Query newWildcardQuery(Term t) {
return super.newWildcardQuery(createInjectTerm(t));
}
private Term createInjectTerm(Term term) {
return new Term(this.field, term.text());
}
}