aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/schema/Field.java
blob: d1886443257260fc36c45235a52e7f8899d5a6b4 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.schema;

import com.yahoo.api.annotations.Beta;
import com.yahoo.tensor.TensorType;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * A field in a schema.
 *
 * @author bratseth
 */
@Beta
public class Field implements FieldInfo {

    private final String name;
    private final Type type;
    private final boolean isAttribute;
    private final boolean isIndex;
    private final Set<String> aliases;

    public Field(Builder builder) {
        this.name = builder.name;
        this.type = builder.type;
        this.isAttribute = builder.isAttribute;
        this.isIndex = builder.isIndex;
        this.aliases = Set.copyOf(builder.aliases);
    }

    @Override
    public String name() { return name; }

    @Override
    public Type type() { return type; }

    public Set<String> aliases() { return aliases; }

    /** Returns whether this field is an attribute, i.e. does indexing: attribute. */
    @Override
    public boolean isAttribute() { return isAttribute; }

    /** Returns whether this field is an index, i.e. does indexing: index. */
    @Override
    public boolean isIndex() { return isIndex; }

    @Override
    public boolean equals(Object o) {
        if ( ! (o instanceof Field other)) return false;
        if ( ! this.name.equals(other.name)) return false;
        if ( this.isAttribute != other.isAttribute) return false;
        if ( this.isIndex != other.isIndex) return false;
        if ( ! this.aliases.equals(other.aliases)) return false;
        return true;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, type, isAttribute, isIndex, aliases);
    }

    @Override
    public String toString() { return "field '" + name + "'"; }

    public static class Type {

        private final Kind kind;

        /** The kind of type this is. */
        public enum Kind {
            ANNOTATIONREFERENCE, ARRAY, BOOL, BYTE, DOUBLE, FLOAT, INT, LONG, MAP, POSITION, PREDICATE, RAW, REFERENCE, STRING, STRUCT, TENSOR, URL, WEIGHTEDSET;
        }

        private Type(Kind kind) {
            this.kind = kind;
        }

        /**
         * Returns the kind of type this is.
         * Structured types have additional information in the subclass specific to that kind of type.
         */
        public Kind kind() { return kind; }

        /** Creates this from a type string on the syntax following "field [name] type " in a schema definition. */
        public static Type from(String typeString) {
            if (typeString.startsWith("annotationreference<"))
                return new Type(Kind.ANNOTATIONREFERENCE); // TODO: Model as subclass
            if (typeString.startsWith("array<"))
                return new Type(Kind.ARRAY); // TODO: Model as subclass
            if (typeString.equals("bool"))
                return new Type(Kind.BOOL);
            if (typeString.equals("byte"))
                return new Type(Kind.BYTE);
            if (typeString.equals("double"))
                return new Type(Kind.DOUBLE);
            if (typeString.equals("float"))
                return new Type(Kind.FLOAT);
            if (typeString.equals("int"))
                return new Type(Kind.INT);
            if (typeString.equals("long"))
                return new Type(Kind.LONG);
            if (typeString.startsWith("map<"))
                return new Type(Kind.MAP); // TODO: Model as subclass
            if (typeString.equals("position"))
                return new Type(Kind.POSITION);
            if (typeString.equals("predicate"))
                return new Type(Kind.PREDICATE);
            if (typeString.equals("raw"))
                return new Type(Kind.RAW);
            if (typeString.startsWith("reference<"))
                return new Type(Kind.REFERENCE); // TODO: Model as subclass
            if (typeString.equals("string"))
                return new Type(Kind.STRING);
            if (typeString.startsWith("tensor<") || typeString.startsWith("tensor("))
                return new TensorFieldType(TensorType.fromSpec(typeString));
            if (typeString.equals("url"))
                return new Type(Kind.URL);
            if (typeString.startsWith("weightedset<"))
                return new Type(Kind.WEIGHTEDSET); // TODO: Model as subclass
            else
                return new Type(Kind.STRUCT); // TODO: Model as a subclass
        }

    }

    public static class TensorFieldType extends Type {

        private final TensorType tensorType;

        public TensorFieldType(TensorType tensorType) {
            super(Kind.TENSOR);
            this.tensorType = tensorType;
        }

        public TensorType tensorType() { return tensorType; }

    }

    public static class Builder {

        private final String name;
        private final Type type;
        private final Set<String> aliases = new HashSet<>();
        private boolean isAttribute;
        private boolean isIndex;

        public Builder(String name, String typeString) {
            this.name = name;
            this.type = Type.from(typeString);
        }

        public Builder addAlias(String alias) {
            aliases.add(alias);
            return this;
        }

        public Builder setAttribute(boolean isAttribute) {
            this.isAttribute = isAttribute;
            return this;
        }

        public Builder setIndex(boolean isIndex) {
            this.isIndex = isIndex;
            return this;
        }

        public Field build() {
            return new Field(this);
        }

    }



}