Skip to content

Commit 0c845a1

Browse files
fix: Serialize UUID and TimeUuid entity keys (#7032)
An entity whose join key is a Uuid or TimeUuid could be applied, but materializing it failed in serialize_entity_key with "Value type not supported for feast feature store", so its features never reached the online store and could not be served. Encode uuid_val and time_uuid_val as their UTF-8 string with the UUID and TIME_UUID value type tags, and decode them back in deserialize_entity_key. Signed-off-by: Mohammad Hijjawi <[email protected]> Co-authored-by: Shuchu Han <[email protected]>
1 parent 9420fac commit 0c845a1

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

‎sdk/python/feast/infra/key_encoding_utils.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ def _serialize_val(
2424
return struct.pack("<q", v.int64_val), ValueType.INT64
2525
elif value_type == "unix_timestamp_val":
2626
return struct.pack("<q", v.unix_timestamp_val), ValueType.UNIX_TIMESTAMP
27+
elif value_type == "uuid_val":
28+
return v.uuid_val.encode("utf8"), ValueType.UUID
29+
elif value_type == "time_uuid_val":
30+
return v.time_uuid_val.encode("utf8"), ValueType.TIME_UUID
2731
else:
2832
raise ValueError(f"Value type not supported for feast feature store: {v}")
2933

@@ -43,6 +47,10 @@ def _deserialize_value(value_type, value_bytes) -> ValueProto:
4347
elif value_type == ValueType.UNIX_TIMESTAMP:
4448
value = struct.unpack("<q", value_bytes)[0]
4549
return ValueProto(unix_timestamp_val=value)
50+
elif value_type == ValueType.UUID:
51+
return ValueProto(uuid_val=value_bytes.decode("utf-8"))
52+
elif value_type == ValueType.TIME_UUID:
53+
return ValueProto(time_uuid_val=value_bytes.decode("utf-8"))
4654
else:
4755
raise ValueError(f"Unsupported value type: {value_type}")
4856

‎sdk/python/tests/unit/infra/test_key_encoding_utils.py‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import pytest
2+
13
from feast.infra.key_encoding_utils import (
24
_deserialize_value,
35
_serialize_val,
@@ -131,6 +133,44 @@ def test_serialize_deserialize_unix_timestamp_entity():
131133
assert deserialized_key.entity_values[0].unix_timestamp_val == 1758823656
132134

133135

136+
@pytest.mark.parametrize(
137+
"value_field, value_type, value",
138+
[
139+
("uuid_val", ValueType.UUID, "a8098c1a-f86e-41da-bd1a-00112444be1e"),
140+
(
141+
"time_uuid_val",
142+
ValueType.TIME_UUID,
143+
"c232ab00-9414-11ec-b3c8-9f6bdeced846",
144+
),
145+
],
146+
ids=["uuid", "time_uuid"],
147+
)
148+
def test_serialize_deserialize_uuid_entity(value_field, value_type, value):
149+
serialized_value, serialized_type = _serialize_val(
150+
value_field, ValueProto(**{value_field: value})
151+
)
152+
assert serialized_type == value_type
153+
assert serialized_value == value.encode("utf8")
154+
155+
entity_key_proto = EntityKeyProto(
156+
join_keys=["session_id"],
157+
entity_values=[ValueProto(**{value_field: value})],
158+
)
159+
160+
serialized_key = serialize_entity_key(
161+
entity_key_proto,
162+
entity_key_serialization_version=3,
163+
)
164+
165+
deserialized_key = deserialize_entity_key(
166+
serialized_key,
167+
entity_key_serialization_version=3,
168+
)
169+
170+
assert deserialized_key == entity_key_proto
171+
assert getattr(deserialized_key.entity_values[0], value_field) == value
172+
173+
134174
def test_reserialize_entity_v2_key_to_v3():
135175
entity_key_proto_v2 = EntityKeyProto(
136176
join_keys=["user"],

0 commit comments

Comments
 (0)