diff --git a/core/src/main/java/feast/core/model/Entity.java b/core/src/main/java/feast/core/model/Entity.java index 4148b8a2a1..791e280d48 100644 --- a/core/src/main/java/feast/core/model/Entity.java +++ b/core/src/main/java/feast/core/model/Entity.java @@ -19,8 +19,7 @@ import feast.core.FeatureSetProto.EntitySpec; import feast.types.ValueProto.ValueType; import java.util.Objects; -import javax.persistence.EmbeddedId; -import javax.persistence.Table; +import javax.persistence.*; import lombok.Getter; import lombok.Setter; @@ -28,9 +27,17 @@ @Getter @Setter @javax.persistence.Entity -@Table(name = "entities") +@Table( + name = "entities", + uniqueConstraints = @UniqueConstraint(columnNames = {"name", "feature_set_id"})) public class Entity { - @EmbeddedId private EntityReference reference; + + @Id @GeneratedValue private Long id; + + private String name; + + @ManyToOne(fetch = FetchType.LAZY) + private FeatureSet featureSet; /** Data type of the entity. String representation of {@link ValueType} * */ private String type; @@ -38,16 +45,10 @@ public class Entity { public Entity() {} private Entity(String name, ValueType.Enum type) { - this.setReference(new EntityReference(name)); + this.setName(name); this.setType(type.toString()); } - public static Entity withRef(EntityReference entityRef) { - Entity entity = new Entity(); - entity.setReference(entityRef); - return entity; - } - public static Entity fromProto(EntitySpec entitySpec) { Entity entity = new Entity(entitySpec.getName(), entitySpec.getValueType()); return entity; @@ -61,12 +62,12 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - Entity feature = (Entity) o; - return getReference().equals(feature.getReference()) && getType().equals(feature.getType()); + Entity entity = (Entity) o; + return getName().equals(entity.getName()) && getType().equals(entity.getType()); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), getReference(), getType()); + return Objects.hash(super.hashCode(), getName(), getType()); } } diff --git a/core/src/main/java/feast/core/model/EntityReference.java b/core/src/main/java/feast/core/model/EntityReference.java deleted file mode 100644 index fb05c067c6..0000000000 --- a/core/src/main/java/feast/core/model/EntityReference.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright 2018-2020 The Feast Authors - * - * Licensed 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 - * - * https://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 feast.core.model; - -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Embeddable -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -public class EntityReference implements Serializable { - // Project the entity belongs to - @Column(nullable = false) - private String project; - - // Feature set the entity belongs to - @Column(name = "feature_set", nullable = false) - private String featureSet; - - // Version of the feature set this entity belongs to - @Column(nullable = false) - private int version; - - // Name of the entity - @Column(nullable = false) - private String name; - - EntityReference(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - EntityReference fieldId = (EntityReference) o; - return Objects.equals(name, fieldId.getName()) - && Objects.equals(project, fieldId.getProject()) - && Objects.equals(featureSet, fieldId.getFeatureSet()); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), project, featureSet, name); - } -} diff --git a/core/src/main/java/feast/core/model/Feature.java b/core/src/main/java/feast/core/model/Feature.java index 03e91d3dd1..38e2d4549e 100644 --- a/core/src/main/java/feast/core/model/Feature.java +++ b/core/src/main/java/feast/core/model/Feature.java @@ -34,10 +34,17 @@ @Getter @Setter @Entity -@Table(name = "features") +@Table( + name = "features", + uniqueConstraints = @UniqueConstraint(columnNames = {"name", "feature_set_id"})) public class Feature { - @EmbeddedId private FeatureReference reference; + @Id @GeneratedValue private Long id; + + private String name; + + @ManyToOne(fetch = FetchType.LAZY) + private FeatureSet featureSet; /** Data type of the feature. String representation of {@link ValueType} * */ private String type; @@ -74,16 +81,10 @@ public class Feature { public Feature() {} private Feature(String name, ValueType.Enum type) { - this.setReference(new FeatureReference(name)); + this.setName(name); this.setType(type.toString()); } - public static Feature withRef(FeatureReference featureRef) { - Feature feature = new Feature(); - feature.setReference(featureRef); - return feature; - } - public static Feature fromProto(FeatureSpec featureSpec) { Feature feature = new Feature(featureSpec.getName(), featureSpec.getValueType()); feature.labels = TypeConversion.convertMapToJsonString(featureSpec.getLabelsMap()); @@ -166,7 +167,7 @@ public boolean equals(Object o) { return false; } Feature feature = (Feature) o; - return Objects.equals(getReference(), feature.getReference()) + return Objects.equals(getName(), feature.getName()) && Objects.equals(labels, feature.labels) && Arrays.equals(getPresence(), feature.getPresence()) && Arrays.equals(getGroupPresence(), feature.getGroupPresence()) @@ -188,6 +189,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), getReference(), getType(), labels); + return Objects.hash(super.hashCode(), getName(), getType(), getLabels()); } } diff --git a/core/src/main/java/feast/core/model/FeatureReference.java b/core/src/main/java/feast/core/model/FeatureReference.java deleted file mode 100644 index bee7a17955..0000000000 --- a/core/src/main/java/feast/core/model/FeatureReference.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright 2018-2020 The Feast Authors - * - * Licensed 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 - * - * https://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 feast.core.model; - -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Embeddable -@NoArgsConstructor -@AllArgsConstructor -@Getter -@Setter -public class FeatureReference implements Serializable { - // Project the feature belongs to - @Column(nullable = false) - private String project; - - // Feature set the feature belongs to - @Column(name = "feature_set", nullable = false) - private String featureSet; - - // Version of the feature set this feature belongs to - @Column(nullable = false) - private int version; - - // Name of the feature - @Column(nullable = false) - private String name; - - FeatureReference(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - FeatureReference fieldId = (FeatureReference) o; - return Objects.equals(name, fieldId.getName()) - && Objects.equals(project, fieldId.getProject()) - && Objects.equals(featureSet, fieldId.getFeatureSet()); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), project, featureSet, name); - } -} diff --git a/core/src/main/java/feast/core/model/FeatureSet.java b/core/src/main/java/feast/core/model/FeatureSet.java index 8ffe334d35..faaee0e41f 100644 --- a/core/src/main/java/feast/core/model/FeatureSet.java +++ b/core/src/main/java/feast/core/model/FeatureSet.java @@ -39,9 +39,7 @@ public class FeatureSet extends AbstractTimestampEntity implements Comparable { // Id of the featureSet, defined as project/feature_set_name:feature_set_version - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private int id; + @Id @GeneratedValue private long id; // Name of the featureSet @Column(name = "name", nullable = false) @@ -61,39 +59,19 @@ public class FeatureSet extends AbstractTimestampEntity implements Comparable entities; // Feature fields inside this feature set - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @JoinTable( - name = "feature_set_features", - joinColumns = @JoinColumn(name = "feature_set_id"), - inverseJoinColumns = { - @JoinColumn(name = "features_name"), - @JoinColumn(name = "features_project"), - @JoinColumn(name = "features_feature_set_id"), - @JoinColumn(name = "features_version") - }, - indexes = { - @Index( - name = "idx_jobs_feature_set_features_feature_set_id", - columnList = "feature_set_id"), - }) + @OneToMany( + mappedBy = "featureSet", + cascade = CascadeType.ALL, + fetch = FetchType.EAGER, + orphanRemoval = true) private Set features; // Source on which feature rows can be found @@ -189,10 +167,7 @@ public void addEntities(List entities) { } public void addEntity(Entity entity) { - EntityReference entityReference = entity.getReference(); - entityReference.setProject(this.project.getName()); - entityReference.setFeatureSet(this.getName()); - entityReference.setVersion(this.getVersion()); + entity.setFeatureSet(this); entities.add(entity); } @@ -203,10 +178,7 @@ public void addFeatures(List features) { } public void addFeature(Feature feature) { - FeatureReference featureReference = feature.getReference(); - featureReference.setProject(this.project.getName()); - featureReference.setFeatureSet(this.getName()); - featureReference.setVersion(this.getVersion()); + feature.setFeatureSet(this); features.add(feature); } @@ -247,14 +219,14 @@ public FeatureSetProto.FeatureSet toProto() throws InvalidProtocolBufferExceptio private void setEntitySpecFields(EntitySpec.Builder entitySpecBuilder, Entity entityField) { entitySpecBuilder - .setName(entityField.getReference().getName()) + .setName(entityField.getName()) .setValueType(Enum.valueOf(entityField.getType())); } private void setFeatureSpecFields(FeatureSpec.Builder featureSpecBuilder, Feature featureField) throws InvalidProtocolBufferException { featureSpecBuilder - .setName(featureField.getReference().getName()) + .setName(featureField.getName()) .setValueType(Enum.valueOf(featureField.getType())); if (featureField.getPresence() != null) { @@ -331,11 +303,11 @@ public boolean equalTo(FeatureSet other) { Map featuresMap = new HashMap<>(); for (Entity e : entities) { - entitiesMap.putIfAbsent(e.getReference().getName(), e); + entitiesMap.putIfAbsent(e.getName(), e); } for (Feature f : features) { - featuresMap.putIfAbsent(f.getReference().getName(), f); + featuresMap.putIfAbsent(f.getName(), f); } // Ensure map size is consistent with existing fields @@ -348,19 +320,19 @@ public boolean equalTo(FeatureSet other) { // Ensure the other entities and features exist in the field map for (Entity e : other.getEntities()) { - if (!entitiesMap.containsKey(e.getReference().getName())) { + if (!entitiesMap.containsKey(e.getName())) { return false; } - if (!e.equals(entitiesMap.get(e.getReference().getName()))) { + if (!e.equals(entitiesMap.get(e.getName()))) { return false; } } for (Feature f : other.getFeatures()) { - if (!featuresMap.containsKey(f.getReference().getName())) { + if (!featuresMap.containsKey(f.getName())) { return false; } - if (!f.equals(featuresMap.get(f.getReference().getName()))) { + if (!f.equals(featuresMap.get(f.getName()))) { return false; } } diff --git a/core/src/main/java/feast/core/service/SpecService.java b/core/src/main/java/feast/core/service/SpecService.java index 8fec6ac511..4a068cba35 100644 --- a/core/src/main/java/feast/core/service/SpecService.java +++ b/core/src/main/java/feast/core/service/SpecService.java @@ -33,6 +33,7 @@ import feast.core.CoreServiceProto.UpdateStoreRequest; import feast.core.CoreServiceProto.UpdateStoreResponse; import feast.core.FeatureSetProto; +import feast.core.FeatureSetProto.FeatureSetStatus; import feast.core.SourceProto; import feast.core.StoreProto; import feast.core.StoreProto.Store.Subscription; @@ -335,6 +336,7 @@ public ApplyFeatureSetResponse applyFeatureSet(FeatureSetProto.FeatureSet newFea // Build a new FeatureSet object which includes the new properties FeatureSet featureSet = FeatureSet.fromProto(newFeatureSet); + featureSet.setStatus(FeatureSetStatus.STATUS_PENDING.toString()); if (newFeatureSet.getSpec().getSource() == SourceProto.Source.getDefaultInstance()) { featureSet.setSource(defaultSource); }