USFEMA_FloodInsuranceClaims - #2177
Conversation
Code fix unenergy
There was a problem hiding this comment.
Code Review
This pull request introduces a direct bulk download option for the FEMA NFIP claims dataset as a faster and more reliable alternative to API pagination, which remains as a fallback. It also increases the pagination page size, improves error handling, and refines CSV chunk merging. The review feedback highlights two key improvements: raising an exception on bulk download failures to ensure proper logging instead of a silent fallback, and adding a check to prevent writing empty newlines when a downloaded chunk contains only a header.
|
|
||
| # Define the page size for each API request. | ||
| PAGE_SIZE = 1000 | ||
| PAGE_SIZE = 10000 |
There was a problem hiding this comment.
Is this page size supported?
| logging.info("Starting download to file: %s", final_filepath) | ||
|
|
||
| # The main download loop for pagination | ||
| while total_records == 0 or records_downloaded < total_records: |
There was a problem hiding this comment.
If total_records is 0 (e.g. if the upstream OpenFEMA metadata endpoint returns 0 due to a transient API issue or empty response), total_records == 0 evaluates to True indefinitely, causing an infinite pagination loop.
Consider removing total_records == 0 or from the while condition and adding an explicit pre-check to terminate immediately if total_records == 0:
if total_records == 0:
logging.fatal("Total records returned 0 from API metadata. Cannot proceed.")
raise RuntimeError("Total records returned 0.")| "Failed to download chunk or file not found. Exiting.") | ||
| break | ||
| "Failed to download chunk at skip=%s or file not found. Exiting.", | ||
| skip_count) |
There was a problem hiding this comment.
Under app.run(main), absl.logging.fatal() aborts the process immediately with SIGABRT (exit code 134). Raising RuntimeError immediately afterwards or maintaining trailing control flow is redundant. Ensure fatal logging and exception handling are clean and consistent across standalone and library execution modes.
| 'The temporary directory to store downloaded chunks.') | ||
| _FLAGS = flags.FLAGS | ||
|
|
||
| # Define the page size for each API request. |
There was a problem hiding this comment.
Increasing PAGE_SIZE to 10000 is a great improvement (reducing API chunks from 2,650 to ~265). To further eliminate network overhead and prevent potential timeout/latency issues across ~265 chunks, consider streaming responses directly using a persistent requests.Session with connection pooling rather than making separate unpooled HEAD + GET requests via download_file on each chunk.
| """ | ||
| filename = "fema_nfip_claims.csv" | ||
|
|
||
| output_dir = "input_file" |
There was a problem hiding this comment.
output_dir = "input_file" (and default temp_dir = 'temp_fema_data') resolves relative to the current working directory (os.getcwd()). When executed from the repository root, this creates input_file/ in the repository root rather than inside statvar_imports/fema/flood_insurance_claims/.
Consider resolving paths relative to __file__:
script_dir = os.path.dirname(os.path.abspath(__file__))
output_dir = os.path.join(script_dir, "input_file")There was a problem hiding this comment.
manifest.json processor flags:
The process.py command in manifest.json does not pass --existing_statvar_mcf or --output_counters.
Please add:
--existing_statvar_mcf="gs://unresolved_mcf/scripts/statvar/stat_vars.mcf"(to reuse existing schema definitions and avoid duplicates)--output_counters="counters/counters.txt"(for pipeline counter telemetry in Cloud Batch)
There was a problem hiding this comment.
manifest.json source_files:
manifest.json currently only lists "source_files": ["input_file/fema_nfip_claims.csv"].
Please update "source_files" to include golden files, validation configs, and counters:
"source_files": [
"input_file/fema_nfip_claims.csv",
"golden_data/*.csv",
"validation_config.json",
"counters/*"
]This ensures these files are copied to the version directory in GCS during batch execution for full historical reproducibility.
There was a problem hiding this comment.
validation_config.json date freshness check:
validation_config.json only configures DELETED_RECORDS_PERCENT and GOLDENS_CHECK. Because golden_summary_report.csv excludes MaxDate, there is no automated validation that data is being refreshed with recent dates.
Consider adding a scoped SQL_VALIDATOR rule in validation_config.json asserting that primary active aggregate StatVars (e.g. CountOfClaims_NaturalHazardInsurance_FEMAHighRiskFloodZone_BuildingStructureAndContents_FloodEvent) have a MaxDate within allowable lag (e.g. within 2–3 months of run date).
There was a problem hiding this comment.
Golden fixtures hygiene:
golden_observations.csv: Contains 2,349 rows, exceeding the guideline recommended 50–200 rows. Consider regenerating it filtered againstgs://unresolved_mcf/import_validation/top_100k_places.csv.golden_summary_report.csv: Contains 309 StatVars with hardcodedNumPlaces. As FEMA claims expand geographically over time, exact place count checks cause false positive golden check failures. Consider filtering againstgs://unresolved_mcf/import_validation/nl_statvars.csvusingvalidator_goldens.py.
| 'The temporary directory to store downloaded chunks.') | ||
| _FLAGS = flags.FLAGS | ||
|
|
||
| # Define the page size for each API request. |
There was a problem hiding this comment.
Verification on Page Size & Bulk Download Parity
-
Page Size Limit (
$top=10000):- OpenFEMA API documentation confirms that
$topdefaults to1,000and supports a maximum of10,000records per request. - Live testing against
https://www.fema.gov/api/open/v2/FimaNfipClaims?$format=csv&$top=10000&$skip=0returnsHTTP 200with all 10,000 records in ~1.2s without throttling.
- OpenFEMA API documentation confirms that
-
Bulk CSV Dataset Parity (
bulk_url):https://www.fema.gov/about/reports-and-data/openfema/FimaNfipClaims.csvcontains the full historical dataset (~1.06 GB, ~2.72M records).- The CSV headers contain all 73 columns, matching the API CSV schema 1:1, and both are updated monthly (
R/P1M) on OpenFEMA's release schedule.
-
Recommendation:
- Direct
bulk_urldownload is well-suited as the primary download method (~1–2 min download time vs 50+ hours). PAGE_SIZE = 10000($top=10000) is safe and officially supported for API pagination fallback.
- Direct
Description
This PR optimizes and stabilizes the data download pipeline for the FEMA NFIP Flood Insurance Claims import.
Key Changes
Direct Bulk Download Support:
bulk_urlsupport to download the full dataset (FimaNfipClaims.csv) directly from OpenFEMA as the primary method, significantly speeding up the download process.Error Handling & Fallback Visibility:
CSV Chunk Concatenation Fixes:
exist_ok=Trueand cleanup infinallyblocks).Testing & Coverage:
fema_download_test.pycovering:Verification