(
table: Union[pyarrow.Table, pyarrow.RecordBatch],
feature_view: "OnDemandFeatureView",
join_keys: Dict[str, ValueType],
)
| 482 | |
| 483 | |
| 484 | def _convert_arrow_odfv_to_proto( |
| 485 | table: Union[pyarrow.Table, pyarrow.RecordBatch], |
| 486 | feature_view: "OnDemandFeatureView", |
| 487 | join_keys: Dict[str, ValueType], |
| 488 | ) -> List[Tuple[EntityKeyProto, Dict[str, ValueProto], datetime, Optional[datetime]]]: |
| 489 | # Avoid ChunkedArrays which guarantees `zero_copy_only` available. |
| 490 | if isinstance(table, pyarrow.Table): |
| 491 | table = table.to_batches()[0] |
| 492 | |
| 493 | columns = [ |
| 494 | (field.name, field.dtype.to_value_type()) for field in feature_view.features |
| 495 | ] + list(join_keys.items()) |
| 496 | |
| 497 | # Convert columns that exist in the table |
| 498 | proto_values_by_column = _columns_to_proto_values( |
| 499 | table, columns, allow_missing=True |
| 500 | ) |
| 501 | |
| 502 | # Ensure join keys are included, creating null values if missing from table |
| 503 | for join_key, value_type in join_keys.items(): |
| 504 | if join_key not in proto_values_by_column: |
| 505 | if join_key in table.column_names: |
| 506 | proto_values_by_column[join_key] = python_values_to_proto_values( |
| 507 | table.column(join_key).to_numpy(zero_copy_only=False), value_type |
| 508 | ) |
| 509 | else: |
| 510 | # Create null proto values directly (no need to build a PyArrow array) |
| 511 | proto_values_by_column[join_key] = python_values_to_proto_values( |
| 512 | [None] * table.num_rows, value_type |
| 513 | ) |
| 514 | |
| 515 | # Cache column names set to avoid recreating list in loop |
| 516 | column_names = {c[0] for c in columns} |
| 517 | |
| 518 | # Adding On Demand Features that are missing from proto_values |
| 519 | for feature in feature_view.features: |
| 520 | if feature.name in column_names and feature.name not in proto_values_by_column: |
| 521 | # Create null proto values directly (more efficient than building PyArrow array) |
| 522 | proto_values_by_column[feature.name] = python_values_to_proto_values( |
| 523 | [None] * table.num_rows, feature.dtype.to_value_type() |
| 524 | ) |
| 525 | |
| 526 | entity_keys = _build_entity_keys(table.num_rows, join_keys, proto_values_by_column) |
| 527 | |
| 528 | # Serialize the features per row |
| 529 | feature_dict = { |
| 530 | feature.name: proto_values_by_column[feature.name] |
| 531 | for feature in feature_view.features |
| 532 | if feature.name in proto_values_by_column |
| 533 | } |
| 534 | if feature_view.write_to_online_store: |
| 535 | table_columns = {col.name for col in table.schema} |
| 536 | for feature in feature_view.schema: |
| 537 | if feature.name not in feature_dict and feature.name in table_columns: |
| 538 | feature_dict[feature.name] = proto_values_by_column[feature.name] |
| 539 | |
| 540 | features = [dict(zip(feature_dict, vars)) for vars in zip(*feature_dict.values())] |
| 541 |
no test coverage detected