Daten mit Microsoft Dallas anreichern

Seit einigen Monaten bietet Microsoft im Rahmen seiner Cloud Computing Strategie das Projekt Microsoft “Dallas” als CTP an; seit Mai 2010 ist das Projekt auch Bestandteil von Microsoft PinPoint.

Microsoft “Dallas” ist ein Service, über den auf freie und kommerzielle Daten unterschiedlichster Anbieter über eine einheitliche REST-basierende API zugegriffen werden kann. Der Zugriff auf die Daten kann dabei per Transaktion oder als Abonnement nach dem Motto “pay-as-you-grow” abgerechnet werden. Aktuell werden Daten von Namenhaften Anbietern wie der Nasa, National Geographic, Navteq, PitneyBowes oder undata – größtenteils noch kostenlos – angeboten.

Weitere Informationen zu Microsoft Dallas gibt es in einem Webcast auf Channel 9 sowie im Windows Azure Platform Training Kit.

REST-basierende API eignen sich recht gut, um sie direkt innerhalb der Integration Services anzusprechen. Auch mein Codeplex Projekt SSIS SMSTask nutzt z.B. für das versenden von SMS entsprechende API. Ein großer Vorteil des Projektes Microsoft “Dallas” ist die Bereitstellung einer Proxy Klasse zu jedem Datenanbieter. Hierdurch kann die Integration mit wenigen Zeilen Code begonnen werden.

ShowDataSetLogo Im folgenden Beispiel zeige ich, wie man Daten aus der AdventureWorks Datenbank um zusätzlichen Informationen des Anbieters “Weather Central Global Forecast and Data Services ” anreichern kann.

 

 

Für die Demo benötigt man einen Zugang zu Microsoft “Dallas”, den man sich bei einer vorhandenen Windows Live ID sehr schnell kostenlos anlegen kann. Als Grundlage für die Daten verwende ich die AdventureWorks2008 Datenbank, in der bereits Geodaten vorhanden sind.

Da für die Anfrage an den Service keine Geography-Instanz verwendet werden kann, sondern die Daten einzeln als Längen- und Breitengrade übergeben werden müssen, werden diese Eigenschaften in der Quelle mit abgefragt (Zeile 7/8).

   1: SELECT TOP 1000 [AddressID]

   2:       ,[AddressLine1]

   3:       ,[AddressLine2]

   4:       ,[City]

   5:       ,[StateProvinceID]

   6:       ,[PostalCode]

   7:       ,SpatialLocation.Long AS Long

   8:       ,SpatialLocation.Lat AS Lat

   9:       ,[rowguid]

  10:       ,[ModifiedDate]

  11:   FROM [AdventureWorks2008].[Person].[Address]

Die Daten laufen aus der Quelle direkt in die Script Component. Aus dem Datenfluss werden die Spalten Latitude und Longitude als Eingangsspalten definiert, zusätzlich werden die 4 neuen Ausgabespalten  Time, Temperature, FeelsLike und RelativeHumidity angelegt.

Da die oben bereits angesprochene Proxy Klasse Referenzen zu System.Data.Linq sowie System.XML.Linq verwendet, muss innerhalb der Script Component Projektmappe im Visual Studio als erstes das .Net Framework von 2.0 auf 3.5 umgestellt werden. Danach werden die beiden entsprechenden Referenzen gesetzt und die zuvor heruntergeladene Proxy Klasse der Projektmappe hinzugefügt.

image image

Im Script unten füge ich nur jeweils die erste Zeile aus dem zurückgelieferten Dataset den Daten im Datenfluss an. In Zeile 11 und 12 Kürze ich zusätzlich die Geodaten aus der AdventureWorks Datenbank auf 5 Zeichen, da der Wetter-Dienst bei den genauen Daten leider zu häufig keine Treffer zurückgibt. 

   1: public override void Input0_ProcessInputRow(Input0Buffer Row)

   2:     {

   3:         string accountKey = "--- YOUR ACCOUNTKEY ---";

   4:         System.Guid uniqueUserID = new Guid("--- YOUR UNIQUE USERID ---");

   5:         DailyForecastService Weather = new DailyForecastService(accountKey, uniqueUserID);

   6:         if (!Row.Long_IsNull && !Row.Lat_IsNull)

   7:         {

   8:             try

   9:             {

  10:                 List<DailyForecastItem> dfc = Weather.Invoke(Row.Lat.ToString().Substring(0, 5)

  11:                     , Row.Long.ToString().Substring(0, 5), null, "metric");

  12:                 Row.RelativeHumidity = dfc[0].RelativeHumidityMax;

  13:                 Row.Temperature = dfc[0].RelativeHumidityMax;

  14:                 Row.Time = dfc[0].Start;

  15:                 Row.FeelsLike = dfc[0].FeelsLikeMax;

  16:             }

  17:             catch (Exception ex)

  18:             {

  19:                 ComponentMetaData.FireWarning(0, "Weather Central", "Invalid coordinates: ("

  20:                     + Row.Lat.ToString() + " " + Row.Long.ToString() + ")", null, 0);

  21:             }

  22:         }

  23:     }

Liefern Anfragen an den Service einen Fehler zurück, so führe ich das hier auf die Geokoordinaten zurück und gebe eine entsprechende Warnung mit der betreffenden Geokoordinate aus (Zeile 20).

image 
Um nun sämtliche zurückgelieferten Daten zu verwenden, also auch wirkliche Vorraussagen meinem Datenfluss hinzuzufügen, füge ich der Script Component noch einen weiteren OutputBuffer “WeatherOutput” hinzu. Dieser bekommt zusätzlich zu den oben genannten 4 Spalten noch die AdressID der Originaldaten, um so später wieder eine vernünftige Zuordnung herstellen zu können. Im Standard OutputBuffer lösche ich wieder die zuvor hinzugefügten Spalten.

 

image

 image

   1: public override void Input0_ProcessInputRow(Input0Buffer Row)

   2:     {

   3:         string accountKey = "--- YOUR ACCOUNTKEY ---";

   4:         System.Guid uniqueUserID = new Guid("--- YOUR UNIQUE USERID ---");

   5:         DailyForecastService Weather = new DailyForecastService(accountKey, uniqueUserID);

   6:         if (!Row.Long_IsNull && !Row.Lat_IsNull)

   7:         {

   8:             try

   9:             {

  10:                 List<DailyForecastItem> dfc = Weather.Invoke(Row.Lat.ToString().Substring(0, 5)

  11:                     , Row.Long.ToString().Substring(0, 5), null, "metric");

  12:                 foreach (DailyForecastItem item in dfc)

  13:                 {

  14:                     WeatherOutputBuffer.AddRow();

  15:                     WeatherOutputBuffer.AddresID = Row.AddressID;

  16:                     WeatherOutputBuffer.RelativeHumidity = item.RelativeHumidityMax;

  17:                     WeatherOutputBuffer.Temperature = item.RelativeHumidityMax;

  18:                     WeatherOutputBuffer.Time = item.Start;

  19:                     WeatherOutputBuffer.FeelsLike = item.FeelsLikeMax;

  20:                 }

  21:  

  22:             }

  23:             catch (Exception ex)

  24:             {

  25:                 ComponentMetaData.FireWarning(0, "Weather Central", "Invalid coordinates: (" 

  26:                     + Row.Lat.ToString() + " " + Row.Long.ToString() + ")", null, 0);

  27:             }

  28:         }

  29:     }

image

Zugegebener Maßen liegen die Ansatzpunkte, Daten mit Wetterdaten anzureichern, nicht wirklich auf der Hand. Aber das Beispiel zeigt sehr gut, wie einfach es ist, Daten mit Microsoft “Dallas” und den gegebenen Proxy Klassen um zusätzliche Informationen anzureichern.