From c6acae3119b252c90d653a8637e0bf0dc6eea935 Mon Sep 17 00:00:00 2001 From: Helen Yang Date: Mon, 12 Sep 2022 17:26:07 -0700 Subject: [PATCH 1/6] Add Data Models in Feathr This RB is to create data models based on proposal: https://microsoft-my.sharepoint.com/:w:/g/personal/djkim_linkedin_biz/EZspGt7jJlRAqHTICZg3UbcBgQQ_VncOgM48hKW--T8qkg?e=T4N3zw --- registry/data-models/__init__.py | 0 registry/data-models/models.py | 102 +++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 registry/data-models/__init__.py create mode 100644 registry/data-models/models.py diff --git a/registry/data-models/__init__.py b/registry/data-models/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/registry/data-models/models.py b/registry/data-models/models.py new file mode 100644 index 000000000..e9599cbc3 --- /dev/null +++ b/registry/data-models/models.py @@ -0,0 +1,102 @@ +from pydantic import BaseModel +from typing import List, Optional + + +class FeatureValue(BaseModel): + """ + A value of a Feature. + NOTE: FeatureValue is to be customized in each registry + """ + pass + + +class FeatureValueType(BaseModel): + """ + A value of a Feature. + NOTE: FeatureValue is to be customized in each registry + """ + pass + + +class Source(BaseModel): + """ + Type of FeatureValue. + It defines where the feature is extracted from. It can be online, offline, Restli, or other FeatureInterfaces. + """ + pass + + +class DataSource(Source): + pass + + +class FeatureSource(Source): + pass + + +class Transformation(BaseModel): + """ + The transformation of a Feature. + A transformation function represents the transformation logic to produce feature value from the source of FeatureAnchor + NOTE: Transformation is to be customized in each registry + """ + pass + + +class Project(BaseModel): + """ + Group of FeatureInterfaces. It can be a project the team is working on, + or a namespace which related FeatureInterfaces have. + """ + id: str + name: str + + +class FeatureInterface(BaseModel): + """ + Named Feature Interface of FeatureImplementations. + Each FeatureInterface is defined by feature producer and interact + by feature consumers.Each FeatureInterface enclosed attributes that don't change across + implementations. (eg. name, default value, value type, format, status, ownership). + One FeatureInterface can have multiple Features for different environments. + """ + default_value: Optional[FeatureValue] # Optional default value + id: str + value_type: FeatureValueType # Feature value type + + +class Anchor(BaseModel): + """ + Group of AnchorFeatures which anchored on same DataSource. + This is mainly used by feature producer gather information about DataSource + and FeatureImplementations associated with the DataSource. + """ + id: str + source: DataSource + + +class Feature(BaseModel): + """ + Actual implementation of FeatureInterface. + An implementation defines where a feature is extracted from (Source) and how it is computed (Transformation). + The Source of a feature can be raw data sources (like Rest.li, HDFS) and/or other features. + """ + feature_interface_id: str # ID of the feature interface that the feature anchor belongs to + id: str + name: str + source: Source # Source can be either data source or feature source + transformation: Transformation # transformation logic to produce feature value + + +class AnchorFeature(Feature): + """ + Feature implementation of FeatureInterface which anchored to a data source. + """ + pass + + +class DerivedFeature(Feature): + """ + Feature implementation that is derived from other FeatureInterfaces. + """ + input_feature_interface_ids: List[str] # List of input feature interface IDs From 45a05acb2a9bf79bf82f9876573910e27cf09749 Mon Sep 17 00:00:00 2001 From: Helen Yang Date: Wed, 14 Sep 2022 17:21:14 -0700 Subject: [PATCH 2/6] Update models.py --- registry/data-models/models.py | 100 +++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/registry/data-models/models.py b/registry/data-models/models.py index e9599cbc3..0b103d434 100644 --- a/registry/data-models/models.py +++ b/registry/data-models/models.py @@ -1,6 +1,40 @@ from pydantic import BaseModel from typing import List, Optional +""" +This file defines abstract backend data models for feature registry. +Backend data models will be used by backend API server to talk to feature registry backend. +Purpose of this is to decouple backend data models from API specific data models. +For each feature registry provider/implementation, they will extend this abstract +data models and backend API. +Diagram of the data models: + +-----------------+ + | Project | + +-----------------+ + | + | + | + +------------------------------+ + | | + | 1:n | 1:n + +------------------+ +------------------+ + | FeatureInterface | | Anchor | + +------------------+ +------------------+ + | | | + | 1:n |1:n | + +------------------------------+ | + | | + |1:n | contains + +---------------+ +---------------+ + | Feature | --------- | Source | + +---------------+ contains +---------------+ + | + | + +----------------+ + | Transformation | + +----------------+ +""" + class FeatureValue(BaseModel): """ @@ -31,6 +65,7 @@ class DataSource(Source): class FeatureSource(Source): + input_feature_interface_ids: List[str] # List of input feature interface IDs pass @@ -43,13 +78,31 @@ class Transformation(BaseModel): pass -class Project(BaseModel): +class Feature(BaseModel): """ - Group of FeatureInterfaces. It can be a project the team is working on, - or a namespace which related FeatureInterfaces have. + Actual implementation of FeatureInterface. + An implementation defines where a feature is extracted from (Source) and how it is computed (Transformation). + The Source of a feature can be raw data sources (like Rest.li, HDFS) and/or other features. """ + feature_interface_id: str # ID of the feature interface that the feature belongs to id: str name: str + source: Source # Source can be either data source or feature source + transformation: Transformation # transformation logic to produce feature value + + +class AnchorFeature(Feature): + """ + Feature implementation of FeatureInterface which anchored to a data source. + """ + source: DataSource + + +class DerivedFeature(Feature): + """ + Feature implementation that is derived from other FeatureInterfaces. + """ + source: FeatureSource class FeatureInterface(BaseModel): @@ -63,40 +116,27 @@ class FeatureInterface(BaseModel): default_value: Optional[FeatureValue] # Optional default value id: str value_type: FeatureValueType # Feature value type + project_id: str + features: List[Feature] # List of features that the FeatureInterface has -class Anchor(BaseModel): - """ - Group of AnchorFeatures which anchored on same DataSource. - This is mainly used by feature producer gather information about DataSource - and FeatureImplementations associated with the DataSource. - """ - id: str - source: DataSource - - -class Feature(BaseModel): +class Project(BaseModel): """ - Actual implementation of FeatureInterface. - An implementation defines where a feature is extracted from (Source) and how it is computed (Transformation). - The Source of a feature can be raw data sources (like Rest.li, HDFS) and/or other features. + Group of FeatureInterfaces. It can be a project the team is working on, + or a namespace which related FeatureInterfaces have. """ - feature_interface_id: str # ID of the feature interface that the feature anchor belongs to id: str name: str - source: Source # Source can be either data source or feature source - transformation: Transformation # transformation logic to produce feature value + feature_interfaces: List[FeatureInterface] # List of feature interfaces that the project has -class AnchorFeature(Feature): - """ - Feature implementation of FeatureInterface which anchored to a data source. - """ - pass - - -class DerivedFeature(Feature): +class Anchor(BaseModel): """ - Feature implementation that is derived from other FeatureInterfaces. + Group of AnchorFeatures which anchored on same DataSource. + This is mainly used by feature producer gather information about DataSource + and FeatureImplementations associated with the DataSource. """ - input_feature_interface_ids: List[str] # List of input feature interface IDs + id: str + project_id: str # ID of Project that the anchor belongs to + source: DataSource # data source of the Anchor + anchor_features: List[AnchorFeature] # List of anchor features that the anchor has From 06966486ba8685f2a731802e0164b125b2235b8b Mon Sep 17 00:00:00 2001 From: Helen Yang Date: Mon, 19 Sep 2022 19:32:26 -0700 Subject: [PATCH 3/6] Update models.py --- registry/data-models/models.py | 142 +++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 58 deletions(-) diff --git a/registry/data-models/models.py b/registry/data-models/models.py index 0b103d434..6cbeb55c8 100644 --- a/registry/data-models/models.py +++ b/registry/data-models/models.py @@ -1,5 +1,5 @@ from pydantic import BaseModel -from typing import List, Optional +from typing import List """ This file defines abstract backend data models for feature registry. @@ -8,46 +8,76 @@ For each feature registry provider/implementation, they will extend this abstract data models and backend API. Diagram of the data models: - +-----------------+ - | Project | - +-----------------+ - | - | - | - +------------------------------+ - | | - | 1:n | 1:n - +------------------+ +------------------+ - | FeatureInterface | | Anchor | - +------------------+ +------------------+ - | | | - | 1:n |1:n | - +------------------------------+ | - | | - |1:n | contains - +---------------+ +---------------+ - | Feature | --------- | Source | - +---------------+ contains +---------------+ - | - | - +----------------+ - | Transformation | - +----------------+ + +-----------------+ + | Project | + +-----------------+ + | + | + | + +------------------------------+ + | | + | 1:n | 1:n + +------------------+ +------------------+ + +---------- | FeatureName | | Anchor | + | 1:n +------------------+ +------------------+ + | | | | + | | 1:n |1:n | + | +------------------------------+ | + | | | + | |1:n \|/ has + | +--------------+ +---------------+ +----------------+ + | |Transformation|----| Feature | --------------- | DataSource | + | +--------------+ has+---------------+ +----------------+ + | /|\ | /|\ |extends + | | | | | + | | +----------------------|---------+ | + | | | | | + | +--------------------------------------+ | has| \|/ + | | | | +----------+ + | |extends |extends |has | Source | + | +----------------+ +-----------------+ +----------+ + | | DerivedFeature | | AnchorFeature | /|\ + | +----------------+ +-----------------+ | + | | | + | | |extends + | | +------------------+ + | +-------------------------------------------------------| FeatureSource | + | has +------------------+ + | | + +-----------------------------------------------------------------------------| + + + + + + """ -class FeatureValue(BaseModel): +class FeatureId(BaseModel): """ - A value of a Feature. - NOTE: FeatureValue is to be customized in each registry + Id for Feature, it's unique ID represents Feature. """ pass -class FeatureValueType(BaseModel): +class FeatureNameId(BaseModel): """ - A value of a Feature. - NOTE: FeatureValue is to be customized in each registry + Id for FeatureName, it's unique ID represents FeatureName. + """ + pass + + +class AnchorId(BaseModel): + """ + Id for Anchor, it's unique ID represents Anchor. + """ + pass + + +class ProjectId(BaseModel): + """ + Id for Project, it's unique ID represents Project. """ pass @@ -55,7 +85,7 @@ class FeatureValueType(BaseModel): class Source(BaseModel): """ Type of FeatureValue. - It defines where the feature is extracted from. It can be online, offline, Restli, or other FeatureInterfaces. + It defines where the feature is extracted from. """ pass @@ -65,7 +95,7 @@ class DataSource(Source): class FeatureSource(Source): - input_feature_interface_ids: List[str] # List of input feature interface IDs + input_feature_name_ids: List[FeatureNameId] # List of input feature name Keys pass @@ -73,51 +103,47 @@ class Transformation(BaseModel): """ The transformation of a Feature. A transformation function represents the transformation logic to produce feature value from the source of FeatureAnchor - NOTE: Transformation is to be customized in each registry """ pass class Feature(BaseModel): """ - Actual implementation of FeatureInterface. + Actual implementation of FeatureName. An implementation defines where a feature is extracted from (Source) and how it is computed (Transformation). - The Source of a feature can be raw data sources (like Rest.li, HDFS) and/or other features. + The Source of a feature can be raw data sources and/or other features. """ - feature_interface_id: str # ID of the feature interface that the feature belongs to - id: str - name: str + id: FeatureId # Unique ID for Feature + feature_name_id: FeatureNameId # Id of the feature name that the feature belongs to source: Source # Source can be either data source or feature source transformation: Transformation # transformation logic to produce feature value class AnchorFeature(Feature): """ - Feature implementation of FeatureInterface which anchored to a data source. + Feature implementation of FeatureName which anchored to a data source. """ source: DataSource class DerivedFeature(Feature): """ - Feature implementation that is derived from other FeatureInterfaces. + Feature implementation that is derived from other FeatureNames. """ source: FeatureSource -class FeatureInterface(BaseModel): +class FeatureName(BaseModel): """ Named Feature Interface of FeatureImplementations. - Each FeatureInterface is defined by feature producer and interact - by feature consumers.Each FeatureInterface enclosed attributes that don't change across - implementations. (eg. name, default value, value type, format, status, ownership). - One FeatureInterface can have multiple Features for different environments. + Each FeatureName is defined by feature producer and interact + by feature consumers.Each FeatureName enclosed attributes that don't change across + implementations. + One FeatureName can have multiple Features for different environments. """ - default_value: Optional[FeatureValue] # Optional default value - id: str - value_type: FeatureValueType # Feature value type - project_id: str - features: List[Feature] # List of features that the FeatureInterface has + id: FeatureNameId # unique ID for FeatureName, used to extract data for current FeatureName + project_id: ProjectId # ID of the project the FeatureName belongs to + features: List[FeatureId] # List of ids of feature that the FeatureName has class Project(BaseModel): @@ -125,9 +151,9 @@ class Project(BaseModel): Group of FeatureInterfaces. It can be a project the team is working on, or a namespace which related FeatureInterfaces have. """ - id: str - name: str - feature_interfaces: List[FeatureInterface] # List of feature interfaces that the project has + id: ProjectId # Unique ID of the project. + feature_names: List[FeatureNameId] # List of feature name ids that the project has + anchor_ids: List[AnchorId] # List of Anchor ids that the project has class Anchor(BaseModel): @@ -136,7 +162,7 @@ class Anchor(BaseModel): This is mainly used by feature producer gather information about DataSource and FeatureImplementations associated with the DataSource. """ - id: str - project_id: str # ID of Project that the anchor belongs to + id: AnchorId # Unique ID for Anchor + project_id: ProjectId # ID of Project that the anchor belongs to source: DataSource # data source of the Anchor - anchor_features: List[AnchorFeature] # List of anchor features that the anchor has + anchor_features: List[FeatureId] # List of anchor features that the anchor has From 5cc163d3480f6b7f40631103d6d589759663b34b Mon Sep 17 00:00:00 2001 From: Helen Yang Date: Tue, 20 Sep 2022 18:48:00 -0700 Subject: [PATCH 4/6] Update models.py --- registry/data-models/models.py | 63 ++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/registry/data-models/models.py b/registry/data-models/models.py index 6cbeb55c8..c59fbccc5 100644 --- a/registry/data-models/models.py +++ b/registry/data-models/models.py @@ -26,13 +26,13 @@ | | | | |1:n \|/ has | +--------------+ +---------------+ +----------------+ - | |Transformation|----| Feature | --------------- | DataSource | + | |Transformation|----| Feature | | DataSource | | +--------------+ has+---------------+ +----------------+ - | /|\ | /|\ |extends - | | | | | - | | +----------------------|---------+ | - | | | | | - | +--------------------------------------+ | has| \|/ + | /|\ /|\ |extends + | | | | + | | | | + | | | | + | +--------------------------------------+ | \|/ | | | | +----------+ | |extends |extends |has | Source | | +----------------+ +-----------------+ +----------+ @@ -41,16 +41,10 @@ | | | | | |extends | | +------------------+ - | +-------------------------------------------------------| FeatureSource | + | +-------------------------------------------------------| FeaturesSource | | has +------------------+ | | - +-----------------------------------------------------------------------------| - - - - - - + +-----------------------------------------------------------------------------| """ @@ -58,43 +52,51 @@ class FeatureId(BaseModel): """ Id for Feature, it's unique ID represents Feature. """ - pass + id: str # id of a feature class FeatureNameId(BaseModel): """ Id for FeatureName, it's unique ID represents FeatureName. """ - pass + id: str # id of a FeatureName class AnchorId(BaseModel): """ Id for Anchor, it's unique ID represents Anchor. """ - pass + id: str # id of a anchor class ProjectId(BaseModel): """ Id for Project, it's unique ID represents Project. """ - pass + id: str # id of a project class Source(BaseModel): """ - Type of FeatureValue. - It defines where the feature is extracted from. + Source of the feature. + It defines where the feature is extracted or derived from. """ pass class DataSource(Source): + """ + Data source of the feature. + It defines the raw data source the feature is extracted from. + """ pass -class FeatureSource(Source): +class FeaturesSource(Source): + """ + Feature source of the feature. + It defines one of multiple features where the feature is derived from. + """ input_feature_name_ids: List[FeatureNameId] # List of input feature name Keys pass @@ -123,23 +125,24 @@ class AnchorFeature(Feature): """ Feature implementation of FeatureName which anchored to a data source. """ - source: DataSource + source: DataSource # Raw data source where the feature is extracted from class DerivedFeature(Feature): """ Feature implementation that is derived from other FeatureNames. """ - source: FeatureSource + source: FeaturesSource # Source features where the feature is derived from class FeatureName(BaseModel): """ - Named Feature Interface of FeatureImplementations. - Each FeatureName is defined by feature producer and interact - by feature consumers.Each FeatureName enclosed attributes that don't change across - implementations. - One FeatureName can have multiple Features for different environments. + Named Feature Interface that can be backed by multiple Feature implementations across + different environments accessing different sources (data lake access for batch training, + KV store access for online serving). Each FeatureName is defined by feature producer. + Feature consumers reference a feature by that name to access that feature data, + agnostic of runtime environment. Each FeatureName also encloses attributes that does not + change across implementations. """ id: FeatureNameId # unique ID for FeatureName, used to extract data for current FeatureName project_id: ProjectId # ID of the project the FeatureName belongs to @@ -148,8 +151,8 @@ class FeatureName(BaseModel): class Project(BaseModel): """ - Group of FeatureInterfaces. It can be a project the team is working on, - or a namespace which related FeatureInterfaces have. + Group of FeatureNames. It can be a project the team is working on, + or a namespace which related FeatureNames have. """ id: ProjectId # Unique ID of the project. feature_names: List[FeatureNameId] # List of feature name ids that the project has From 53dfb5e796034bd72b8290f39611a3335b67e716 Mon Sep 17 00:00:00 2001 From: Helen Yang Date: Wed, 21 Sep 2022 10:16:27 -0700 Subject: [PATCH 5/6] Update models.py --- registry/data-models/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/registry/data-models/models.py b/registry/data-models/models.py index c59fbccc5..92f7f9004 100644 --- a/registry/data-models/models.py +++ b/registry/data-models/models.py @@ -146,7 +146,7 @@ class FeatureName(BaseModel): """ id: FeatureNameId # unique ID for FeatureName, used to extract data for current FeatureName project_id: ProjectId # ID of the project the FeatureName belongs to - features: List[FeatureId] # List of ids of feature that the FeatureName has + feature_ids: List[FeatureId] # List of ids of feature that the FeatureName has class Project(BaseModel): @@ -155,7 +155,7 @@ class Project(BaseModel): or a namespace which related FeatureNames have. """ id: ProjectId # Unique ID of the project. - feature_names: List[FeatureNameId] # List of feature name ids that the project has + feature_name_ids: List[FeatureNameId] # List of feature name ids that the project has anchor_ids: List[AnchorId] # List of Anchor ids that the project has @@ -168,4 +168,4 @@ class Anchor(BaseModel): id: AnchorId # Unique ID for Anchor project_id: ProjectId # ID of Project that the anchor belongs to source: DataSource # data source of the Anchor - anchor_features: List[FeatureId] # List of anchor features that the anchor has + anchor_feature_ids: List[FeatureId] # List of anchor features that the anchor has From 9d9af5f9621174955a49a268011c6b1c31d39367 Mon Sep 17 00:00:00 2001 From: Helen Yang Date: Wed, 21 Sep 2022 10:16:27 -0700 Subject: [PATCH 6/6] Update models.py --- registry/data-models/data-model-diagram.md | 59 ++++++++++++++++++++++ registry/data-models/models.py | 52 +++---------------- 2 files changed, 66 insertions(+), 45 deletions(-) create mode 100644 registry/data-models/data-model-diagram.md diff --git a/registry/data-models/data-model-diagram.md b/registry/data-models/data-model-diagram.md new file mode 100644 index 000000000..31e3fbff7 --- /dev/null +++ b/registry/data-models/data-model-diagram.md @@ -0,0 +1,59 @@ + +# Feathr Abstract backend Data Model Diagram + +This file defines abstract backend data models diagram for feature registry. +[Python Code](./models.py) + +```mermaid +classDiagram + Project "1" --> "n" FeatureName : contains + Project "1" --> "n" Anchor : contains + FeatureName "1" --> "n" Feature : contains + Anchor "1" --> "n" Feature : contains + Feature <|-- AnchorFeature : extends + Feature <|-- DerivedFeature: extends + Feature --> Transformation + Feature --> Transformation : contains + Source <|-- DataSource: extends + Source <|-- FeatureSource: extends + AnchorFeature --> DataSource : contains + DerivedFeature "1" --> "1..n" FeatureSource: contains + + class Source{ + } + + class DataSource{ + } + + class FeatureSource{ + +feature_name_id FeatureNameId + } + class Feature{ + +FeatureId id + +FeatureNameId feature_namme_id + +Source source + +Transformation transformation + } + class AnchorFeature{ + +DataSource source + } + class DerivedFeature{ + +List[FeatureSource] source + } + class FeatureName{ + +FeatureNameId id + +ProjectId project_id + +List[FeatureId] feature_ids + } + class Project{ + +ProjectId id + +List[FeatureNameId] feature_name_ids + +List[AnchorId] anchor_ids + } + class Anchor{ + +AnchorId id + +ProjectId project_id + +DataSource source + +List[FeatureId] anchor_feature_ids + } +``` \ No newline at end of file diff --git a/registry/data-models/models.py b/registry/data-models/models.py index c59fbccc5..c50b6a1c0 100644 --- a/registry/data-models/models.py +++ b/registry/data-models/models.py @@ -7,44 +7,7 @@ Purpose of this is to decouple backend data models from API specific data models. For each feature registry provider/implementation, they will extend this abstract data models and backend API. -Diagram of the data models: - +-----------------+ - | Project | - +-----------------+ - | - | - | - +------------------------------+ - | | - | 1:n | 1:n - +------------------+ +------------------+ - +---------- | FeatureName | | Anchor | - | 1:n +------------------+ +------------------+ - | | | | - | | 1:n |1:n | - | +------------------------------+ | - | | | - | |1:n \|/ has - | +--------------+ +---------------+ +----------------+ - | |Transformation|----| Feature | | DataSource | - | +--------------+ has+---------------+ +----------------+ - | /|\ /|\ |extends - | | | | - | | | | - | | | | - | +--------------------------------------+ | \|/ - | | | | +----------+ - | |extends |extends |has | Source | - | +----------------+ +-----------------+ +----------+ - | | DerivedFeature | | AnchorFeature | /|\ - | +----------------+ +-----------------+ | - | | | - | | |extends - | | +------------------+ - | +-------------------------------------------------------| FeaturesSource | - | has +------------------+ - | | - +-----------------------------------------------------------------------------| +Diagram of the data models: """ @@ -89,15 +52,14 @@ class DataSource(Source): Data source of the feature. It defines the raw data source the feature is extracted from. """ - pass class FeaturesSource(Source): """ Feature source of the feature. - It defines one of multiple features where the feature is derived from. + It defines one of features where the feature is derived from. """ - input_feature_name_ids: List[FeatureNameId] # List of input feature name Keys + input_feature_name_id: FeatureNameId # Input feature name Keys pass @@ -132,7 +94,7 @@ class DerivedFeature(Feature): """ Feature implementation that is derived from other FeatureNames. """ - source: FeaturesSource # Source features where the feature is derived from + source: List[FeaturesSource] # Source features where the feature is derived from class FeatureName(BaseModel): @@ -146,7 +108,7 @@ class FeatureName(BaseModel): """ id: FeatureNameId # unique ID for FeatureName, used to extract data for current FeatureName project_id: ProjectId # ID of the project the FeatureName belongs to - features: List[FeatureId] # List of ids of feature that the FeatureName has + feature_ids: List[FeatureId] # List of ids of feature that the FeatureName has class Project(BaseModel): @@ -155,7 +117,7 @@ class Project(BaseModel): or a namespace which related FeatureNames have. """ id: ProjectId # Unique ID of the project. - feature_names: List[FeatureNameId] # List of feature name ids that the project has + feature_name_ids: List[FeatureNameId] # List of feature name ids that the project has anchor_ids: List[AnchorId] # List of Anchor ids that the project has @@ -168,4 +130,4 @@ class Anchor(BaseModel): id: AnchorId # Unique ID for Anchor project_id: ProjectId # ID of Project that the anchor belongs to source: DataSource # data source of the Anchor - anchor_features: List[FeatureId] # List of anchor features that the anchor has + anchor_feature_ids: List[FeatureId] # List of anchor features that the anchor has