669 lines
17 KiB
Markdown
Raw Normal View History

# 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
| Method | Required | Description |
| ----------------------- | -------- | ---------------------------------------------- |
| `tool(String)` | ✅ Yes | BI tool identifier (e.g., "looker", "tableau") |
| `id(String)` | ✅ Yes | Dashboard identifier within the tool |
| `title(String)` | No | Dashboard title |
| `description(String)` | No | Dashboard description |
| `customProperties(Map)` | No | Map 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:
| Feature | Dashboard | Chart |
| ---------------- | ----------------------------- | ------------------------- |
| Purpose | Collection of visualizations | Single visualization |
| URN Pattern | `(tool,id)` | `(tool,id)` |
| Patch Operations | ✅ Full support | ✅ Full support |
| Common Use Cases | Executive dashboards, reports | Individual graphs, charts |
## Next Steps
- **[Chart Entity Guide](./chart-entity.md)** - Working with chart entities
- **[Dataset Entity Guide](./dataset-entity.md)** - Working with dataset entities
- **[Patch Operations](./patch-operations.md)** - Deep dive into patches
- **[Migration Guide](./migration-from-v1.md)** - Upgrading from V1
## 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 }}
```