aboutsummaryrefslogtreecommitdiffstats
path: root/predicate-search-core/src/main/java/com/yahoo/search/predicate/optimization/PredicateOptions.java
blob: c635215c1ec64f27d93617905d854e13cd953be0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.predicate.optimization;

import java.util.OptionalLong;

/**
 * This class contains the configured options for predicate indexes.
 * The adjusted bounds are extended to the nearest power of the arity (-1)
 * and are used to generate more efficient indexes.
 *
 * @author Magnar Nedland
 * @author bjorncs
 */
public class PredicateOptions {

    public static final long DEFAULT_LOWER_BOUND = 0x8000000000000000L;
    public static final long DEFAULT_UPPER_BOUND = 0x7fffffffffffffffL;

    private final int arity;
    private final long lowerBound;
    private final long upperBound;
    private OptionalLong adjustedLowerBound;
    private OptionalLong adjustedUpperBound;

    public PredicateOptions(int arity, Long lowerBound, Long upperBound) {
        this.arity = arity;
        this.lowerBound = lowerBound == null? DEFAULT_LOWER_BOUND : lowerBound;
        this.upperBound = upperBound == null? DEFAULT_UPPER_BOUND : upperBound;
        this.adjustedLowerBound = OptionalLong.empty();
        this.adjustedUpperBound = OptionalLong.empty();
    }

    public PredicateOptions(int arity) {
        this(arity, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND);
    }

    public int getArity() {
        return arity;
    }

    public long getLowerBound() {
        return lowerBound;
    }

    public long getUpperBound() {
        return upperBound;
    }

    public long getAdjustedLowerBound() {
        if (!adjustedLowerBound.isPresent()) {
            if (lowerBound == DEFAULT_LOWER_BOUND) {
                adjustedLowerBound = OptionalLong.of(lowerBound);
            } else if (lowerBound > 0) {
                adjustedLowerBound = OptionalLong.of(0L);
            } else {
                adjustedLowerBound = OptionalLong.of(-adjustBound(arity, -lowerBound));
            }
        }
        return adjustedLowerBound.getAsLong();
    }

    public long getAdjustedUpperBound() {
        if (!adjustedUpperBound.isPresent()) {
            if (upperBound == DEFAULT_UPPER_BOUND) {
                adjustedUpperBound = OptionalLong.of(DEFAULT_UPPER_BOUND);
            } else if (upperBound < 0) {
                adjustedUpperBound = OptionalLong.of(-1L);  // 0 belongs to the positive range.
            } else {
                adjustedUpperBound = OptionalLong.of(adjustBound(arity, upperBound));
            }
        }
        return adjustedUpperBound.getAsLong();
    }

    private static long adjustBound(int arity, long bound) {
        long adjusted = arity;
        long value = bound;
        long max = Long.MAX_VALUE / arity;
        while ((value/=arity) > 0) {
            if (adjusted > max) {
                return bound;
            }
            adjusted *= arity;
        }
        return adjusted - 1;
    }
}