Skip to content

Commit c21053c

Browse files
fix(spark): S3/GCS PyArrow filesystem for staging paths
Signed-off-by: abhijeet-dhumal <abhijeetdhumal652@gmail.com>
1 parent 103809a commit c21053c

1 file changed

Lines changed: 42 additions & 11 deletions

File tree

  • sdk/python/feast/infra/offline_stores/contrib/spark_offline_store

sdk/python/feast/infra/offline_stores/contrib/spark_offline_store/spark.py

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -482,21 +482,52 @@ def _to_arrow_via_staging(self) -> pyarrow.Table:
482482
if not parquet_paths:
483483
return pyarrow.table({})
484484

485-
normalized_paths = self._normalize_staging_paths(parquet_paths)
486-
dataset = ds.dataset(normalized_paths, format="parquet")
485+
pa_fs, stripped_paths = self._resolve_staging_filesystem(parquet_paths)
486+
dataset = ds.dataset(stripped_paths, format="parquet", filesystem=pa_fs)
487487
return dataset.to_table()
488488

489-
def _normalize_staging_paths(self, paths: List[str]) -> List[str]:
490-
"""Normalize staging paths for PyArrow datasets."""
489+
def _resolve_staging_filesystem(
490+
self, paths: List[str]
491+
) -> Tuple[Optional[pyarrow.fs.FileSystem], List[str]]:
492+
"""Return (pyarrow filesystem, prefix-stripped paths) for staging URIs."""
493+
sample = paths[0]
494+
495+
if sample.startswith("s3://") or sample.startswith("s3a://"):
496+
import pyarrow.fs as pafs
497+
498+
endpoint = os.environ.get("AWS_ENDPOINT_URL_S3") or os.environ.get(
499+
"AWS_S3_ENDPOINT", ""
500+
)
501+
region = getattr(
502+
self._config.offline_store, "region", None
503+
) or os.environ.get("AWS_DEFAULT_REGION", "us-east-1")
504+
kwargs: Dict[str, Any] = {"region": region}
505+
if endpoint:
506+
kwargs["endpoint_override"] = endpoint.rstrip("/").replace(
507+
"https://", ""
508+
).replace("http://", "")
509+
kwargs["scheme"] = (
510+
"https" if endpoint.startswith("https") else "http"
511+
)
512+
fs = pafs.S3FileSystem(**kwargs)
513+
stripped = [p.replace("s3a://", "").replace("s3://", "") for p in paths]
514+
return fs, stripped
515+
516+
if sample.startswith("gs://"):
517+
import pyarrow.fs as pafs
518+
519+
fs = pafs.GcsFileSystem()
520+
stripped = [p[len("gs://") :] for p in paths]
521+
return fs, stripped
522+
523+
# Local paths
491524
normalized = []
492-
for path in paths:
493-
if path.startswith("file://"):
494-
normalized.append(path[len("file://") :])
495-
elif "://" in path:
496-
normalized.append(path)
525+
for p in paths:
526+
if p.startswith("file://"):
527+
normalized.append(p[len("file://") :])
497528
else:
498-
normalized.append(path)
499-
return normalized
529+
normalized.append(p)
530+
return None, normalized
500531

501532
def to_feast_df(
502533
self,

0 commit comments

Comments
 (0)