Skip to content

Support custom namespaces in MCF and observations importers - #661

Open
dwnoble wants to merge 2 commits into
datacommonsorg:masterfrom
dwnoble:custom-namespace-importer-fix
Open

Support custom namespaces in MCF and observations importers#661
dwnoble wants to merge 2 commits into
datacommonsorg:masterfrom
dwnoble:custom-namespace-importer-fix

Conversation

@dwnoble

@dwnoble dwnoble commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Add support for custom namespace subjects and objects in MCF and Observations importers, allowing custom namespace data sources to be successfully processed.

Highlights:

  1. MCF Importer Namespace Resolution: Updated simple/kg_util/mcf_parser.py and mcf_importer.py to parse and maintain custom namespaces in the node properties.
  2. Observations Importer Namespace support: Ensured simple/stats/observations_importer.py handles namespaced identifiers during pre-resolution and resolving phases.
  3. Validation & Test Cases: Added test inputs and expected output files for custom namespace testing (custom_namespace_provenance and custom_namespace_observations).

@codacy-production

codacy-production Bot commented Jul 17, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity

Metric Results
Complexity 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request refactors the data importers to support streaming and chunked processing of observations, reducing memory usage, and adds support for custom namespaces in entity resolution. Feedback on the changes highlights opportunities to optimize performance by deduplicating entity lists before resolution in both ObservationsImporter and EventsImporter to avoid redundant API requests, as well as a minor consistency improvement in logging paths.

Comment thread simple/stats/observations_importer.py Outdated
Comment on lines +225 to +227
unresolved = [
e for e in entities if e not in self._resolved_entities_cache
]

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.

high

Deduplicating the unresolved list of entities before calling _do_resolve is highly recommended. Since observations data often contains many duplicate entities (e.g., multiple dates or variables for the same entity), resolving duplicates externally can result in redundant network requests and API load. Deduplicating them locally improves performance and efficiency.

Suggested change
unresolved = [
e for e in entities if e not in self._resolved_entities_cache
]
unresolved = list(set(
e for e in entities if e not in self._resolved_entities_cache
))

Comment thread simple/stats/events_importer.py Outdated
Comment on lines +272 to +287
def _resolve(self, entities: list[str]) -> dict[str, str]:
lower_case_entity_name = self.entity_column_name.lower()

# Check if the entities can be resolved locally.
# If so, return them by prefixing the values as appropriate.
if lower_case_entity_name in constants.PRE_RESOLVED_INPUT_COLUMNS_TO_PREFIXES:
prefix = constants.PRE_RESOLVED_INPUT_COLUMNS_TO_PREFIXES[
lower_case_entity_name]
return dict([(entity, f"{prefix}{entity}") for entity in entities])

# Resolve entities externally.
property_name = constants.EXTERNALLY_RESOLVED_INPUT_COLUMNS_TO_PREFIXES.get(
lower_case_entity_name, constants.PROPERTY_DESCRIPTION)
return dc.resolve_entities(entities=entities,
entity_type=self.entity_type,
property_name=property_name)

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.

high

Deduplicating the entities list before resolving them (either locally or externally) is highly recommended. Since events data can contain many duplicate entities, resolving duplicates externally can result in redundant network requests and API load. Deduplicating them locally improves performance and efficiency.

Suggested change
def _resolve(self, entities: list[str]) -> dict[str, str]:
lower_case_entity_name = self.entity_column_name.lower()
# Check if the entities can be resolved locally.
# If so, return them by prefixing the values as appropriate.
if lower_case_entity_name in constants.PRE_RESOLVED_INPUT_COLUMNS_TO_PREFIXES:
prefix = constants.PRE_RESOLVED_INPUT_COLUMNS_TO_PREFIXES[
lower_case_entity_name]
return dict([(entity, f"{prefix}{entity}") for entity in entities])
# Resolve entities externally.
property_name = constants.EXTERNALLY_RESOLVED_INPUT_COLUMNS_TO_PREFIXES.get(
lower_case_entity_name, constants.PROPERTY_DESCRIPTION)
return dc.resolve_entities(entities=entities,
entity_type=self.entity_type,
property_name=property_name)
def _resolve(self, entities: list[str]) -> dict[str, str]:
lower_case_entity_name = self.entity_column_name.lower()
unique_entities = list(set(entities))
# Check if the entities can be resolved locally.
# If so, return them by prefixing the values as appropriate.
if lower_case_entity_name in constants.PRE_RESOLVED_INPUT_COLUMNS_TO_PREFIXES:
prefix = constants.PRE_RESOLVED_INPUT_COLUMNS_TO_PREFIXES[
lower_case_entity_name]
return dict([(entity, f"{prefix}{entity}") for entity in unique_entities])
# Resolve entities externally.
property_name = constants.EXTERNALLY_RESOLVED_INPUT_COLUMNS_TO_PREFIXES.get(
lower_case_entity_name, constants.PROPERTY_DESCRIPTION)
return dc.resolve_entities(entities=unique_entities,
entity_type=self.entity_type,
property_name=property_name)

Comment thread simple/stats/observations_importer.py Outdated
def _write_debug_csvs(self) -> None:
if self.debug_resolve_df is not None:
logging.info("Writing resolutions (for debugging) to: %s",
self.debug_resolve_file.path)

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.

medium

For consistency with EventsImporter and to provide more useful debugging information, log the full path of the debug resolve file (self.debug_resolve_file) instead of just the relative path (self.debug_resolve_file.path).

                         self.debug_resolve_file

@dwnoble
dwnoble force-pushed the custom-namespace-importer-fix branch from 5ad9973 to 8184c49 Compare July 17, 2026 10:07
@dwnoble
dwnoble force-pushed the custom-namespace-importer-fix branch from 8184c49 to a7dad39 Compare July 17, 2026 10:11
@dwnoble
dwnoble requested review from clincoln8 and gmechali July 17, 2026 10:16
in ('location', 'observedNode', 'containedInPlace', 'containedIn',
'populationType', 'measuredProperty', 'measurementDenominator',
'populationGroup', 'constraintProperties', 'measurementMethod',
'comparedNode', 'source', 'sourceLink'))

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.

We got rid of sourceLink that was a mistake. It should just be source

@@ -172,9 +173,12 @@ def _resolve_entities(self) -> None:
pre_resolved_entities = {}

def remove_pre_resolved(entity: str) -> bool:

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.

should we just make a shared helper called remove_pre_resolve?

@@ -0,0 +1,7 @@
{
"inputFiles": {

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 think this is the legacy config.json format. Can you use the new one? (notice the input.csv is the key to the map

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.

2 participants