Back to Datahub

Dashboard Entity

metadata-integration/java/docs/sdk-v2/dashboard-entity.md

1.5.0.317.0 KB
Original Source

Dashboard Entity

The Dashboard entity represents collections of visualizations and reports in BI tools (e.g., Looker, Tableau, PowerBI). This guide covers comprehensive dashboard operations in SDK V2.

Creating a Dashboard

Minimal Dashboard

Only tool and id are required:

java
Dashboard dashboard = Dashboard.builder()
    .tool("looker")
    .id("my_sales_dashboard")
    .build();

With Metadata

Add title and description at construction:

java
Dashboard dashboard = Dashboard.builder()
    .tool("tableau")
    .id("executive_dashboard")
    .title("Executive KPI Dashboard")
    .description("Real-time executive dashboard showing key business metrics")
    .build();

With Custom Properties

Include custom properties in builder:

java
Map<String, String> props = new HashMap<>();
props.put("team", "business-intelligence");
props.put("refresh_schedule", "hourly");

Dashboard dashboard = Dashboard.builder()
    .tool("powerbi")
    .id("sales_dashboard")
    .title("Sales Performance")
    .customProperties(props)
    .build();

URN Construction

Dashboard URNs follow the pattern:

urn:li:dashboard:({tool},{id})

Automatic URN creation:

java
Dashboard dashboard = Dashboard.builder()
    .tool("looker")
    .id("regional_sales")
    .build();

DashboardUrn urn = dashboard.getDashboardUrn();
// urn:li:dashboard:(looker,regional_sales)

Supported BI Tools

Common tool identifiers:

  • looker - Looker
  • tableau - Tableau
  • powerbi - Power BI
  • superset - Apache Superset
  • metabase - Metabase
  • redash - Redash
  • mode - Mode Analytics
  • quicksight - Amazon QuickSight
  • thoughtspot - ThoughtSpot

Tags

Adding Tags

java
// Simple tag name (auto-prefixed)
dashboard.addTag("executive");
// Creates: urn:li:tag:executive

// Full tag URN
dashboard.addTag("urn:li:tag:production");

Removing Tags

java
dashboard.removeTag("executive");
dashboard.removeTag("urn:li:tag:production");

Tag Chaining

java
dashboard.addTag("executive")
         .addTag("real-time")
         .addTag("kpi");

Owners

Adding Owners

java
import com.linkedin.common.OwnershipType;

// Business owner
dashboard.addOwner(
    "urn:li:corpuser:john_doe",
    OwnershipType.BUSINESS_OWNER
);

// Technical owner
dashboard.addOwner(
    "urn:li:corpuser:bi_team",
    OwnershipType.TECHNICAL_OWNER
);

// Data steward
dashboard.addOwner(
    "urn:li:corpuser:governance",
    OwnershipType.DATA_STEWARD
);

Removing Owners

java
dashboard.removeOwner("urn:li:corpuser:john_doe");

Owner Types

Available ownership types:

  • BUSINESS_OWNER - Business stakeholder
  • TECHNICAL_OWNER - Maintains the technical implementation
  • DATA_STEWARD - Manages data quality and compliance
  • DATAOWNER - Generic data owner
  • DEVELOPER - Software developer
  • PRODUCER - Dashboard producer/creator
  • CONSUMER - Dashboard consumer
  • STAKEHOLDER - Other stakeholder

Glossary Terms

Adding Terms

java
dashboard.addTerm("urn:li:glossaryTerm:ExecutiveMetrics");
dashboard.addTerm("urn:li:glossaryTerm:BusinessIntelligence");

Removing Terms

java
dashboard.removeTerm("urn:li:glossaryTerm:ExecutiveMetrics");

Term Chaining

java
dashboard.addTerm("urn:li:glossaryTerm:KeyPerformanceIndicator")
         .addTerm("urn:li:glossaryTerm:SalesMetrics")
         .addTerm("urn:li:glossaryTerm:RealTimeData");

Domain

Setting Domain

java
dashboard.setDomain("urn:li:domain:Sales");

Removing Domain

java
// Remove a specific domain
dashboard.removeDomain("urn:li:domain:Sales");

// Or clear all domains
dashboard.clearDomains();

Custom Properties

Adding Individual Properties

java
dashboard.addCustomProperty("team", "sales-operations");
dashboard.addCustomProperty("refresh_schedule", "hourly");
dashboard.addCustomProperty("data_source", "snowflake");

Setting All Properties

Replace all custom properties:

java
Map<String, String> properties = new HashMap<>();
properties.put("team", "business-intelligence");
properties.put("refresh_schedule", "real-time");
properties.put("access_level", "executive");

dashboard.setCustomProperties(properties);

Removing Properties

java
dashboard.removeCustomProperty("refresh_schedule");

Reading Dashboard Metadata

Get Title

java
String title = dashboard.getTitle();

Get Description

java
String description = dashboard.getDescription();

Lineage Operations

Dashboard lineage represents the data sources (datasets) that feed into the dashboard. This creates upstream lineage relationships from the dashboard to its source datasets.

Adding Input Datasets

Add datasets one at a time:

java
// Using DatasetUrn
DatasetUrn dataset = DatasetUrn.createFromString(
    "urn:li:dataset:(urn:li:dataPlatform:snowflake,sales.orders,PROD)"
);
dashboard.addInputDataset(dataset);

// Using string URN
dashboard.addInputDataset(
    "urn:li:dataset:(urn:li:dataPlatform:bigquery,marketing.campaigns,PROD)"
);

Setting Input Datasets

Replace all input datasets at once:

java
List<DatasetUrn> datasets = Arrays.asList(
    DatasetUrn.createFromString(
        "urn:li:dataset:(urn:li:dataPlatform:snowflake,sales.orders,PROD)"
    ),
    DatasetUrn.createFromString(
        "urn:li:dataset:(urn:li:dataPlatform:snowflake,sales.customers,PROD)"
    )
);

dashboard.setInputDatasets(datasets);

Removing Input Datasets

java
// Using DatasetUrn
DatasetUrn dataset = DatasetUrn.createFromString(
    "urn:li:dataset:(urn:li:dataPlatform:snowflake,sales.orders,PROD)"
);
dashboard.removeInputDataset(dataset);

// Using string URN
dashboard.removeInputDataset(
    "urn:li:dataset:(urn:li:dataPlatform:bigquery,marketing.campaigns,PROD)"
);

Getting Input Datasets

Retrieve all input datasets:

java
List<DatasetUrn> inputDatasets = dashboard.getInputDatasets();
for (DatasetUrn dataset : inputDatasets) {
    System.out.println("Dataset: " + dataset);
}

Lineage Chaining

java
dashboard.addInputDataset("urn:li:dataset:(urn:li:dataPlatform:snowflake,sales.orders,PROD)")
         .addInputDataset("urn:li:dataset:(urn:li:dataPlatform:snowflake,sales.customers,PROD)")
         .addInputDataset("urn:li:dataset:(urn:li:dataPlatform:salesforce,Account,PROD)");

Chart Relationships

Chart relationships represent the visualizations embedded in a dashboard. This creates "Contains" relationships between the dashboard and its charts.

Adding Charts

Add charts one at a time:

java
// Using ChartUrn
ChartUrn chart = new ChartUrn("tableau", "revenue_chart");
dashboard.addChart(chart);

// Using string URN
dashboard.addChart("urn:li:chart:(looker,sales_performance_chart)");

Setting Charts

Replace all charts at once:

java
List<ChartUrn> charts = Arrays.asList(
    new ChartUrn("tableau", "revenue_chart"),
    new ChartUrn("tableau", "customer_satisfaction_chart"),
    new ChartUrn("tableau", "regional_breakdown_chart")
);

dashboard.setCharts(charts);

Removing Charts

java
// Using ChartUrn
ChartUrn chart = new ChartUrn("tableau", "revenue_chart");
dashboard.removeChart(chart);

// Using string URN
dashboard.removeChart("urn:li:chart:(looker,sales_performance_chart)");

Getting Charts

Retrieve all charts:

java
List<ChartUrn> charts = dashboard.getCharts();
for (ChartUrn chart : charts) {
    System.out.println("Chart: " + chart);
}

Chart Chaining

java
dashboard.addChart(new ChartUrn("looker", "revenue_chart"))
         .addChart(new ChartUrn("looker", "customer_chart"))
         .addChart(new ChartUrn("looker", "product_chart"));

Dashboard-Specific Properties

Dashboard URL

Set a direct link to the dashboard in its native BI tool:

java
// Set dashboard URL
dashboard.setDashboardUrl("https://tableau.company.com/views/sales-dashboard");

// Get dashboard URL
String url = dashboard.getDashboardUrl();

Last Refreshed

Track when the dashboard data was last updated:

java
// Set last refreshed timestamp (milliseconds since epoch)
long currentTime = System.currentTimeMillis();
dashboard.setLastRefreshed(currentTime);

// Get last refreshed timestamp
Long lastRefreshed = dashboard.getLastRefreshed();
if (lastRefreshed != null) {
    System.out.println("Last refreshed at: " + new Date(lastRefreshed));
}

Combined Dashboard Properties

java
dashboard.setDashboardUrl("https://looker.company.com/dashboards/executive")
         .setLastRefreshed(System.currentTimeMillis());

Complete Example

java
import datahub.client.v2.DataHubClientV2;
import datahub.client.v2.entity.Dashboard;
import com.linkedin.common.OwnershipType;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

public class DashboardExample {
    public static void main(String[] args) {
        // Create client
        DataHubClientV2 client = DataHubClientV2.builder()
            .server("http://localhost:8080")
            .build();

        try {
            // Build dashboard with all metadata
            Dashboard dashboard = Dashboard.builder()
                .tool("looker")
                .id("sales_performance_dashboard")
                .title("Sales Performance Dashboard")
                .description("Executive dashboard showing key sales metrics and regional performance")
                .build();

            // Add tags
            dashboard.addTag("executive")
                     .addTag("sales")
                     .addTag("production");

            // Add owners
            dashboard.addOwner("urn:li:corpuser:sales_team", OwnershipType.BUSINESS_OWNER)
                     .addOwner("urn:li:corpuser:bi_team", OwnershipType.TECHNICAL_OWNER);

            // Add glossary terms
            dashboard.addTerm("urn:li:glossaryTerm:SalesMetrics")
                     .addTerm("urn:li:glossaryTerm:ExecutiveDashboard");

            // Set domain
            dashboard.setDomain("urn:li:domain:Sales");

            // Add custom properties
            dashboard.addCustomProperty("team", "sales-operations")
                     .addCustomProperty("refresh_schedule", "hourly")
                     .addCustomProperty("data_source", "snowflake");

            // Upsert to DataHub
            client.entities().upsert(dashboard);

            System.out.println("Successfully created dashboard: " + dashboard.getUrn());

        } catch (IOException | ExecutionException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Updating Existing Dashboards

Load and Modify

java
// Load existing dashboard
DashboardUrn urn = new DashboardUrn("looker", "my_dashboard");
Dashboard dashboard = client.entities().get(urn);

// Add new metadata (creates patches)
dashboard.addTag("new-tag")
         .addOwner("urn:li:corpuser:new_owner", OwnershipType.TECHNICAL_OWNER);

// Apply patches
client.entities().update(dashboard);

Incremental Updates

java
// Just add what you need
dashboard.addTag("real-time");
client.entities().update(dashboard);

// Later, add more
dashboard.addCustomProperty("updated_at", String.valueOf(System.currentTimeMillis()));
client.entities().update(dashboard);

Builder Options Reference

MethodRequiredDescription
tool(String)✅ YesBI tool identifier (e.g., "looker", "tableau")
id(String)✅ YesDashboard identifier within the tool
title(String)NoDashboard title
description(String)NoDashboard description
customProperties(Map)NoMap of custom key-value properties

Patch-Based Operations

Dashboard uses patch-based updates for metadata operations. All methods like addTag(), addOwner(), etc. create patches that are accumulated until upsert() or update() is called.

Benefits:

  • Efficient: Multiple operations batched into fewer API calls
  • Atomic: All changes succeed or fail together
  • Incremental: Only specified fields are modified, others remain unchanged

Example:

java
Dashboard dashboard = Dashboard.builder()
    .tool("tableau")
    .id("sales_dashboard")
    .build();

// These create patches (no API calls yet)
dashboard.addTag("production");
dashboard.addOwner("urn:li:corpuser:owner", OwnershipType.BUSINESS_OWNER);
dashboard.setDomain("urn:li:domain:Sales");

// Single API call emits all patches
client.entities().upsert(dashboard);

Common Patterns

Creating Multiple Dashboards

java
List<String> dashboardIds = Arrays.asList("dashboard1", "dashboard2", "dashboard3");

for (String dashboardId : dashboardIds) {
    Dashboard dashboard = Dashboard.builder()
        .tool("looker")
        .id(dashboardId)
        .title("Dashboard " + dashboardId)
        .build();

    dashboard.addTag("auto-generated")
             .addCustomProperty("created_by", "sync_job");

    client.entities().upsert(dashboard);
}

Batch Metadata Addition

java
Dashboard dashboard = Dashboard.builder()
    .tool("tableau")
    .id("executive_dashboard")
    .build();

List<String> tags = Arrays.asList("executive", "kpi", "real-time", "production");
tags.forEach(dashboard::addTag);

client.entities().upsert(dashboard);  // Emits all tags in one call

Conditional Metadata

java
if (isExecutiveDashboard(dashboard)) {
    dashboard.addTag("executive")
             .addTerm("urn:li:glossaryTerm:ExecutiveMetrics");
}

if (requiresGovernance(dashboard)) {
    dashboard.addOwner("urn:li:corpuser:governance_team", OwnershipType.DATA_STEWARD);
}

Dashboard with Full Lineage Context

java
// Create dashboard with rich metadata
Dashboard dashboard = Dashboard.builder()
    .tool("looker")
    .id("customer_360_dashboard")
    .title("Customer 360 Dashboard")
    .description("Comprehensive customer analytics dashboard")
    .build();

// Add business context
dashboard.addTerm("urn:li:glossaryTerm:CustomerAnalytics")
         .addTerm("urn:li:glossaryTerm:BusinessIntelligence")
         .setDomain("urn:li:domain:Customer");

// Add input datasets for lineage
dashboard.addInputDataset("urn:li:dataset:(urn:li:dataPlatform:snowflake,customer.profile,PROD)")
         .addInputDataset("urn:li:dataset:(urn:li:dataPlatform:salesforce,Account,PROD)")
         .addInputDataset("urn:li:dataset:(urn:li:dataPlatform:zendesk,Tickets,PROD)");

// Add embedded charts
dashboard.addChart(new ChartUrn("looker", "customer_segmentation_chart"))
         .addChart(new ChartUrn("looker", "lifetime_value_chart"))
         .addChart(new ChartUrn("looker", "support_tickets_chart"));

// Add operational metadata
dashboard.addCustomProperty("data_sources", "snowflake,salesforce,zendesk")
         .addCustomProperty("refresh_schedule", "every_15_minutes")
         .addCustomProperty("sla_tier", "tier1")
         .addCustomProperty("business_criticality", "high");

// Set dashboard properties
dashboard.setDashboardUrl("https://looker.company.com/dashboards/customer-360")
         .setLastRefreshed(System.currentTimeMillis());

// Add ownership and governance
dashboard.addOwner("urn:li:corpuser:product_team", OwnershipType.BUSINESS_OWNER)
         .addOwner("urn:li:corpuser:bi_team", OwnershipType.TECHNICAL_OWNER)
         .addTag("production")
         .addTag("customer-facing");

client.entities().upsert(dashboard);

Comparison with Chart Entity

Dashboard and Chart are similar but serve different purposes:

FeatureDashboardChart
PurposeCollection of visualizationsSingle visualization
URN Pattern(tool,id)(tool,id)
Patch Operations✅ Full support✅ Full support
Common Use CasesExecutive dashboards, reportsIndividual graphs, charts

Next Steps

Examples

Basic Dashboard Creation

java
{{ inline /metadata-integration/java/examples/src/main/java/io/datahubproject/examples/v2/DashboardCreateExample.java show_path_as_comment }}

Comprehensive Dashboard with Metadata

java
{{ inline /metadata-integration/java/examples/src/main/java/io/datahubproject/examples/v2/DashboardFullExample.java show_path_as_comment }}

Dashboard with Lineage and Relationships

java
{{ inline /metadata-integration/java/examples/src/main/java/io/datahubproject/examples/v2/DashboardLineageExample.java show_path_as_comment }}