All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.index.search.NumericRangeFieldDataFilter Maven / Gradle / Ivy

There is a newer version: 8.14.1
Show newest version
/*
 * Licensed to ElasticSearch and Shay Banon under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. ElasticSearch licenses this
 * file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.elasticsearch.index.search;

import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.lucene.docset.MatchDocIdSet;
import org.elasticsearch.index.fielddata.*;

import java.io.IOException;

/**
 * A numeric filter that can be much faster than {@link org.apache.lucene.search.NumericRangeFilter} at the
 * expense of loading numeric values of the field to memory using {@link org.elasticsearch.index.cache.field.data.FieldDataCache}.
 */
public abstract class NumericRangeFieldDataFilter extends Filter {
    final IndexNumericFieldData indexFieldData;
    final T lowerVal;
    final T upperVal;
    final boolean includeLower;
    final boolean includeUpper;

    public String getField() {
        return indexFieldData.getFieldNames().indexName();
    }

    public T getLowerVal() {
        return lowerVal;
    }

    public T getUpperVal() {
        return upperVal;
    }

    public boolean isIncludeLower() {
        return includeLower;
    }

    public boolean isIncludeUpper() {
        return includeUpper;
    }

    protected NumericRangeFieldDataFilter(IndexNumericFieldData indexFieldData, T lowerVal, T upperVal, boolean includeLower, boolean includeUpper) {
        this.indexFieldData = indexFieldData;
        this.lowerVal = lowerVal;
        this.upperVal = upperVal;
        this.includeLower = includeLower;
        this.includeUpper = includeUpper;
    }

    @Override
    public final String toString() {
        final StringBuilder sb = new StringBuilder(indexFieldData.getFieldNames().indexName()).append(":");
        return sb.append(includeLower ? '[' : '{')
                .append((lowerVal == null) ? "*" : lowerVal.toString())
                .append(" TO ")
                .append((upperVal == null) ? "*" : upperVal.toString())
                .append(includeUpper ? ']' : '}')
                .toString();
    }

    @Override
    public final boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof NumericRangeFieldDataFilter)) return false;
        NumericRangeFieldDataFilter other = (NumericRangeFieldDataFilter) o;

        if (!this.indexFieldData.getFieldNames().indexName().equals(other.indexFieldData.getFieldNames().indexName())
                || this.includeLower != other.includeLower
                || this.includeUpper != other.includeUpper
                ) {
            return false;
        }
        if (this.lowerVal != null ? !this.lowerVal.equals(other.lowerVal) : other.lowerVal != null) return false;
        if (this.upperVal != null ? !this.upperVal.equals(other.upperVal) : other.upperVal != null) return false;
        return true;
    }

    @Override
    public final int hashCode() {
        int h = indexFieldData.getFieldNames().indexName().hashCode();
        h ^= (lowerVal != null) ? lowerVal.hashCode() : 550356204;
        h = (h << 1) | (h >>> 31);  // rotate to distinguish lower from upper
        h ^= (upperVal != null) ? upperVal.hashCode() : -1674416163;
        h ^= (includeLower ? 1549299360 : -365038026) ^ (includeUpper ? 1721088258 : 1948649653);
        return h;
    }

    public static NumericRangeFieldDataFilter newByteRange(IndexNumericFieldData indexFieldData, Byte lowerVal, Byte upperVal, boolean includeLower, boolean includeUpper) {
        return new NumericRangeFieldDataFilter(indexFieldData, lowerVal, upperVal, includeLower, includeUpper) {
            @Override
            public DocIdSet getDocIdSet(AtomicReaderContext ctx, Bits acceptedDocs) throws IOException {
                final byte inclusiveLowerPoint, inclusiveUpperPoint;
                if (lowerVal != null) {
                    byte i = lowerVal.byteValue();
                    if (!includeLower && i == Byte.MAX_VALUE)
                        return null;
                    inclusiveLowerPoint = (byte) (includeLower ? i : (i + 1));
                } else {
                    inclusiveLowerPoint = Byte.MIN_VALUE;
                }
                if (upperVal != null) {
                    byte i = upperVal.byteValue();
                    if (!includeUpper && i == Byte.MIN_VALUE)
                        return null;
                    inclusiveUpperPoint = (byte) (includeUpper ? i : (i - 1));
                } else {
                    inclusiveUpperPoint = Byte.MAX_VALUE;
                }

                if (inclusiveLowerPoint > inclusiveUpperPoint)
                    return null;

                final LongValues values = indexFieldData.load(ctx).getLongValues();
                return new MatchDocIdSet(ctx.reader().maxDoc(), acceptedDocs) {

                    @Override
                    public boolean isCacheable() {
                        return true;
                    }

                    @Override
                    protected boolean matchDoc(int doc) {
                        LongValues.Iter iter = values.getIter(doc);
                        while (iter.hasNext()) {
                            long value = iter.next();
                            if (value >= inclusiveLowerPoint && value <= inclusiveUpperPoint) {
                                return true;
                            }
                        }
                        return false;
                    }
                };
            }
        };
    }


    public static NumericRangeFieldDataFilter newShortRange(IndexNumericFieldData indexFieldData, Short lowerVal, Short upperVal, boolean includeLower, boolean includeUpper) {
        return new NumericRangeFieldDataFilter(indexFieldData, lowerVal, upperVal, includeLower, includeUpper) {
            @Override
            public DocIdSet getDocIdSet(AtomicReaderContext ctx, Bits acceptedDocs) throws IOException {
                final short inclusiveLowerPoint, inclusiveUpperPoint;
                if (lowerVal != null) {
                    short i = lowerVal.shortValue();
                    if (!includeLower && i == Short.MAX_VALUE)
                        return null;
                    inclusiveLowerPoint = (short) (includeLower ? i : (i + 1));
                } else {
                    inclusiveLowerPoint = Short.MIN_VALUE;
                }
                if (upperVal != null) {
                    short i = upperVal.shortValue();
                    if (!includeUpper && i == Short.MIN_VALUE)
                        return null;
                    inclusiveUpperPoint = (short) (includeUpper ? i : (i - 1));
                } else {
                    inclusiveUpperPoint = Short.MAX_VALUE;
                }

                if (inclusiveLowerPoint > inclusiveUpperPoint)
                    return null;

                final LongValues values = indexFieldData.load(ctx).getLongValues();
                return new MatchDocIdSet(ctx.reader().maxDoc(), acceptedDocs) {

                    @Override
                    public boolean isCacheable() {
                        return true;
                    }

                    @Override
                    protected boolean matchDoc(int doc) {
                        LongValues.Iter iter = values.getIter(doc);
                        while (iter.hasNext()) {
                            long value = iter.next();
                            if (value >= inclusiveLowerPoint && value <= inclusiveUpperPoint) {
                                return true;
                            }
                        }
                        return false;
                    }
                };
            }
        };
    }

    public static NumericRangeFieldDataFilter newIntRange(IndexNumericFieldData indexFieldData, Integer lowerVal, Integer upperVal, boolean includeLower, boolean includeUpper) {
        return new NumericRangeFieldDataFilter(indexFieldData, lowerVal, upperVal, includeLower, includeUpper) {
            @Override
            public DocIdSet getDocIdSet(AtomicReaderContext ctx, Bits acceptedDocs) throws IOException {
                final int inclusiveLowerPoint, inclusiveUpperPoint;
                if (lowerVal != null) {
                    int i = lowerVal.intValue();
                    if (!includeLower && i == Integer.MAX_VALUE)
                        return null;
                    inclusiveLowerPoint = includeLower ? i : (i + 1);
                } else {
                    inclusiveLowerPoint = Integer.MIN_VALUE;
                }
                if (upperVal != null) {
                    int i = upperVal.intValue();
                    if (!includeUpper && i == Integer.MIN_VALUE)
                        return null;
                    inclusiveUpperPoint = includeUpper ? i : (i - 1);
                } else {
                    inclusiveUpperPoint = Integer.MAX_VALUE;
                }

                if (inclusiveLowerPoint > inclusiveUpperPoint)
                    return null;

                final LongValues values = indexFieldData.load(ctx).getLongValues();
                return new MatchDocIdSet(ctx.reader().maxDoc(), acceptedDocs) {

                    @Override
                    public boolean isCacheable() {
                        return true;
                    }

                    @Override
                    protected boolean matchDoc(int doc) {
                        LongValues.Iter iter = values.getIter(doc);
                        while (iter.hasNext()) {
                            long value = iter.next();
                            if (value >= inclusiveLowerPoint && value <= inclusiveUpperPoint) {
                                return true;
                            }
                        }
                        return false;
                    }
                };
            }
        };
    }

    public static NumericRangeFieldDataFilter newLongRange(IndexNumericFieldData indexFieldData, Long lowerVal, Long upperVal, boolean includeLower, boolean includeUpper) {
        return new NumericRangeFieldDataFilter(indexFieldData, lowerVal, upperVal, includeLower, includeUpper) {
            @Override
            public DocIdSet getDocIdSet(AtomicReaderContext ctx, Bits acceptedDocs) throws IOException {
                final long inclusiveLowerPoint, inclusiveUpperPoint;
                if (lowerVal != null) {
                    long i = lowerVal.longValue();
                    if (!includeLower && i == Long.MAX_VALUE)
                        return null;
                    inclusiveLowerPoint = includeLower ? i : (i + 1l);
                } else {
                    inclusiveLowerPoint = Long.MIN_VALUE;
                }
                if (upperVal != null) {
                    long i = upperVal.longValue();
                    if (!includeUpper && i == Long.MIN_VALUE)
                        return null;
                    inclusiveUpperPoint = includeUpper ? i : (i - 1l);
                } else {
                    inclusiveUpperPoint = Long.MAX_VALUE;
                }

                if (inclusiveLowerPoint > inclusiveUpperPoint)
                    return null;

                final LongValues values = indexFieldData.load(ctx).getLongValues();
                return new MatchDocIdSet(ctx.reader().maxDoc(), acceptedDocs) {

                    @Override
                    public boolean isCacheable() {
                        return true;
                    }

                    @Override
                    protected boolean matchDoc(int doc) {
                        LongValues.Iter iter = values.getIter(doc);
                        while (iter.hasNext()) {
                            long value = iter.next();
                            if (value >= inclusiveLowerPoint && value <= inclusiveUpperPoint) {
                                return true;
                            }
                        }
                        return false;
                    }
                };
            }
        };
    }

    public static NumericRangeFieldDataFilter newFloatRange(IndexNumericFieldData indexFieldData, Float lowerVal, Float upperVal, boolean includeLower, boolean includeUpper) {
        return new NumericRangeFieldDataFilter(indexFieldData, lowerVal, upperVal, includeLower, includeUpper) {
            @Override
            public DocIdSet getDocIdSet(AtomicReaderContext ctx, Bits acceptedDocs) throws IOException {
                // we transform the floating point numbers to sortable integers
                // using NumericUtils to easier find the next bigger/lower value
                final float inclusiveLowerPoint, inclusiveUpperPoint;
                if (lowerVal != null) {
                    float f = lowerVal.floatValue();
                    if (!includeUpper && f > 0.0f && Float.isInfinite(f))
                        return null;
                    int i = NumericUtils.floatToSortableInt(f);
                    inclusiveLowerPoint = NumericUtils.sortableIntToFloat(includeLower ? i : (i + 1));
                } else {
                    inclusiveLowerPoint = Float.NEGATIVE_INFINITY;
                }
                if (upperVal != null) {
                    float f = upperVal.floatValue();
                    if (!includeUpper && f < 0.0f && Float.isInfinite(f))
                        return null;
                    int i = NumericUtils.floatToSortableInt(f);
                    inclusiveUpperPoint = NumericUtils.sortableIntToFloat(includeUpper ? i : (i - 1));
                } else {
                    inclusiveUpperPoint = Float.POSITIVE_INFINITY;
                }

                if (inclusiveLowerPoint > inclusiveUpperPoint)
                    return null;

                final DoubleValues values = indexFieldData.load(ctx).getDoubleValues();
                return new MatchDocIdSet(ctx.reader().maxDoc(), acceptedDocs) {

                    @Override
                    public boolean isCacheable() {
                        return true;
                    }

                    @Override
                    protected boolean matchDoc(int doc) {
                        DoubleValues.Iter iter = values.getIter(doc);
                        while (iter.hasNext()) {
                            double value = iter.next();
                            if (value >= inclusiveLowerPoint && value <= inclusiveUpperPoint) {
                                return true;
                            }
                        }
                        return false;
                    }
                };
            }
        };
    }

    public static NumericRangeFieldDataFilter newDoubleRange(IndexNumericFieldData indexFieldData, Double lowerVal, Double upperVal, boolean includeLower, boolean includeUpper) {
        return new NumericRangeFieldDataFilter(indexFieldData, lowerVal, upperVal, includeLower, includeUpper) {
            @Override
            public DocIdSet getDocIdSet(AtomicReaderContext ctx, Bits acceptedDocs) throws IOException {
                // we transform the floating point numbers to sortable integers
                // using NumericUtils to easier find the next bigger/lower value
                final double inclusiveLowerPoint, inclusiveUpperPoint;
                if (lowerVal != null) {
                    double f = lowerVal.doubleValue();
                    if (!includeUpper && f > 0.0 && Double.isInfinite(f))
                        return null;
                    long i = NumericUtils.doubleToSortableLong(f);
                    inclusiveLowerPoint = NumericUtils.sortableLongToDouble(includeLower ? i : (i + 1L));
                } else {
                    inclusiveLowerPoint = Double.NEGATIVE_INFINITY;
                }
                if (upperVal != null) {
                    double f = upperVal.doubleValue();
                    if (!includeUpper && f < 0.0 && Double.isInfinite(f))
                        return null;
                    long i = NumericUtils.doubleToSortableLong(f);
                    inclusiveUpperPoint = NumericUtils.sortableLongToDouble(includeUpper ? i : (i - 1L));
                } else {
                    inclusiveUpperPoint = Double.POSITIVE_INFINITY;
                }

                if (inclusiveLowerPoint > inclusiveUpperPoint)
                    return null;

                final DoubleValues values = indexFieldData.load(ctx).getDoubleValues();
                return new MatchDocIdSet(ctx.reader().maxDoc(), acceptedDocs) {

                    @Override
                    public boolean isCacheable() {
                        return true;
                    }

                    @Override
                    protected boolean matchDoc(int doc) {
                        DoubleValues.Iter iter = values.getIter(doc);
                        while (iter.hasNext()) {
                            double value = iter.next();
                            if (value >= inclusiveLowerPoint && value <= inclusiveUpperPoint) {
                                return true;
                            }
                        }
                        return false;
                    }
                };
            }
        };
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy