Skip to content

Commit 031ba15

Browse files
bdchathamEric Zou
authored andcommitted
feat: Feature/get record api (aws#650)
Co-authored-by: Eric Zou <[email protected]>
1 parent ad9e259 commit 031ba15

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

src/sagemaker/feature_store/feature_group.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,23 @@ def load_feature_definitions(
644644
self.feature_definitions = feature_definitions
645645
return self.feature_definitions
646646

647+
def get_record(
648+
self, record_identifier_value_as_string: str, feature_names: Sequence[str] = None
649+
) -> Sequence[Dict[str, str]]:
650+
"""Get a single record in a FeatureGroup
651+
652+
Args:
653+
record_identifier_value_as_string (String):
654+
a String representing the value of the record identifier.
655+
feature_names (Sequence[String]):
656+
a list of Strings representing feature names.
657+
"""
658+
return self.sagemaker_session.get_record(
659+
record_identifier_value_as_string=record_identifier_value_as_string,
660+
feature_group_name=self.name,
661+
feature_names=feature_names,
662+
).get("Record")
663+
647664
def put_record(self, record: Sequence[FeatureValue]):
648665
"""Put a single record in the FeatureGroup.
649666

src/sagemaker/session.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4454,6 +4454,29 @@ def put_record(
44544454
Record=record,
44554455
)
44564456

4457+
def get_record(
4458+
self,
4459+
record_identifier_value_as_string: str,
4460+
feature_group_name: str,
4461+
feature_names: Sequence[str],
4462+
) -> Dict[str, Sequence[Dict[str, str]]]:
4463+
"""Gets a single record in the FeatureGroup.
4464+
4465+
Args:
4466+
record_identifier_value_as_string (str): name of the record identifier.
4467+
feature_group_name (str): name of the FeatureGroup.
4468+
feature_names (Sequence[str]): list of feature names.
4469+
"""
4470+
get_record_args = {
4471+
"FeatureGroupName": feature_group_name,
4472+
"RecordIdentifierValueAsString": record_identifier_value_as_string,
4473+
}
4474+
4475+
if feature_names:
4476+
get_record_args["FeatureNames"] = feature_names
4477+
4478+
return self.sagemaker_featurestore_runtime_client.get_record(**get_record_args)
4479+
44574480
def start_query_execution(
44584481
self,
44594482
catalog: str,

tests/integ/test_feature_store.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ def test_create_feature_group_glue_table_format(
271271
offline_store_s3_uri,
272272
pandas_data_frame,
273273
):
274-
feature_group = FeatureGroup(name=feature_group_name, sagemaker_session=feature_store_session)
274+
feature_group = FeatureGroup(name=feature_group_name,
275+
sagemaker_session=feature_store_session)
275276
feature_group.load_feature_definitions(data_frame=pandas_data_frame)
276277

277278
with cleanup_feature_group(feature_group):
@@ -288,6 +289,52 @@ def test_create_feature_group_glue_table_format(
288289
table_format = feature_group.describe().get("OfflineStoreConfig").get("TableFormat")
289290
assert table_format == "Glue"
290291

292+
def test_get_record(
293+
feature_store_session,
294+
role,
295+
feature_group_name,
296+
pandas_data_frame,
297+
record,
298+
):
299+
feature_group = FeatureGroup(name=feature_group_name, sagemaker_session=feature_store_session)
300+
feature_group.load_feature_definitions(data_frame=pandas_data_frame)
301+
302+
record_identifier_value_as_string = record[0].value_as_string
303+
with cleanup_feature_group(feature_group):
304+
feature_group.create(
305+
s3_uri=False,
306+
record_identifier_name="feature1",
307+
event_time_feature_name="feature3",
308+
role_arn=role,
309+
enable_online_store=True,
310+
)
311+
_wait_for_feature_group_create(feature_group)
312+
# Ingest data
313+
feature_group.put_record(record=record)
314+
# Retrieve data
315+
retrieved_record = feature_group.get_record(
316+
record_identifier_value_as_string=record_identifier_value_as_string,
317+
)
318+
record_names = list(map(lambda r: r.feature_name, record))
319+
assert len(retrieved_record) == len(record_names)
320+
for feature in retrieved_record:
321+
assert feature["FeatureName"] in record_names
322+
removed_feature_name = record_names.pop()
323+
# Retrieve data
324+
retrieved_record = feature_group.get_record(
325+
record_identifier_value_as_string=record_identifier_value_as_string,
326+
feature_names=record_names,
327+
)
328+
assert len(retrieved_record) == len(record_names)
329+
for feature in retrieved_record:
330+
assert feature["FeatureName"] in record_names
331+
assert feature["FeatureName"] is not removed_feature_name
332+
# Retrieve data
333+
retrieved_record = feature_group.get_record(
334+
record_identifier_value_as_string="1.0",
335+
)
336+
assert retrieved_record is None
337+
291338

292339
def test_update_feature_group(
293340
feature_store_session,

tests/unit/sagemaker/feature_store/test_feature_group.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,22 @@ def test_feature_metadata_describe(sagemaker_session_mock):
201201
)
202202

203203

204+
def test_get_record(sagemaker_session_mock):
205+
feature_group_name = "MyFeatureGroup"
206+
feature_names = ["MyFeature1", "MyFeature2"]
207+
record_identifier_value_as_string = "1.0"
208+
feature_group = FeatureGroup(name=feature_group_name, sagemaker_session=sagemaker_session_mock)
209+
feature_group.get_record(
210+
record_identifier_value_as_string=record_identifier_value_as_string,
211+
feature_names=feature_names,
212+
)
213+
sagemaker_session_mock.get_record.assert_called_with(
214+
feature_group_name=feature_group_name,
215+
record_identifier_value_as_string=record_identifier_value_as_string,
216+
feature_names=feature_names,
217+
)
218+
219+
204220
def test_put_record(sagemaker_session_mock):
205221
feature_group = FeatureGroup(name="MyFeatureGroup", sagemaker_session=sagemaker_session_mock)
206222
feature_group.put_record(record=[])

0 commit comments

Comments
 (0)