aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/main/java/com/yahoo/searchlib/rankingexpression/evaluation/ArrayContext.java
blob: f9bf09caadae072bf8f8116b822e61c08323fc3d (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchlib.rankingexpression.evaluation;

import com.yahoo.searchlib.rankingexpression.RankingExpression;
import com.yahoo.searchlib.rankingexpression.Reference;
import com.yahoo.tensor.TensorType;

import java.util.Arrays;

/**
 * Creates a context which supports array index based lookup.
 * This instance may be reused indefinitely for evaluations of a single
 * ranking expression, in a single thread at the time.
 *
 * @author bratseth
 */
public class ArrayContext extends AbstractArrayContext implements Cloneable {

    /** The current values set */
    private Value[] values;

    /**
     * Create a fast lookup context for an expression.
     * This instance should be reused indefinitely by a single thread.
     * This will fail if unknown values are attempted added.
     */
    public ArrayContext(RankingExpression expression) {
        this(expression, false);
    }

    public ArrayContext(RankingExpression expression, boolean ignoreUnknownValues) {
        this(expression, ignoreUnknownValues, defaultMissingValue);
    }

    public ArrayContext(RankingExpression expression, Value defaultValue) {
        this(expression, false, defaultValue);
    }

    /**
     * Create a fast lookup context for an expression.
     * This instance should be reused indefinitely by a single thread.
     *
     * @param expression the expression to create a context for
     * @param ignoreUnknownValues whether attempts to put values not present in this expression
     *                            should fail (false - the default), or be ignored (true)
     * @param missingValue the value to return if not set.
     */
    public ArrayContext(RankingExpression expression, boolean ignoreUnknownValues, Value missingValue) {
        super(expression, ignoreUnknownValues, missingValue);
        values = new Value[doubleValues().length];
        Arrays.fill(values, this.missingValue);
    }

    /**
     * Puts a value by name.
     * The value will be frozen if it isn't already.
     *
     * @throws IllegalArgumentException if the name is not present in the ranking expression this was created with, and
     *         ignoredUnknownValues is false
     */
    @Override
    public final void put(String name, Value value) {
        Integer index = nameToIndex().get(name);
        if (index == null) {
            if (ignoreUnknownValues())
                return;
            else
                throw new IllegalArgumentException("Value '" + name + "' is not known to " + this);
        }
        put(index, value);
    }

    /** Same as put(index,DoubleValue.frozen(value)) */
    public final void put(int index, double value) {
        put(index, DoubleValue.frozen(value));
    }

    /**
     * Puts a value by index.
     * The value will be frozen if it isn't already.
     */
    public final void put(int index, Value value) {
        values[index] = value.freeze();
        clearMissing(index);
        try {
            doubleValues()[index] = value.asDouble();
        }
        catch (UnsupportedOperationException e) {
            doubleValues()[index] = Double.NaN; // see getDouble below
        }
    }

    @Override
    public TensorType getType(Reference reference) {
        Integer index = nameToIndex().get(reference.toString());
        if (index == null) return null;
        return values[index].type();
    }

    /** Perform a slow lookup by name */
    @Override
    public Value get(String name) {
        Integer index = nameToIndex().get(name);
        if (index == null) return missingValue;
        return values[index];
    }

    /** Perform a fast lookup by index */
    @Override
    public final Value get(int index) {
        return values[index];
    }

    /** Perform a fast lookup directly of the value as a double. This is faster than get(index).asDouble() */
    @Override
    public final double getDouble(int index) {
        double value = doubleValues()[index];
        if (Double.isNaN(value) && ! isMissing(index))  // NaN is valid as a missing value
            throw new UnsupportedOperationException("Value at " + index + " has no double representation");
        return value;
    }

    /**
     * Creates a clone of this context suitable for evaluating against the same ranking expression
     * in a different thread (i.e, name name to index map, different value set.
     */
    public ArrayContext clone() {
        ArrayContext clone = (ArrayContext)super.clone();
        clone.values = new Value[nameToIndex().size()];
        Arrays.fill(clone.values, missingValue);
        return clone;
    }

}