Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ingest/looker): update browse paths to align with looker UI #10147

Merged
merged 5 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 2 additions & 1 deletion docs/how/updating-datahub.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ This file documents any backwards-incompatible changes in DataHub and assists pe
- #10026 - The dbt `use_compiled_code` option has been removed, because we now support capturing both source and compiled dbt SQL. This can be configured using `include_compiled_code`, which will be default enabled in 0.13.1.
- #10055 - Assertion entities generated by dbt are now associated with the dbt dataset entity, and not the entity in the data warehouse.
- #10090 - For Redshift ingestion, `use_lineage_v2` is now enabled by default.

- #10147 - For looker ingestion, the browse paths for looker Dashboard, Chart, View, Explore have been updated to align with Looker UI. This does not affect URNs or lineage but primarily affects (improves) browsing experience.
-
### Potential Downtime

### Deprecations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,7 @@ class LookerDashboardElement:
type: Optional[str] = None
description: Optional[str] = None
input_fields: Optional[List[InputFieldElement]] = None
folder_path: Optional[str] = None # for independent looks.

def url(self, base_url: str) -> str:
# A dashboard element can use a look or just a raw query against an explore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,12 @@ def _get_looker_dashboard_element( # noqa: C901
else:
slug = ""

look_folder_path = None
if element.look.folder is not None:
look_folder_path = self._get_folder_path(
element.look.folder, self.looker_api
)

return LookerDashboardElement(
id=element.id,
title=title,
Expand All @@ -464,6 +470,7 @@ def _get_looker_dashboard_element( # noqa: C901
for exp in explores
],
input_fields=input_fields,
folder_path=look_folder_path,
)

# Failing the above two approaches, pick out details from result_maker
Expand Down Expand Up @@ -524,10 +531,12 @@ def _get_looker_dashboard_element( # noqa: C901
type=element.type,
description=element.subtitle_text,
look_id=element.look_id,
query_slug=element.result_maker.query.slug
if element.result_maker.query is not None
and element.result_maker.query.slug is not None
else "",
query_slug=(
element.result_maker.query.slug
if element.result_maker.query is not None
and element.result_maker.query.slug is not None
else ""
),
upstream_explores=[
LookerExplore(model_name=model, name=exp) for exp in explores
],
Expand Down Expand Up @@ -603,11 +612,15 @@ def _make_chart_metadata_events(
chartUrl=dashboard_element.url(self.source_config.external_base_url or ""),
inputs=dashboard_element.get_view_urns(self.source_config),
customProperties={
"upstream_fields": ",".join(
sorted(set(field.name for field in dashboard_element.input_fields))
"upstream_fields": (
",".join(
sorted(
set(field.name for field in dashboard_element.input_fields)
)
)
if dashboard_element.input_fields
else ""
)
if dashboard_element.input_fields
else ""
},
)
chart_snapshot.aspects.append(chart_info)
Expand All @@ -617,6 +630,13 @@ def _make_chart_metadata_events(
paths=[f"/Folders/{dashboard.folder_path}/{dashboard.title}"]
)
chart_snapshot.aspects.append(browse_path)
elif (
dashboard is None and dashboard_element.folder_path is not None
): # independent look
browse_path = BrowsePathsClass(
paths=[f"/Folders/{dashboard_element.folder_path}"]
)
chart_snapshot.aspects.append(browse_path)

if dashboard is not None:
ownership = self.get_ownership(dashboard)
Expand Down Expand Up @@ -1084,10 +1104,12 @@ def process_dashboard(
looker_dashboard = self._get_looker_dashboard(dashboard_object, self.looker_api)
mces = self._make_dashboard_and_chart_mces(looker_dashboard)
workunits = [
MetadataWorkUnit(id=f"looker-{mce.proposedSnapshot.urn}", mce=mce)
if isinstance(mce, MetadataChangeEvent)
else MetadataWorkUnit(
id=f"looker-{mce.aspectName}-{mce.entityUrn}", mcp=mce
(
MetadataWorkUnit(id=f"looker-{mce.proposedSnapshot.urn}", mce=mce)
if isinstance(mce, MetadataChangeEvent)
else MetadataWorkUnit(
id=f"looker-{mce.aspectName}-{mce.entityUrn}", mcp=mce
)
)
for mce in mces
]
Expand Down Expand Up @@ -1177,12 +1199,7 @@ def extract_independent_looks(self) -> Iterable[MetadataWorkUnit]:
self.reporter.report_stage_start("extract_independent_looks")

logger.debug("Extracting looks not part of Dashboard")
look_fields: List[str] = [
"id",
"title",
"description",
"query_id",
]
look_fields: List[str] = ["id", "title", "description", "query_id", "folder"]
query_fields: List[str] = [
"id",
"view",
Expand Down Expand Up @@ -1227,8 +1244,8 @@ def extract_independent_looks(self) -> Iterable[MetadataWorkUnit]:
subtitle_text=look.description,
look_id=look.id,
dashboard_id=None, # As this is independent look
look=LookWithQuery(query=query),
)
look=LookWithQuery(query=query, folder=look.folder),
),
)

if dashboard_element is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,13 @@
}
]
}
},
{
"com.linkedin.pegasus2avro.common.BrowsePaths": {
"paths": [
"/Folders/Shared"
]
}
}
]
}
Expand Down Expand Up @@ -397,6 +404,29 @@
"lastRunId": "no-run-id-provided"
}
},
{
"entityType": "chart",
"entityUrn": "urn:li:chart:(looker,dashboard_elements.looks_1)",
"changeType": "UPSERT",
"aspectName": "browsePathsV2",
"aspect": {
"json": {
"path": [
{
"id": "Folders"
},
{
"id": "Shared"
}
]
}
},
"systemMetadata": {
"lastObserved": 1586847600000,
"runId": "looker-test",
"lastRunId": "no-run-id-provided"
}
},
{
"proposedSnapshot": {
"com.linkedin.pegasus2avro.metadata.snapshot.DatasetSnapshot": {
Expand Down
1 change: 1 addition & 0 deletions metadata-ingestion/tests/integration/looker/test_looker.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ def setup_mock_look(mocked_client):
title="Outer Look",
description="I am not part of any Dashboard",
query_id="1",
folder=FolderBase(name="Shared", id="shared-folder-id"),
)
]

Expand Down
6 changes: 3 additions & 3 deletions metadata-ingestion/tests/integration/lookml/test_lookml.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ def test_lookml_git_info(pytestconfig, tmp_path, mock_time):
"parse_table_names_from_sql": True,
"project_name": "lkml_samples",
"model_pattern": {"deny": ["data2"]},
"github_info": {"repo": "datahub/looker-demo", "branch": "master"},
"git_info": {"repo": "datahub/looker-demo", "branch": "master"},
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This change is only to remove warnings when executing lookml tests.

"emit_reachable_views_only": False,
"process_refinements": False,
},
Expand Down Expand Up @@ -693,7 +693,7 @@ def test_hive_platform_drops_ids(pytestconfig, tmp_path, mock_time):
"parse_table_names_from_sql": True,
"project_name": "lkml_samples",
"model_pattern": {"deny": ["data2"]},
"github_info": {"repo": "datahub/looker-demo", "branch": "master"},
"git_info": {"repo": "datahub/looker-demo", "branch": "master"},
"emit_reachable_views_only": False,
"process_refinements": False,
},
Expand Down Expand Up @@ -791,7 +791,7 @@ def test_lookml_base_folder():

LookMLSourceConfig.parse_obj(
{
"github_info": {
"git_info": {
"repo": "acryldata/long-tail-companions-looker",
"deploy_key": "this-is-fake",
},
Expand Down
Loading