Skip to content

Commit 6764630

Browse files
author
Chen Zhiling
authored
Split Field model into distinct Feature and Entity objects (feast-dev#655)
* Split Field model into distinct Feature and Entity objects * Remove TFX fields for entities in testdata * Split Field model into distinct Feature and Entity objects * Index jointables * Explicitly name tables, remove redundant constructor * Integrate labels * Fix code comments * Change FeatureSetId to int * Retrieve featuresets from repository so that ids are consistent * Add uniqueness constraint to FeatureSets, fix tests * Remove feature and entity references
1 parent 3d9bafd commit 6764630

20 files changed

Lines changed: 390 additions & 711 deletions

core/src/main/java/feast/core/dao/MetricsRepository.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

core/src/main/java/feast/core/job/JobUpdateTask.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package feast.core.job;
1818

19+
import com.google.common.collect.Sets;
1920
import feast.core.log.Action;
2021
import feast.core.log.AuditLogger;
2122
import feast.core.log.Resource;
@@ -35,7 +36,6 @@
3536
import java.util.concurrent.Future;
3637
import java.util.concurrent.TimeUnit;
3738
import java.util.concurrent.TimeoutException;
38-
import java.util.stream.Collectors;
3939
import lombok.Getter;
4040
import lombok.extern.slf4j.Slf4j;
4141

@@ -102,10 +102,8 @@ public Job call() {
102102
}
103103

104104
boolean featureSetsChangedFor(Job job) {
105-
Set<String> existingFeatureSetsPopulatedByJob =
106-
job.getFeatureSets().stream().map(FeatureSet::getId).collect(Collectors.toSet());
107-
Set<String> newFeatureSetsPopulatedByJob =
108-
featureSets.stream().map(FeatureSet::getId).collect(Collectors.toSet());
105+
Set<FeatureSet> existingFeatureSetsPopulatedByJob = Sets.newHashSet(job.getFeatureSets());
106+
Set<FeatureSet> newFeatureSetsPopulatedByJob = Sets.newHashSet(featureSets);
109107

110108
return !newFeatureSetsPopulatedByJob.equals(existingFeatureSetsPopulatedByJob);
111109
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright 2018-2019 The Feast Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package feast.core.model;
18+
19+
import feast.core.FeatureSetProto.EntitySpec;
20+
import feast.types.ValueProto.ValueType;
21+
import java.util.Objects;
22+
import javax.persistence.*;
23+
import lombok.Getter;
24+
import lombok.Setter;
25+
26+
/** Feast entity object. Contains name and type of the entity. */
27+
@Getter
28+
@Setter
29+
@javax.persistence.Entity
30+
@Table(
31+
name = "entities",
32+
uniqueConstraints = @UniqueConstraint(columnNames = {"name", "feature_set_id"}))
33+
public class Entity {
34+
35+
@Id @GeneratedValue private Long id;
36+
37+
private String name;
38+
39+
@ManyToOne(fetch = FetchType.LAZY)
40+
private FeatureSet featureSet;
41+
42+
/** Data type of the entity. String representation of {@link ValueType} * */
43+
private String type;
44+
45+
public Entity() {}
46+
47+
private Entity(String name, ValueType.Enum type) {
48+
this.setName(name);
49+
this.setType(type.toString());
50+
}
51+
52+
public static Entity fromProto(EntitySpec entitySpec) {
53+
Entity entity = new Entity(entitySpec.getName(), entitySpec.getValueType());
54+
return entity;
55+
}
56+
57+
@Override
58+
public boolean equals(Object o) {
59+
if (this == o) {
60+
return true;
61+
}
62+
if (o == null || getClass() != o.getClass()) {
63+
return false;
64+
}
65+
Entity entity = (Entity) o;
66+
return getName().equals(entity.getName()) && getType().equals(entity.getType());
67+
}
68+
69+
@Override
70+
public int hashCode() {
71+
return Objects.hash(super.hashCode(), getName(), getType());
72+
}
73+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright 2018-2019 The Feast Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package feast.core.model;
18+
19+
import feast.core.FeatureSetProto.FeatureSpec;
20+
import feast.core.util.TypeConversion;
21+
import feast.types.ValueProto.ValueType;
22+
import java.util.Arrays;
23+
import java.util.Map;
24+
import java.util.Objects;
25+
import javax.persistence.*;
26+
import javax.persistence.Entity;
27+
import lombok.Getter;
28+
import lombok.Setter;
29+
30+
/**
31+
* Feature belonging to a featureset. Contains name, type as well as domain metadata about the
32+
* feature.
33+
*/
34+
@Getter
35+
@Setter
36+
@Entity
37+
@Table(
38+
name = "features",
39+
uniqueConstraints = @UniqueConstraint(columnNames = {"name", "feature_set_id"}))
40+
public class Feature {
41+
42+
@Id @GeneratedValue private Long id;
43+
44+
private String name;
45+
46+
@ManyToOne(fetch = FetchType.LAZY)
47+
private FeatureSet featureSet;
48+
49+
/** Data type of the feature. String representation of {@link ValueType} * */
50+
private String type;
51+
52+
// Labels for this feature
53+
@Column(name = "labels", columnDefinition = "text")
54+
private String labels;
55+
56+
// Presence constraints (refer to proto feast.core.FeatureSet.FeatureSpec)
57+
// Only one of them can be set.
58+
private byte[] presence;
59+
private byte[] groupPresence;
60+
61+
// Shape type (refer to proto feast.core.FeatureSet.FeatureSpec)
62+
// Only one of them can be set.
63+
private byte[] shape;
64+
private byte[] valueCount;
65+
66+
// Domain info for the values (refer to proto feast.core.FeatureSet.FeatureSpec)
67+
// Only one of them can be set.
68+
private String domain;
69+
private byte[] intDomain;
70+
private byte[] floatDomain;
71+
private byte[] stringDomain;
72+
private byte[] boolDomain;
73+
private byte[] structDomain;
74+
private byte[] naturalLanguageDomain;
75+
private byte[] imageDomain;
76+
private byte[] midDomain;
77+
private byte[] urlDomain;
78+
private byte[] timeDomain;
79+
private byte[] timeOfDayDomain;
80+
81+
public Feature() {}
82+
83+
private Feature(String name, ValueType.Enum type) {
84+
this.setName(name);
85+
this.setType(type.toString());
86+
}
87+
88+
public static Feature fromProto(FeatureSpec featureSpec) {
89+
Feature feature = new Feature(featureSpec.getName(), featureSpec.getValueType());
90+
feature.labels = TypeConversion.convertMapToJsonString(featureSpec.getLabelsMap());
91+
92+
switch (featureSpec.getPresenceConstraintsCase()) {
93+
case PRESENCE:
94+
feature.setPresence(featureSpec.getPresence().toByteArray());
95+
break;
96+
case GROUP_PRESENCE:
97+
feature.setGroupPresence(featureSpec.getGroupPresence().toByteArray());
98+
break;
99+
case PRESENCECONSTRAINTS_NOT_SET:
100+
break;
101+
}
102+
103+
switch (featureSpec.getShapeTypeCase()) {
104+
case SHAPE:
105+
feature.setShape(featureSpec.getShape().toByteArray());
106+
break;
107+
case VALUE_COUNT:
108+
feature.setValueCount(featureSpec.getValueCount().toByteArray());
109+
break;
110+
case SHAPETYPE_NOT_SET:
111+
break;
112+
}
113+
114+
switch (featureSpec.getDomainInfoCase()) {
115+
case DOMAIN:
116+
feature.setDomain(featureSpec.getDomain());
117+
break;
118+
case INT_DOMAIN:
119+
feature.setIntDomain(featureSpec.getIntDomain().toByteArray());
120+
break;
121+
case FLOAT_DOMAIN:
122+
feature.setFloatDomain(featureSpec.getFloatDomain().toByteArray());
123+
break;
124+
case STRING_DOMAIN:
125+
feature.setStringDomain(featureSpec.getStringDomain().toByteArray());
126+
break;
127+
case BOOL_DOMAIN:
128+
feature.setBoolDomain(featureSpec.getBoolDomain().toByteArray());
129+
break;
130+
case STRUCT_DOMAIN:
131+
feature.setStructDomain(featureSpec.getStructDomain().toByteArray());
132+
break;
133+
case NATURAL_LANGUAGE_DOMAIN:
134+
feature.setNaturalLanguageDomain(featureSpec.getNaturalLanguageDomain().toByteArray());
135+
break;
136+
case IMAGE_DOMAIN:
137+
feature.setImageDomain(featureSpec.getImageDomain().toByteArray());
138+
break;
139+
case MID_DOMAIN:
140+
feature.setMidDomain(featureSpec.getMidDomain().toByteArray());
141+
break;
142+
case URL_DOMAIN:
143+
feature.setUrlDomain(featureSpec.getUrlDomain().toByteArray());
144+
break;
145+
case TIME_DOMAIN:
146+
feature.setTimeDomain(featureSpec.getTimeDomain().toByteArray());
147+
break;
148+
case TIME_OF_DAY_DOMAIN:
149+
feature.setTimeOfDayDomain(featureSpec.getTimeOfDayDomain().toByteArray());
150+
break;
151+
case DOMAININFO_NOT_SET:
152+
break;
153+
}
154+
return feature;
155+
}
156+
157+
public Map<String, String> getLabels() {
158+
return TypeConversion.convertJsonStringToMap(this.labels);
159+
}
160+
161+
@Override
162+
public boolean equals(Object o) {
163+
if (this == o) {
164+
return true;
165+
}
166+
if (o == null || getClass() != o.getClass()) {
167+
return false;
168+
}
169+
Feature feature = (Feature) o;
170+
return Objects.equals(getName(), feature.getName())
171+
&& Objects.equals(labels, feature.labels)
172+
&& Arrays.equals(getPresence(), feature.getPresence())
173+
&& Arrays.equals(getGroupPresence(), feature.getGroupPresence())
174+
&& Arrays.equals(getShape(), feature.getShape())
175+
&& Arrays.equals(getValueCount(), feature.getValueCount())
176+
&& Objects.equals(getDomain(), feature.getDomain())
177+
&& Arrays.equals(getIntDomain(), feature.getIntDomain())
178+
&& Arrays.equals(getFloatDomain(), feature.getFloatDomain())
179+
&& Arrays.equals(getStringDomain(), feature.getStringDomain())
180+
&& Arrays.equals(getBoolDomain(), feature.getBoolDomain())
181+
&& Arrays.equals(getStructDomain(), feature.getStructDomain())
182+
&& Arrays.equals(getNaturalLanguageDomain(), feature.getNaturalLanguageDomain())
183+
&& Arrays.equals(getImageDomain(), feature.getImageDomain())
184+
&& Arrays.equals(getMidDomain(), feature.getMidDomain())
185+
&& Arrays.equals(getUrlDomain(), feature.getUrlDomain())
186+
&& Arrays.equals(getTimeDomain(), feature.getTimeDomain())
187+
&& Arrays.equals(getTimeDomain(), feature.getTimeOfDayDomain());
188+
}
189+
190+
@Override
191+
public int hashCode() {
192+
return Objects.hash(super.hashCode(), getName(), getType(), getLabels());
193+
}
194+
}

0 commit comments

Comments
 (0)