Salesforce Analytics Cloud Overview

analytics-cloud

This post provides an overview of the features and functionality of the Salesforce Analytics Cloud.

The Analytics Cloud, or Wave Analytics as it is also referred to, is a cloud-based business intelligence platform that enables the connection of disparate data sources to form interactive data views (or visualisations) that can be distributed via dashboards. A key concept here is empowerment of business users to deliver their own insights, in fact usability is often described as the defining feature – perhaps in addition to mobile access.

From a history perspective, during 2013 Salesforce acquired a cutting edge BI platform via the EdgeSpring acquisition. The EdgeSpring platform included the EdgeMart data storage service plus the Lens dynamic visualisation engine; both of which (one could safely assume) feature strongly in the Analytics Cloud architecture.

The first release of the Salesforce branded Wave Analytics took place at Dreamforce 2014, where the dynamic visualisation capabilities drew significant attention. The offer at this stage was expensive and complex in terms of licensing (Explorer and Builder user licenses plus platform setup fee/license), platform-led and focused on enterprise deployments. The perceived complexity and cost aspects particularly impacted negatively upon adoption. A second generation of Wave Analytics was launched at Dreamforce 2015, this time with a simplified license model and a focus on prebuilt analytics apps for Sales, Service and ultimately Marketing. The introduction of prebuilt Wave Apps offers two clear benefits; template-based, simplified deployment and tighter, cross-cloud integration (with Sales and Service Cloud predominantly). This latter point is key; end-users shouldn’t have to navigate consciously between distinct analytic and transactional views the two services should be seamlessly blended – this is the key differentiator Salesforce will be targeting to drive adoption.

The current set of prebuilt Wave Apps are listed below. There are also a growing number of 3rd party Wave Apps being developed on the Wave Analytics Platform; Financialforce (ERP Wave Apps; Accounting and Supply Chain) and Apptus (Quote-to-Cash Intelligence App) are notable examples.

Sales Wave Analytics App: A 9-step wizard captures parameters relating to segmentation, lead funnel and opportunity pipeline fields plus additional Sales Cloud related dimensions and measures; on completion an App is created with datasets populated via a number of auto-launched dataflows.

Service Wave Analytics App: As above with Service Cloud related dimensions and measures (7-step wizard).

Event Monitoring Wave App: Event log and setup audit trail datasets enable analysis of org and user behaviour.

Wave for B2B Marketing App: Consolidation of Sales Cloud and Pardot data to enable analysis of marketing impact on sales etc.

Key Concepts

Wave Assets – App: Analogous to a Folder an App contains a logical grouping of dashboards, lenses, and datasets. Apps can be Shared or Private.

wave-assets-app

Wave Assets – Dashboard: A dashboard is a composition of charts, metrics, and tables based on the data provided by one or many lenses.

wave-assets-dashboard

Wave Assets – Lens: A lens is a view on to the data provided by a dataset. The definition of a lens encapsulates both a query and visualisation for a specific analysis. A Lens can be clipped; this effect of this is to copy the Lens query to a Step within the most recently used dashboard.

wave-assets-lens

Wave Assets – Dataset: A dataset provides the source analytical data in a representation optimised for interactive visualisation. Data Sources can be Salesforce objects, uploaded files or partner connectors (Informatica, Jitterbit etc.). Fields added to a dataset are defined as date, dimension (qualitative) or measure (quantitative) type. Predicates can be added, with filter logic, that define record-level permissions which reflect Salesforce record ownership, management visibility or team/account collaboration.

wave-assets-dataset

Dataflow: A dataflow is a set of instructions (in JSON format) that specifies the data to extract and transform from Salesforce objects or datasets.

wave-dataflow

Visualisation: A single analytical representation of data (chart, tabular etc.) underpinned by a query.

Dimension: A dimension is a qualitative value such as Product or Region. Data analytics are primarily comprised of measures projected over multiple dimensions.

Measure: A measure is a quantitative value such as Price or Quantity. Mathematical operations can be applied to measures to calculate aggregates.

Architecture

The diagram below shows the main building blocks of a Wave Analytics App and the flow of data.

wave-analytics-architecture

Key Features

Cross-Dataset Faceting: Faceting enables steps to auto-filter in response to filters applied to a related step. Steps that share the same dataset facet by default, cross-dataset faceting can be defined directly in the dashboard designer.

Trend Wave Dashboards: Trended Datasets can be created from Salesforce reports. A snapshot of the report data is created each time the dataset is updated by the trend schedule. Each snapshot is limited to 100K rows.

Bulk Actions (Spring ’17): Table widgets can invoke a custom bulk action where the underlying SAQL query is passed to a designated Visualforce page. Apex page controller code can then execute the SAQL query (via the Wave Analytics API) and apply custom logic to results. This provides a flexible integration point, where analytics can be used to drive action such as campaign creation, email sending and so on – powerful stuff.

Smart Data Discovery (Spring ’17 tbc): This feature relates to the integration of BeyondCore (another Salesforce acquisition) into the Analytics Cloud UI. BeyondCore adds statistically significant insights such as unbiased answers, explanations and recommendations.

Analytics Home (Spring ’17): The new Analytics home page allows commonly used apps to be pinned, notification tracking is displayed with convenient links directly to the related dashboards. In new Wave orgs the Analytics tab can be accessed directly within the Salesforce UI, older orgs require a custom tab plus Visualforce container page.

Dashboard Annotations: Widgets within a dashboard can be enabled for collaboration via Annotations. This feature is natively integrated with Chatter; annotations will appear as Chatter posts and vice-versa. @Mentions are also supported.

Smart Notifications: Number type dashboard widgets can be configured for smart notifications; criteria is added to define the notification logic and a query scheduled defined. The notifications appear in the app, mobile app and are also sent via email.

Salesforce Integration Points

Lightning Experience: The Wave Dashboard component enables dashboards to be added to Lightning Home Pages, Record Pages and App Home Pages defined within the Lightning App Builder.

Salesforce Classic: Wave Analytics Assets appear listed in the palette of the Enhanced Page Layout editor and can be added directly to page layouts with context supplied via field mapping. The Visualforce component enables dashboards to be embedded and integrated at any entry point available to Visualforce (Custom tabs, links/buttons etc.). The component supports filtering to enable context to be set.

Communities users (Customer Community Plus and Customer Partner Community licenses) can view Wave Analytics Dashboard embedded in a Visualforce page.

References

Analyze Your Data – 700+ page PDF
Wave Analytics Platform Setup Guide
Wave Analytics Data Integration

Winter 14 Embedded Analytics

Super quick post on Embedded Analytics just in case this has passed anyone by and because it’s probably my favourite non-technical new feature for some time.

embedded_analytics_screenshot

In short, it is now possible to embed two charts (not reports) into a standard page layout (custom objects and standard objects), blurring the lines slightly between layouts and dashboards. The source report must be of the summary or matrix type and include a chart. Note the displayed analytics support manual refresh, but this is a limited resource (a users can refresh up to 100 report charts every 60 minutes, at the org-level this is 3,000 report charts every 60 minutes).

Hopefully the embedded analytics capability will be enhanced over future releases to remove the 2 chart limit and to support non-chart report outputs. A blended approach to the composition of layouts where dashboard components and standard page sections could be intermingled would be great – particularly if this supported dynamically resizing Visualforce page components. I can dream for now at least. In the meantime the Winter ’14 functionality covers a key functional area typically addressed through technical customisation or un-secure off-platform solutions using image formula fields (Google Charts anyone?). Standard functionality that directly removes the need to build such workarounds is a big positive.

Salesforce Analytics API

With Winter ’14 the new Analytics API turns GA. This RESTful style of API consumes standard API call limits, uses OAuth authentication and JSON request/response message formats (representations).

The key functionality of the Analytics API is the execution of reports (in synchronous or asynchronous modes), the application of dynamic filtering and the inspection of report metadata.

Note, in experimenting/testing any of the RESTful APIs (Force.com REST API, Chatter REST API, Analytics API etc.) the Apigee Salesforce API Consoles are an extremely convenient and useful tool – screenshot below.

apigee_screenshot

Core API Resources

– Report metadata (GET /services/data/v29.0/analytics/reports/report_ID/describe)

– List recently viewed reports (GET /services/data/v29.0/analytics/reports/list)
Note to obtain a full list of reports the standard REST API should be used to query the Report resource (via Soql).

– Synchronous report execution (/services/data/v29.0/analytics/reports/report_ID)
GET for a simple execution (add includeDetail=true to the Querystring if required)
POST to apply filtering.

– Asynchronous report execution (/services/data/v29.0/analytics/reports/report_ID/instances) – POST to request an execution.
GET to retrieve a list of the execution instances.
GET to the ../instances/instance_ID to request the results of a single execution.

– Fact Maps
The JSON message format for a report execution, synchronous or asynchronous, provides the detail and summary data in a Fact Map structure. In short, the keys provided in the structured groupings (across and down) data provided in the embedded report metadata are concatenated to provide a composite lookup key to detail row (hasDetailRows response flag indicates the existence of detail rows) and aggregate data held in the data map.

For more on Fact Maps refer to the “Decode the Fact Map” section in the Analytics API Reference.

Use Cases
The Analytics API is a long awaited key enabler for mobile/tablet analytics use cases, allowing on-platform reports to be executed and the results accessed in a constrained-device friendly lightweight format. Without this API mobile app developers have been limited to the execution of Soql queries via the standard REST API. With the API such developers have access to the recently viewed reports for a specific user, the report metadata, the ability to execute reports and then to pass the report results up to the graphics library of choice using a standard data format.

Outside of the mobile context, the API offers the same patterns to composite applications such as complementary web applications and 3rd party tools where datasets can be defined on-platform using reports (by end-users perhaps) and the data picked up for services such as mass email marketing etc.

Key Limitations
– 500 synchronous report executions per hour
– 1200 synchronous report execution requests per hour
– Asynchronous report results are available for 24 hours from execution

Report Response Example – Matrix Report

HTTP/1.1 200 OK
Sforce-Limit-Info:api-usage=21/5000000
Date:Sat, 28 Sep 2013 18:30:16 GMT
Content-Length:8705
Content-Type:application/json;charset=UTF-8

{
  "hasDetailRows": false,
  "attributes": {
    "describeUrl": "/services/data/v29.0/analytics/reports/00O300000041iFQEAX/describe",
    "instancesUrl": "/services/data/v29.0/analytics/reports/00O300000041iFQEAX/instances",
    "type": "Report",
    "reportId": "00O300000041iFQEAX",
    "reportName": "Example Report"
  },
  "groupingsDown": {
    "groupings": [
      {
        "value": "001Q000000PUcCtIAX",
        "key": "0",
        "groupings": [
          {
            "value": "2013-08-28",
            "key": "0_0",
            "groupings": [],
            "label": "2013/08/28 - 2013/09/03"
          }
        ],
        "label": "New Business"
      },
      {
        "value": "001Q000000Q0wLMIAX",
        "key": "1",
        "groupings": [
          {
            "value": "2013-09-18",
            "key": "1_0",
            "groupings": [],
            "label": "2013/09/18 - 2013/09/24"
          }
        ],
        "label": "Existing Business"
      },
      {
        "value": "001Q000000OwobqIAX",
        "key": "2",
        "groupings": [
          {
            "value": "2013-07-31",
            "key": "2_0",
            "groupings": [],
            "label": "2013/07/31 - 2013/08/06"
          }
        ],
        "label": "Prospects"
      }
    ]
  },
  "groupingsAcross": {
    "groupings": [
      {
        "value": "Product Sales",
        "key": "0",
        "groupings": [
          {
            "value": "a0AQ00000054Q0uMAX",
            "key": "0_0",
            "groupings": [],
            "label": "Product A"
          },
          {
            "value": "a0AQ0000004YV8xMAX",
            "key": "0_1",
            "groupings": [],
            "label": "Product B"
          }
        ],
        "label": "Product Sales"
      },
      {
        "value": "Services",
        "key": "1",
        "groupings": [
          {
            "value": "a0AQ0000005G0OpMAX",
            "key": "1_0",
            "groupings": [],
            "label": "Service A"
          }
        ],
        "label": "Services"
      }
    ]
  },
  "reportMetadata": {
    "name": "Example Report",
    "id": "00O300000041iFQEAX",
    "aggregates": [
      "RowCount"
    ],
    "groupingsDown": [
      {
        "name": "Client__c.Name",
        "sortOrder": "Asc",
        "dateGranularity": "None"
      },
      {
        "name": "Projection__c.Date__c",
        "sortOrder": "Asc",
        "dateGranularity": "Week"
      }
    ],
    "groupingsAcross": [
      {
        "name": "MyProduct__c.Classification__c",
        "sortOrder": "Asc",
        "dateGranularity": "None"
      },
      {
        "name": "MyProduct__c.Name",
        "sortOrder": "Asc",
        "dateGranularity": "None"
      }
    ],
    "reportType": {
      "type": "MyProduct_CRT__c",
      "label": "My Product CRT"
    },
    "reportBooleanFilter": null,
    "reportFilters": [],
    "detailColumns": [],
    "reportFormat": "MATRIX",
    "currency": null,
    "developerName": "Example_Report"
  },
  "factMap": {
    "1_0!T": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "0!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!T": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "0!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0!0_1": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "1!1": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "T!1": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "1!0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2_0!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2_0!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!0": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "2_0!0_0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "T!0": {
      "aggregates": [
        {
          "value": 7,
          "label": "7"
        }
      ]
    },
    "1_0!1_0": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "2_0!0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "2_0!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1_0!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "1_0!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "T!1_0": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "0!0": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "1_0!1": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "1_0!0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!0_1": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "2!0_0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "0_0!0_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!0_1": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "2!0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "T!T": {
      "aggregates": [
        {
          "value": 8,
          "label": "8"
        }
      ]
    },
    "0!T": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "1!T": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "2!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    },
    "0_0!T": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "T!0_0": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "1!1_0": {
      "aggregates": [
        {
          "value": 1,
          "label": "1"
        }
      ]
    },
    "T!0_1": {
      "aggregates": [
        {
          "value": 2,
          "label": "2"
        }
      ]
    },
    "2_0!T": {
      "aggregates": [
        {
          "value": 5,
          "label": "5"
        }
      ]
    },
    "0_0!1_0": {
      "aggregates": [
        {
          "value": 0,
          "label": "0"
        }
      ]
    }
  },
  "allData": true
}