Laszlo B
Laszlo B

Reputation: 455

Lucene: filtering by a set of allowed values on a numeric stored field

Is there a simple way to apply the following filter query:

userAccessibleDocTypesSet.contains(doc.type)

where the set is passed to the query (with scattered integers), and doc.type is a stored int field on the documents. A BooleanQuery with a should-clause for all values in the set seems overkill, and might push the limits.

What would be the right approach? How to apply this filter last, for the case when it doesn't filter anything due to full access rights for the user?

Upvotes: 1

Views: 542

Answers (1)

Laszlo B
Laszlo B

Reputation: 455

This is what I came up with. If you see any performance concerns, please let me know.

public class FilterByIntegerSetQuery extends Query
{
    protected String numericDocValueFieldName;
    protected Set<Integer> allowedValues;


    public FilterByIntegerSetQuery(String numericDocValueFieldName, Set<Integer> allowedValues)
    {
        this.numericDocValueFieldName = numericDocValueFieldName;
        this.allowedValues = allowedValues;
    }

    @Override
    public Weight createWeight(IndexSearcher searcher, boolean needsScores)
    {
        return new RandomAccessWeight(this)
        {
            @Override
            protected Bits getMatchingDocs(LeafReaderContext context) throws IOException
            {
                final int len = context.reader().maxDoc();
                final NumericDocValues values = context.reader().getNumericDocValues(numericDocValueFieldName);
                return new Bits()
                {
                    @Override
                    public boolean get(int index)
                    {
                        return allowedValues.contains((int) values.get(index));
                    }

                    @Override
                    public int length()
                    {
                        return len;
                    }
                };
            }
        };
    }


    @Override
    public String toString(String field)
    {
        return "(filter "+numericDocValueFieldName+" by set)";
    }
}

Upvotes: 1

Related Questions