Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions sdv/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,17 @@ def _get_root_tables(relationships):
return parent_tables - child_tables


def _get_max_child_depth(child_map, table):
"""Return the max child depth for the given table."""
max_depth = 1
for child in child_map[table]:
child_depth = 1 + _get_max_child_depth(child_map, child)
if child_depth > max_depth:
max_depth = child_depth

return max_depth


def generate_synthesizer_id(synthesizer):
"""Generate a unique identifier for the synthesizer instance.

Expand Down
20 changes: 20 additions & 0 deletions sdv/metadata/multi_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from sdv._utils import (
_cast_to_iterable,
_format_invalid_values_string,
_get_max_child_depth,
_get_root_tables,
_get_unreferenced_keys,
_load_data_from_csv,
)
Expand Down Expand Up @@ -289,6 +291,24 @@ def _get_all_keys(self, table_name):
foreign_keys = self._get_all_foreign_keys(table_name)
return set(foreign_keys).union(self.tables[table_name]._get_primary_and_alternate_keys())

def _get_max_schema_depth(self):
"""Calculate the maximum depth of this schema.

This method traverses all relationships and returns the length of the longest relationship
chain between tables.

Returns:
int:
The maximum depth of the schema.
"""
max_depth = 1
child_map = self._get_child_map()
for root_table in _get_root_tables(self.relationships):
root_depth = _get_max_child_depth(child_map, root_table)
max_depth = root_depth if root_depth > max_depth else max_depth

return max_depth

def add_relationship(
self, parent_table_name, child_table_name, parent_primary_key, child_foreign_key
):
Expand Down
50 changes: 14 additions & 36 deletions sdv/multi_table/hma.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def __init__(self, metadata, locales=['en_US'], verbose=True):
child_tables.add(relationship['child_table_name'])
for child_table_name in child_tables:
self.set_table_parameters(child_table_name, {'default_distribution': 'norm'})
self._print_estimate_warning()
self._validate_schema_complexity()

def set_table_parameters(self, table_name, table_parameters):
"""Update the table's synthesizer instantiation parameters.
Expand Down Expand Up @@ -260,42 +260,20 @@ def _get_distributions(self):

return distributions

def _print_estimate_warning(self):
total_est_cols = 0
metadata_columns = self._get_num_data_columns(self.metadata)
print_table = []
distributions = self._get_distributions()
estimated_columns = self._estimate_num_columns(self.metadata, distributions)
for table, est_cols in estimated_columns.items():
entry = []
entry.append(table)
entry.append(sum(metadata_columns[table]))
total_est_cols += est_cols
entry.append(min(est_cols, PERFORMANCE_ALERT_DISPLAY_CAP))
print_table.append(entry)

if total_est_cols > MAX_NUMBER_OF_COLUMNS:
display_total = (
f'{PERFORMANCE_ALERT_DISPLAY_CAP}+'
if total_est_cols > PERFORMANCE_ALERT_DISPLAY_CAP
else f'{total_est_cols}'
)
self._print(
'PerformanceAlert: Using the HMASynthesizer on this metadata '
'schema is not recommended. To model this data, HMA will '
f'generate a large number of columns. ({display_total} columns)\n\n'
)
self._print(
pd.DataFrame(
print_table, columns=['Table Name', '# Columns in Metadata', 'Est # Columns']
).to_string(index=False)
+ '\n'
)
self._print(
'We recommend simplifying your metadata schema using '
"'sdv.utils.poc.simplify_schema'.\nIf this is not possible, please visit "
'datacebo.com and reach out to us for enterprise solutions.\n'
def _validate_schema_complexity(self):
num_tables = len(self.metadata.tables)
schema_depth = self.metadata._get_max_schema_depth()

if num_tables > 5 or schema_depth > 2:
error_msg = (
'HMASynthesizer is not designed to handle a schema with more than 5 tables or '
'relationship depth greater than 2.\n'
'Please use SDV Enterprise to model this schema.\n\n'
'SDV Enterprise provides access to synthesizers that can easily scale with the '
'amount of data and complexity of your schema.\n\n'
'For more information, visit datacebo.com'
)
raise SynthesizerInputError(error_msg)

def preprocess(self, data):
"""Transform the raw data to numerical space.
Expand Down
6 changes: 0 additions & 6 deletions tests/integration/multi_table/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ def data_metadata_1_to_1(fake_hotels):
}

metadata_dict['relationships'] = [
{
'parent_table_name': 'hotels',
'parent_primary_key': 'hotel_id',
'child_table_name': 'guests',
'child_foreign_key': 'hotel_id',
},
{
'parent_table_name': 'guests',
'parent_primary_key': 'guest_email',
Expand Down
Loading