正如我在回复您对我的 SO 问题的评论时提到的那样,我对执行一些复杂的过滤也有相当小众的要求。最终,我必须创建一个自定义字段类,它允许我重写负责返回包含自定义逻辑的查询对象的方法以过滤结果。这种方法应该非常适合您:
public class MyCustomFieldType extends FieldType {
/**
* {@inheritDoc}
*/
@Override
protected void init(final IndexSchema schema, final Map<String, String> args) {
trueProperties |= TOKENIZED;
super.init(schema, args);
}
/**
* {@inheritDoc}
*/
@Override
public void write(final XMLWriter xmlWriter, final String name, final Fieldable fieldable)
throws IOException
{
xmlWriter.writeStr(name, fieldable.stringValue());
}
/**
* {@inheritDoc}
*/
@Override
public void write(final TextResponseWriter writer, final String name, final Fieldable fieldable)
throws IOException
{
writer.writeStr(name, fieldable.stringValue(), true);
}
/**
* {@inheritDoc}
*/
@Override
public SortField getSortField(final SchemaField field, final boolean reverse) {
return getStringSort(field, reverse);
}
/**
* {@inheritDoc}
*/
@Override
public void setAnalyzer(final Analyzer analyzer) {
this.analyzer = analyzer;
}
/**
* {@inheritDoc}
*/
@Override
public void setQueryAnalyzer(final Analyzer queryAnalyzer) {
this.queryAnalyzer = queryAnalyzer;
}
/**
* {@inheritDoc}
*/
@Override
public Query getFieldQuery(
final QParser parser, final SchemaField field, final String externalVal)
{
// Do some parsing of the user's input (if necessary) from the query string (externalVal)
final String parsedInput = ...
// Instantiate your custom filter, taking note to wrap it in a caching wrapper!
final Filter filter = new CachingWrapperFilter(
new MyCustomFilter(field, parsedValue));
// Return a query that runs your filter against all docs in the index
// NOTE: depending on your needs, you may be able to do a more fine grained query here
// instead of a MatchAllDocsQuery!!
return new FilteredQuery(new MatchAllDocsQuery(), filter);
}
}
现在您需要一个自定义过滤器...
public class MyCustomFilter extends Filter {
/**
* The field that is being filtered.
*/
private final SchemaField field;
/**
* The value to filter against.
*/
private final String filterBy;
/**
*
*
* @param field The field to perform filtering against.
* @param filterBy A value to filter by.
*/
public ProgrammeAvailabilityFilter(
final SchemaField field,
final String filterBy)
{
this.field = field;
this.filterBy = filterBy;
}
/**
* {@inheritDoc}
*/
@Override
public DocIdSet getDocIdSet(final IndexReader reader) throws IOException {
final FixedBitSet bitSet = new FixedBitSet(reader.maxDoc());
// find all the docs you want to run the filter against
final Weight weight = new IndexSearcher(reader).createNormalizedWeight(
new SOME_QUERY_TYPE_HERE());
final Scorer docIterator = weight.scorer(reader, true, false);
if (docIterator == null) {
return bitSet;
}
int docId;
while ((docId = docIterator.nextDoc()) != Scorer.NO_MORE_DOCS) {
final Document doc = reader.document(docId);
for (final String indexFieldValue : doc.getValues(field.getName())) {
// CUSTOM LOGIC GOES HERE
// If your criteria are met, consider the doc a match
bitSet.set(docId);
}
}
return bitSet;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(final Object other) {
// NEEDED FOR CACHING
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
// NEEDED FOR CACHING
}
}
上面的示例显然是非常基础的,但是如果您将其用作模板并进行调整以提高性能并添加您的自定义逻辑,您应该会得到您所需要的。还要确保在您的过滤器中实现hashCode
和equals
方法,因为它们将用于缓存。在查询字符串中,您可以fq
像这样提供参数:`?q=some query&fq=myfield:[0,0,0,0 to 3,8,8,8]。
正如我所提到的,这种方法对我和我的团队非常有效,因为我们对内容过滤有非常具体的要求。
祝你好运。:)