Tableau Web Data Connector – Vad är det?

27 december 2015

I Stefans tidigare bloggpost om att visualisera sina likes på Facebook använde han sig av en Tableau Web Data Connector, WDC. I denna lite mer tekniska post ska vi ta en djupare titt på vad det är och kan användas till.

Bakgrunden till WDC:er är den trend som nu pågår där allt mer data publiceras och levereras i form av tjänster. Självklart vill vi kunna analysera den här informationen i Tableau. Men som ni kanske förstår är det omöjligt för Tableau att bygga färdiga kopplingar till alla dessa tjänster då de kan vara både externa och interna samt leverera data i ett oändligt antal olika format och strukturer. Det är här WDC:er kommer in i bilden och ger oss möjligheten att själva välja vilken tjänst och vilken data vi vill läsa och på ett hyfsat enkelt sätt själva koppla ihop dessa med Tableau.

Vi kommer även gå igenom en del verktyg och erfarenheter som kan vara bra att ha med sig innan man kör igång och skapar sin egen WDC.

Jag fortsätter nu like-jakten och exemplifierar genom att bygga en WDC för att läsa data från Instagram.

Tekniken bakom

I korthet är en WDC inget mer än en websida med logik byggd i javascript som fungerar som en brygga mellan den datakälla du vill läsa data ifrån och Tableau. För att förenkla för oss har Tableau här tagit fram ett paket innehållandes en debug-miljö i form av en html-sida samt ett javascript-bibliotek så att man inte behöver bygga allt från början utan på ett hyfsat enkelt sätt har kopplingen till Tableau.
I och med den utveckling som nu sker med t.ex. molnet och big data där allt mer data publiceras i form av tjänster som levererar data i form av javascript-formatet JSON passar det väldigt bra att med hjälp av javascript leverera data till Tableau. Dock är detta något som lämpar sig bäst för mindre analyser och inte som en ETL-ersättare, dvs att hämta och hantera data på runt 100.000 rader fungerar bra med bra responstider, mer än så kanske man ska tänka om.

De första stegen

Till att börja med behöver man sätta upp mallen för en connector enligt nedan och spara till en fil, t.ex. InstaConnect.html. Denna mall innehåller de delar som gör att man kan kommunicera med Tableau och skicka data. I steg två kommer vi lägga till delar för att prata med vår datakälla, i detta fall Instagram och sedan skicka denna data vidare till Tableau.

[code language=”html” firstline=”1″]
<html>
<meta http-equiv=”Cache-Control” content=”no-store” />
<head>
<title>Instagram connect</title>
<script src=”https://online.tableau.com/javascripts/api/tableauwdc-1.1.0.js” type=”text/javascript”></script>
<script type=”text/javascript”>
(function() {
var myConnector = tableau.makeConnector();

myConnector.getColumnHeaders = function() {
var fieldNames = [];
var fieldTypes = [];
tableau.headersCallback(fieldNames, fieldTypes);
}

myConnector.getTableData = function(lastRecordToken) {
var dataToReturn = [];
var lastRecordToken = 0;
var hasMoreData = false;
tableau.dataCallback(dataToReturn, lastRecordToken.toString(), hasMoreData);
}

tableau.registerConnector(myConnector);
})();
</script>
</head>
<body></body>
</html>
[/code]
Det första, och kanske viktigaste, i mallen är att skapa en referens till Tableau API. Detta ger oss tillgång till alla de funktioner som behövs för att kommunicera med Tableau.

[code language=”html” firstline=”5″]
<script src=”https://online.tableau.com/javascripts/api/tableauwdc-1.1.0.js” type=”text/javascript”></script>
[/code]

Det andra som händer är att skapa en referens till Tableau enligt kodsnutten nedan, detta gör att vi i Javascript har ett sätt att kommunicera med Tableau.

[code language=”javascript” firstline=”9″]
var myConnector = tableau.makeConnector();
[/code]

Som steg tre skapar man den funktion som gör det möjligt för Tableau att hämta definitionen på den datastruktur du vill analysera.

[code language=”javascript” firstline=”11″]
myConnector.getColumnHeaders = function() {
var fieldNames = [];
var fieldTypes = [];
tableau.headersCallback(fieldNames, fieldTypes);
}
[/code]

Fjärde komponenten är den funktion som levererar data till Tableau enligt den struktur som tidigare definierats i funktionen ovan. Det är även denna funktion som man behöver implementera paging i, dvs om den tjänsten du hämtar data ifrån levererar data i delar som Tableau behöver loopa och göra flera iterationer mot. I funktionsskelettet nedan kan man se att det avslutas med att kalla på ”dataCallBack”-funktionen i Tableau. Detta skulle jag kalla den viktigaste funktionen i Tableau API:t och tar som synes tre argument.

  1. dataToReturn – Ett JSON-objekt med alla datarader enligt tidigare definierat format.
  2. lastRecordToken – En sträng för att nästa iteration, loop, mot datakällan ska veta från vilken position den ska hämta data. Kan t.ex. vara ett datum eller en identifierare för nästa transaktion att hämta.
  3. hasMoreData – en boolean som berättar om vi är klara och tableau kan presentera resultatet till användaren eller om vi har fler loopar att utföra.

[code language=”javascript” firstline=”17″]
myConnector.getTableData = function(lastRecordToken) {
var dataToReturn = [];
var lastRecordToken = 0;
var hasMoreData = false;
tableau.dataCallback(dataToReturn, lastRecordToken.toString(), hasMoreData);
}
[/code]

Det femte och sista steget är att registrera vår connector tillbaka till Tableau så att den vet om den.

[code language=”javascript” firstline=”25″]
tableau.registerConnector(myConnector);
[/code]

Steg två – koppla upp sig mot en datakälla och returnera data

I detta steg kommer vi börja modifiera vår mall för att kommunicera med Tableau. Den färdiga connectorn kommer ni kunna hitta på länken som anges under länkar nedan. Så kommer i detta kapitel fokusera på att gå igenom de viktigaste punkterna, vissa saker som hur t.ex. själva Instagram-APIt fungerar kommer jag inte gå igenom utan kan läsas mer om på bifogade länkar.

Till att börja med kommer jag definiera strukturen på informationen som ska levereras tillbaka till Tableau efter att ha undersökt vad och vilken data jag är intresserad av att analysera. Nedan ses resultatet av detta där jag ersatt koden i skelettet med en funktion som skapar upp 6 kolumner med deras respektive datatyper. IMAGE_ID av typen string etc. Detta skickas sedan tillbaka till Tableau med headersCallback.

[code language=”javascript” firstline=”11″]
myConnector.getColumnHeaders = function () {
var fieldNames = [’IMAGE_ID’,’User name’, ’Image’, ’Likes’,’Liker’, ’Photo Date’];
var fieldTypes = [’string’, ’string’, ’string’, ’int’, ’string’, ’datetime’];
tableau.headersCallback(fieldNames, fieldTypes);
};
[/code]
Nästa steg är nu att börja läsa data och returnera till Tableau. Så nu modifierar vi skelettet och funktionen för getTableData enligt nedan.
Som steg 1 nedan kontrollerar jag att vi fått ett svar från Instagram. Sedan loopar vi igenom alla raderna från Instagram i steg 2 och lagrar dessa i den struktur vi vill ha det, dvs var entry = , dessa rader lägger vi sedan till i den lista, kallad toRet, med toRet.push(entry).
När vi loopat igenom alla resultat från Instagram kan vi sedan skicka vår färdiga lista till Tableau genom att köra funktionen tableau.dataCallback med toRet som ett argument tillsammans med numret till nästa transaktions id samt en true/false boolean om vi har fler bilder att hämta.

[code language=”javascript” firstline=”17″]
myConnector.getTableData = function (lastRecordToken) {
…. ….
// 1. Kontrollera om vi har ett svar från instagram
if (response.data) { var toRet = [];
// Loopa alla svar från instagram och skapa JSON objekt
for (var ii = 0; ii &amp;lt; response.data.length; ii++)
{
var entry = {
’IMAGE_ID’: response.data[ii].id,
’User name’: response.data[ii].user.username,
’Image’: response.data[ii].images.low_resolution.url,
’Likes’: response.data[ii].likes.count,
’Photo Date’: new Date(response.data[ii].created_time *
1000).toISOString();
};
toRet.push(entry);
}

var morePages = false;
var expiryDate = new Date();
expiryDate.setTime(
expiryDate.getTime() – (2*365 * 24 * 60 * 60 * 1000)
);

tableau.dataCallback(toRet, JSON.stringify( { ’max_id’: nextMaxId, ’pageNumber’: pageNumber }), morePages);
[/code]
Sedan har jag som kan ses i exemplet även lagt till mer kod för att hantera specifika funktioner i Instagram samt lite HTML för att snygga till connectorn.

Men med detta gjort kan man nu koppla upp sig med Tableau och testa! Observera att connectorn lika gärna kan publiceras lokalt på din dator som på en webbserver eller en Tableau server beroende på ditt case.

Dags att analysera!

Så med vår fil InstaConnect.html tillgänglig kan vi nu prova att koppla upp oss mot den nya connectorn.
Och efter att ha loggat in på Instagram läser nu Tableau datat från Instagram enligt det format som tidigare definierats i getColumnHeaders och tillgängliggör dessa.

Och med denna data kan jag nu konstatera att jag tyvärr är inne på en dåligtrend vad det gäller mina likes efter att ha haft en topp under sommaren.

Bra att ha redo innan man sätter igång

Först och främst gäller det att ha koll på det egna verktyget från Tableau, simulatorn, som ingår i startpaketet, den kan användas för att testa ifall den kod du skrivit kommer att fungera tillsammans med Tableau. Exempelvis kan man koppla upp sig mot den WDC som jag skapat enligt nedan.

Även om en WDC helt och hållet kan skrivas i notepad så finns det några verktyg som kan spara en hel del tid under utvecklingen. Finns säkert en hel del olika alternativ till nedan men då jag själv kommer från Microsoft-skolan valde jag Visual Studio som min utvecklingsmiljö, där man på ett enkelt sätt kan köra sin WDC, kör som ett webprojekt och lägg till HTML-sida, och sätta break-points för att se vad som händer bakom kulisserna.

För att lära känna den eller de datakällorna jag kopplar upp mig mot har jag använt ett tillägg till Google Chrome kallat Postman. Med detta verktyg kan man enkelt koppla upp sig och testa olika körningar mot webbtjänster för att se hur dataseten ser ut innan man börjar utveckla mot dem. I exemplet nedan testar jag att koppla upp mig med Postman mot Instagram och hämta hem de senaste posterna i min feed och som synes får jag ett svar från Instagram i form av ett JSON objekt med information om alla bilder i feeden.

Summering av WDC

För att summera skulle jag vilja säga att WDC är en bra ny funktion att ha med sig i verktygsbältet som passar perfekt för att snabbt komma åt data från tjänster och börja ”klämma och känna” på det i Tableau. Men är som jag tidigare nämnde inte en ersättare för ETL och ett bra datalager.
Det kan även vara en viss tröskel för BI-utvecklare då allt bygger på teknik som i vanliga fall främst används inom webbutveckling och inte klassisk BI. Men ny teknik är väl bara kul att lära sig!

Länkar

Tableau WDC
Chrome Postman
Microsoft Visual Studio
Den färdiga connectorn för Instagram
Instagram developer