Forum Discussion

kinsin5's avatar
kinsin5
New Member
8 months ago
Solved

Checking if semantic model is composite

Hi,   Do you know how can I check semantic model metadata using sempy? I want to list all composite models inside all workspaces.
  • GeraldGEmerick's avatar
    8 months ago

    kinsin5 As far as I know, there isn’t a first-class “IsComposite” flag in SemPy right now; you infer it from things like partition storage modes and data source types.

     

    Below is a pattern that might work in Fabric notebooks.

     

    1. Basic semantic model metadata with SemPy

    From a Fabric notebook:

     
    %pip install semantic-link -q
    %load_ext sempy
    
    import sempy.fabric as fabric

     

    Typical metadata calls for a single semantic model:

     
    dataset = "My Semantic Model"
    workspace = "My Workspace"   # or workspace ID
    # Tables / columns / measures
    tables      = fabric.list_tables(dataset=dataset, workspace=workspace)
    columns     = fabric.list_columns(dataset=dataset, workspace=workspace)
    measures    = fabric.list_measures(dataset=dataset, workspace=workspace)
    # Relationships
    relationships = fabric.list_relationships(dataset=dataset, workspace=workspace)
    # Partitions (this is where storage mode lives)
    partitions  = fabric.list_partitions(dataset=dataset, workspace=workspace, extended=True)
    # Data sources (for checking Analysis Services / other PBI models, etc.)
    datasources = fabric.list_datasources(dataset=dataset, workspace=workspace)

     

    These all come back as pandas DataFrames, so you can query them however you like.

    2. Listing all composite models across all Fabric workspaces

    A semantic model is “composite” if, for example:

    • It has different storage modes across tables/partitions (Import + DirectQuery, DirectLake + Import, etc.), or

    • It uses another semantic model / AAS as a data source (via AnalysisServices / PowerBI source types).

    SemPy gives you enough to derive that:

    • fabric.list_workspaces() -> all workspaces you can see

    • fabric.list_datasets(workspace=...) -> semantic models in a workspace

    • fabric.list_partitions(...) + fabric.list_datasources(...) -> storage modes & source types per model

    So maybe something along these lines:

    %load_ext sempy
    import sempy.fabric as fabric
    import pandas as pd
    
    def classify_composite_for_dataset(workspace_name: str, dataset_name: str) -> dict:
        # Partitions: storage mode per table
        parts = fabric.list_partitions(
            workspace=workspace_name,
            dataset=dataset_name,
            extended=True
        )
    
        if parts is None or parts.empty:
            modes = set()
        else:
            modes = set(parts["Mode"].dropna().unique())
    
        # Data sources: where the data is coming from
        try:
            ds_df = fabric.list_datasources(
                workspace=workspace_name,
                dataset=dataset_name
            )
        except Exception:
            ds_df = pd.DataFrame()
    
        if ds_df is None or ds_df.empty:
            source_types = set()
        else:
            # Column name is typically "Type" in list_datasources output
            source_types = set(ds_df["Type"].dropna().unique())
    
        # Heuristics for "composite"
        has_import      = "Import" in modes
        has_directquery = "DirectQuery" in modes
        has_directlake  = "DirectLake" in modes
        has_multiple_modes = len(modes) > 1
    
        # Remote semantic models / AAS as datasources
        uses_remote_semantic = any(
            t in source_types for t in ["AnalysisServices", "PowerBI"]
        )
    
        is_composite = (
            has_multiple_modes
            or (has_directquery and (modes - {"DirectQuery"}))   # DQ + something else
            or (has_directlake and (has_import or "Dual" in modes))
            or uses_remote_semantic
        )
    
        return {
            "Workspace": workspace_name,
            "Dataset": dataset_name,
            "Modes": ", ".join(sorted(modes)) if modes else "",
            "SourceTypes": ", ".join(sorted(source_types)) if source_types else "",
            "IsComposite": is_composite,
        }
    
    
    def list_composite_models(include_personal_workspaces: bool = False) -> pd.DataFrame:
        workspaces = fabric.list_workspaces()   # all workspaces you can access
    
        # Optional: filter out personal workspaces if the column exists
        if not include_personal_workspaces and "Type" in workspaces.columns:
            workspaces = workspaces[workspaces["Type"] != "Personal"]
    
        rows = []
    
        for _, ws in workspaces.iterrows():
            ws_name = ws["Name"]
            # could also use ws["Id"]; sempy accepts name or ID in most functions
    
            datasets = fabric.list_datasets(workspace=ws_name)
            if datasets is None or datasets.empty:
                continue
    
            for _, ds in datasets.iterrows():
                ds_name = ds["Name"]
                info = classify_composite_for_dataset(ws_name, ds_name)
                rows.append(info)
    
        return pd.DataFrame(rows)
    
    
    # Run the scan
    all_models = list_composite_models(include_personal_workspaces=False)
    
    # Only composite semantic models
    composite_models = all_models[all_models["IsComposite"]].copy()
    
    display(composite_models)

     

    That composite_models DataFrame will give you, per semantic model:

    • Workspace name

    • Dataset / semantic model name

    • All storage modes it uses (from list_partitions)

    • All data source types (from list_datasources)

    • A boolean IsComposite based on the rules above

    You can then:

    • Write it to a Lakehouse table and build a governance semantic model on top,

    • Or slice and dice it directly in the notebook.

    Notes:

    • Permissions: You’ll only see workspaces and semantic models you have rights to. For full-tenant scanning you typically combine this with admin or scanner APIs (often via Semantic Link Labs, not plain SemPy).

    • Definition of “composite”: If you want to be super strict (e.g., “DQ over PBI dataset + local tables only”), tweak the heuristic in classify_composite_for_dataset.

    • Performance: On big tenants, you may want to:

      • Filter list_workspaces() first (e.g., only dedicated capacities, only certain domains), and/or

      • Parallelize per-workspace scans with multiprocessing in Python.