Skip to content

[DEV-12162] Agency loader#8

Merged
alburde1 merged 10 commits into
qatfrom
mod/dev-12162-agency-loader
May 22, 2026
Merged

[DEV-12162] Agency loader#8
alburde1 merged 10 commits into
qatfrom
mod/dev-12162-agency-loader

Conversation

@alburde1

@alburde1 alburde1 commented May 14, 2026

Copy link
Copy Markdown
Contributor

Description:

Creating a loader to load in all agency data (CGAC, FREC, Subtier).

Technical Details:

Created 3 new gold tables and a new bronze table to house agency data. Updated the existing table models from what was in Broker to simplify without the availability of the FKs. FREC and Subtier tables now use the related codes directly instead of using IDs of higher tier tables.

Requirements for PR Merge:

  1. Unit & integration tests updated
  2. Documentation updated
  3. Data validation completed (examples listed below)
    1. Is performance impacted in the changes (e.g., API, pipeline, downloads, etc.)?
    2. Is the expected data returned with the expected format?
  4. Appropriate Operations ticket(s) created
  5. Jira Ticket(s)
    1. DEV-12162
  6. Developer Reviews
    • Broker Developer Review
    • USAS Developer Review
  7. Merge [DEV-12155] Funding Opportunity Extractor and Loader #6

Explain N/A in above checklist:

alburde1 added 6 commits May 13, 2026 10:47
+ Creating the agency references
+ Creating the initial script containing most of the work for cgac and frec loading
+ Also add subtier data
+ black
+ flake
+ removing prints
Comment thread brus_backend_common/models/lakehouse_model.py Outdated
Comment thread brus_backend_common/models/lakehouse_model.py Outdated
Comment thread brus_backend_common/scripts/extractors/fon.py Outdated
Comment on lines +80 to +87
cgac_data["display_name"] = cgac_data.apply(
lambda row: (
f"{row["agency_name"]} ({row["agency_abbreviation"]})"
if row["agency_abbreviation"]
else f"{row["agency_name"]} (nan)"
),
axis=1,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be done column-wise instead of row-wise to increase performance:

Suggested change
cgac_data["display_name"] = cgac_data.apply(
lambda row: (
f"{row["agency_name"]} ({row["agency_abbreviation"]})"
if row["agency_abbreviation"]
else f"{row["agency_name"]} (nan)"
),
axis=1,
)
cgac_data["display_name"] = (
cgac_data["agency_name"]
+ " ("
+ cgac_data["agency_abbreviation"].replace("", "nan").fillna("nan")
+ ")"
)

Comment on lines +137 to +144
frec_data["display_name"] = frec_data.apply(
lambda row: (
f"{row["agency_name"]} ({row["agency_abbreviation"]})"
if row["agency_abbreviation"]
else f"{row["agency_name"]} (nan)"
),
axis=1,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing here re: column-wise vs row-wise operations

Comment on lines +122 to +131
frec_data = clean_data(
raw_data,
frec_mapping,
{"frec": {"keep_null": False}, "cgac_code": {"pad_to_length": 3}, "frec_code": {"pad_to_length": 4}},
)

# de-dupe
frec_data = frec_data[frec_data.frec_cgac == "TRUE"]
frec_data.drop(["frec_cgac"], axis=1, inplace=True)
frec_data.drop_duplicates(subset=["frec_code"], inplace=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of mutating the data in place, you could chain these:

Suggested change
frec_data = clean_data(
raw_data,
frec_mapping,
{"frec": {"keep_null": False}, "cgac_code": {"pad_to_length": 3}, "frec_code": {"pad_to_length": 4}},
)
# de-dupe
frec_data = frec_data[frec_data.frec_cgac == "TRUE"]
frec_data.drop(["frec_cgac"], axis=1, inplace=True)
frec_data.drop_duplicates(subset=["frec_code"], inplace=True)
frec_data = (
clean_data(
raw_data,
frec_mapping,
{"frec": {"keep_null": False}, "cgac_code": {"pad_to_length": 3}, "frec_code": {"pad_to_length": 4}},
)
.loc[lambda df: df.frec_cgac == "TRUE"]
.drop(columns=["frec_cgac"])
.drop_duplicates(subset=["frec_code"])
)

Comment on lines +182 to +185
raw_data.loc[condition, "PRIORITY"] = 1
raw_data.loc[~condition, "PRIORITY"] = 2
raw_data["PRIORITY"] = raw_data["PRIORITY"].astype(int)
raw_data.replace({"TRUE": True, "FALSE": False}, inplace=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same approach here re: method chaining.

Suggested change
raw_data.loc[condition, "PRIORITY"] = 1
raw_data.loc[~condition, "PRIORITY"] = 2
raw_data["PRIORITY"] = raw_data["PRIORITY"].astype(int)
raw_data.replace({"TRUE": True, "FALSE": False}, inplace=True)
raw_data = (
raw_data
.assign(PRIORITY=lambda df: np.where(df["TOPTIER_FLAG"] == "TRUE", 1, 2).astype(int))
.replace({"TRUE": True, "FALSE": False})
)

Comment thread brus_backend_common/scripts/loaders/defc_gold.py Outdated
Comment thread brus_backend_common/scripts/loaders/defc_gold.py Outdated
Comment thread brus_backend_common/models/reference.py Outdated
DESCRIPTION = "CGAC Data after processing"
CSV_NAME = "cgac.csv"
PK = "cgac_id"
UNIQUE_CONSTRAINTS = []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know UNIQUE_CONSTRAINTS hasn't been setup as an extra validation yet. The intent is for any other columns (or group of columns) needing a unique check. I'm gonna make another PR to 1) fix DEFCGroup's PK but also 2) update the type mapping of UNIQUE_CONSTRAINTS to be List[(str,) | str]; so it can be ['col x', ('col y', 'col z')] to support single column uniqueness but also multiple columns as well.

So in this case (as well as FRECGold and SubtierAgencyGold), since the PKs are x_id, the other unique col would be ["cgac_code"] (or ["frec_code"], ["subtier_code"]).

Again, not functional yet so I'm fine with leaving it alone as it may change in the future when we do implement it. Just letting you know where I'm thinking for now.

cgac_data["display_name"] = (
cgac_data["agency_name"] + " (" + cgac_data["agency_abbreviation"].replace("", "nan").fillna("nan") + ")"
)
logger.info("Overwriting new CGAC data to Broker")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
logger.info("Overwriting new CGAC data to Broker")
logger.info("Overwriting new CGAC data to CGACGold")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for FREC and Subtier

Comment on lines +244 to +246
metrics_json = load_cgac(raw_data, start_time, force_reload, metrics_json)
metrics_json = load_frec(raw_data, start_time, force_reload, metrics_json)
metrics_json = load_subtier(raw_data, start_time, force_reload, metrics_json)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of passing in start_time, could you pull it from metrics_json? I know it gets messy with the strings vs datetimes but when saving the metrics file json.dump(metrics, metrics_file, default=str) including that default=str stringifys the dates automatically which is nice.



if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Process the bronze defc data into the gold defc table.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this was likely based on defc_gold.py which doesnt include this (making another PR fix for that). Could you add a

from brus_backend_common.logging import configure_logging

...

if __name__ == "__main__":
    configure_logging()

here? Running it locally I could see none of the logs.

I'm going to also start looking into a shared Loader class or shared methods that standardizes all our scripts so that we don't need to remember little details like this.

"""Loads the FREC data into the gold table

Args:
raw_data: the raw agency codes bronze table\

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raw_data: the raw agency codes bronze table\
raw_data: the raw agency codes bronze table

@alburde1 alburde1 merged commit 3ecf577 into qat May 22, 2026
10 checks passed
@alburde1 alburde1 deleted the mod/dev-12162-agency-loader branch May 22, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants