目前大数据和Hadoop技术已历经十多年的发展,大数据和大数据分析受到前所未有的重视。Hadoop的最初版本仅支持批处理工作负载,现在Hadoop生态已具有处理结构化数据、流数据、事件处理、机器学习等工作负载以及处理图数据的工具。
尽管Hadoop生态中具有大量的工具,提供了完整的特性集,例如Hive、Impala, Pig、Storm和Mahout等。但Spark等新兴数据分析工具的出现,为处理多类型复杂工作提供了集成解决方案。
Azure 数据湖分析(简称ADLA)是一种新推出的大数据分析引擎。ADLA是由微软Azure cloud完全托管和提供的按需分析服务。ALDA与Azure 数据湖存储及HDInsight一并形成了微软基于云的数据湖和分析工具集。ADLA提供了一种新的大数据查询和处理语言,称为U-SQL。下面本文将介绍U-SQL语言,以及如何在应用中使用该语言。
Azure 数据湖是微软基于Azure公有云提供的数据湖工具集,其中包括多种服务,涉及数据存储、数据处理、数据分析,以及NoSQL存储、关系数据库、数据仓库和ETL工具等相关配套服务。
图1给出了微软在Azure Cloud上提供的各种云服务。
图1:Azure 数据湖提供的各种服务
图2给出了Azure云平台上提供的基于大数据和数据湖的应用架构。
图2:Azure上的典型大数据/数据湖/ETL/数据分析架构
U-SQL是Azure 数据湖分析提供的大数据查询和处理语言。 它是微软专为Azure 数据湖分析创建的一种新语言。U-SQL结合了类SQL的声明性语言与C#提供的包括丰富类型和表达式在内的编程功能,提供了为用户所熟知的大数据处理概念,例如“读取时模式”(Schema on Read)、“惰性计算”(Lazy Evaluation)、自定义处理器和Reducer等。熟悉Pig、Hive和Spark等开发的数据工程师会触类旁通。同时,具有C#和SQL知识的开发人员也会感觉U-SQL易于学习,并由此入手。
图3:U-SQL与C#、SQL间的相互关系
尽管U-SQL使用了SQL中的多个概念和关键词,但是它并非ANSI SQL兼容的。它定义了关键字EXTRACT and OUTPUT,增加了对非结构化文件的处理能力。
当前,ADLA和U-SQL仅支持批处理,并不支持流数据分析或事件分析。
图4给出了Visual Studio IDE中的U-SQL项目截图。
图4:Visual Studio中的U-SQL项目
图5:U-SQL脚本中的数据流
为支持在本地机器和笔记本电脑上使用U-SQL和Azure 数据湖,微软提供了类模拟器安装程序。开发环境需要下列组件:
图6:新建项目模板的截图
为构建首个U-SQL脚本,所使用的数据集是班加罗尔餐馆评分数据。原数据是CSV文件格式,其中各数据列定义如下:
下图中给出了部分示例数据。
图7:餐馆评级表中的部分示例数据
下面的脚本实现从CSV文件读取餐馆评分数据,并将同一数据写入到一个TSV文件中。该脚本中并未执行数据转换操作。
// 脚本:RestaurantScript.usql
// 从CSV文件抽取数据,存储到Rowset变量“employees”中。
@restaurant_ratings =
EXTRACT rest_id int,
name string,
address string,
online_order bool,
book_order bool,
rate double,
votes int,
phone string,
location string,
rest_type string,
favorite_dish_id int
FROM "/Samples/Data/restaurants_ratings.csv"
USING Extractors.Csv();
// 不执行数据转换:抽取的数据输出到一个TSV文件中。
OUTPUT @restaurant_ratings
TO "/output/restaurants_out.tsv"
USING Outputters.Tsv();
该脚本读取整个餐馆数据到Rowset变量,并以制表符分隔的格式写入到输出文件。
注意,上例中使用了字符串等C#数据类型,而非SQL中通常使用的char/varchar类型。其中不仅使用了C#的数据类型,而且利用了表达式及其它所有表述性编程语言的优点。
// 脚本:RestaurantScript.usql
// 定义输入、输出文件名和路径的变量。
DECLARE @inputFile = "/Samples/Data/restaurants_ratings.csv";
DECLARE @outputFile = "/output/restaurants_out.tsv";
// 数据从输入CSV文件中抽取,存储在Rowset变量employees中。
@restaurant_ratings =
EXTRACT rest_id int,
name string,
address string,
online_order bool,
book_order bool,
rate double,
votes int,
phone string,
location string,
rest_type string,
favorite_dish_id int
FROM @inputFile
USING Extractors.Csv(skipFirstNRows:1); // 跳过含有表头的第一行。
// 数据转换操作:重命名数据列,过滤掉行号数据。
@bestOnlineRestaurants =
SELECT name.ToUpper() AS Name, // 将餐馆名称转换为大写。
rate AS Rating,
online_order AS OnlineOrder,
phone AS Phone,
location AS Location,
rest_type AS Category,
favorite_dish_id AS FavoriteDishId
FROM @restaurants_rating
WHERE rate > 4 && online_order == true;
// 将经转换的数据写入输出文件。
OUTPUT @bestOnlineRestaurants
TO @outputFile
USING Outputters.Tsv(outputHeader:true); // 将列名或表头写入输出文件。
U-SQL支持C#语言编写的自定义表达式。C#代码形成独立于脚本的文件。注意,下图展示的.usql文件,具有关联的.usql.cs文件,存储相关的自定义C#代码。
图8:具有多个脚本和相关代码文件的U-SQL项目
// 相关C#代码文件:RestaurantScript.usql.cs
namespace UsqlApp1
{
public static class Helpers
{
public static string FormatRestaurantName(string name, string location, string restaurantType)
{
return name + " (" + restaurantType + ") - " + location;
// 注意:U-SQL尚不支持新的C# 7.0字符串操作。
// return $"{name} ( {restaurantType} ) - {location}";
}
}
}
// 脚本:RestaurantScript.usql
// 定义输入、输出文件名和路径的变量。
DECLARE @inputFile = "/Samples/Data/restaurants_ratings.csv";
DECLARE @outputFile = "/output/restaurants_out.tsv";
// 数据从输入CSV文件中抽取,存储在Rowset变量employees中。
@restaurant_ratings =
EXTRACT rest_id int,
name string,
address string,
online_order bool,
book_order bool,
rate double,
votes int,
phone string,
location string,
rest_type string,
favorite_dish_id int
FROM @inputFile
USING Extractors.Csv(skipFirstNRows:1); // 跳过含有表头的第一行。
// 数据转换过程:重命名数据列,滤掉行号。
@bestOnlineRestaurants =
SELECT USQLApp1.Helpers.FormatRestaurantName(name, location, rest_type) AS Name,
rate AS Rating,
online_order AS OnlineOrder,
phone AS Phone,
favorite_dish AS FavoriteDish
FROM @restaurant_ratings
WHERE rate > 4 && online_order == true;
// 将转换后的数据写入输出文件。
OUTPUT @bestOnlineRestaurants
TO @outputFile
USING Outputters.Tsv(outputHeader:true); // 将列名或表头写入输出文件。
U-SQL支持对两个不同数据集执行连接运算,可实现内连接、外连接、交叉连接等运算。
在下面的示例代码段中,执行了餐馆数据集和菜品食材数据集间的内连接运算。
// 脚本:RestaurantScript.usql
DECLARE @inputFile = "/Samples/Data/restaurants_ratings.csv";
DECLARE @outputFile = "/output/restaurants_out.tsv";
// 数据从输入CSV文件中抽取,存储在Rowset变量employees中。
@restaurant_ratings = // 代码同上,此处略。
// 数据转换过程:重命名数据列,过滤掉行号。
@bestOnlineRestaurants = // 代码同上,此处略。
现在,我们需要的是菜品及其中食材的数据。尽管这些数据通常可从外部数据源抽取,但在该代码中使用了内存中的Rowset变量。
// 定义内存中Rowset变量,存储菜品食材数据,包括菜品标识、菜品名称和食材。
@dish_ingredients =
SELECT
* FROM
(VALUES
(1, "Biryani", "Rice, Indian spices, Vegetables, Meat, Egg, Yoghurt, Dried Fruits"),
(2, "Masala Dosa", "rice, husked black gram, mustard seeds, fenugreek seeds, salt, vegetable oil, potatoes, onion, green chillies, curry leaves, turmeric"),
(3, "Cake", " sugar, butter, egg, cocoa, creme, salt")
) AS D(DishId, Dish, Ingredients);
// 在Rowset变量@bestOnlineRestaurants和@dish_ingredients间执行内连接运算。
@rs_innerJn = SELECT
r.Name,
r.Rating,
i.Dish,
i.Ingredients
FROM @bestOnlineRestaurants AS r
INNER JOIN @dish_ingredients AS i
ON r.FavoriteDishId == i.DishId;
// 结果写入输出文件中。
OUTPUT @rs_innerJn
TO @outputFile
USING Outputters.Tsv(outputHeader:true);
该代码返回高评分的餐馆和其最受欢迎菜品的食材清单。这是通过对餐馆数据和菜品食材Rowset数据间执行内连接运算得到的。
图9:具有多个脚本和相关代码文件的U-SQL项目
U-SQL提供了大量内建函数,包括聚合、分析函数、分级函数等。以下仅列出部分示例:
函数类型 | 示例 |
---|---|
聚合函数(Aggregate Functions) | AVG、SUM、COUNT、STDEV(标准偏差)、MIN、MAX等。 |
分析函数(Analytical Functions) | FIRST_VALUE、LAST_VALUE、LAG、LEAD、PERCENTILE_CONT等。 |
排名函数(Ranking Functions) | RANK、 DENSE_RANK、NTILE、 ROW_NUMBER等。 |
下面的示例脚本对餐馆数据集使用内建聚合函数,包括MIN、MAX、AVG和STDEV。
// 定义输入和输出文件的变量。
DECLARE @inputFile = "/Samples/Data/restaurants_raw_data.csv";
DECLARE @outputFile = "/output/restaurants_aggr.csv";
@restaurant_ratings =
EXTRACT rest_id int,
name string,
address string,
online_order bool,
book_order bool,
rate double,
votes int,
phone string,
location string,
rest_type string,
favorite_dish_id int
FROM @inputFile
USING Extractors.Csv(skipFirstNRows:1);
@output =
SELECT
rest_type AS RestaurantType,
MIN(rate) AS MinRating,
MAX(rate) AS MaxRating,
AVG(rate) AS AvgRating,
STDEV(rate) AS StdDevRating
FROM @restaurants_ratings
GROUP BY rest_type;
// 写入到输出文件。
OUTPUT @output
TO @outputFile
USING Outputters.Csv(outputHeader:true);
上面介绍主要关注的是如何从文件中读写非结构化和半结构化数据。当然,U-SQL的强大之处在于操作存储在文件中的非结构化数据,并对所抽取数据构建模式化视图,但是U-SQL同样可管理结构化数据。它提供了类似于Hive的通用元数据目录系统。下面列出了U-SQL支持的主要对象:
现在回到上面的餐馆评分示例。我们希望进一步分析那些低评分的餐馆。为实现此,我们需要抽取所有评分低于四级的餐馆到一张表中,以做进一步分析。
示例代码在数据库中创建了一个具有模式和索引键的U-SQL数据库。代码中并未指定创建的模式,因此类似于SQL Sever中的操作,数据库表创建使用的是数据库内置的缺省模式“dbo”。
下面给出创建数据库表的示例代码。
// 脚本:RestaurantScript.usql
DECLARE @inputFile = "/Samples/Data/restaurants_ratings.csv";
DECLARE @outputFile = "/output/restaurants_out.tsv";
// 数据从输入CSV文件中抽取,存储在Rowset变量employees中。
@restaurant_ratings = // 代码同上,在此略。
// 数据转换过程:过滤出所有评分低于4级的餐馆。
@lowRatedRestaurants =
SELECT rest_id AS RestaurantId,
name AS Name,
rate AS Rating,
online_order AS OnlineOrder,
phone AS Phone,
location AS Location,
rest_type AS Category,
favorite_dish_id AS FavoriteDishId
FROM @restaurants_ratings
WHERE rate < 4;
// 将低评分餐馆的详细数据插入到U-SQL目录中。
// 判断数据库是否存在。如不存在,则新建数据库。
CREATE DATABASE IF NOT EXISTS RestaurantsDW;
USE RestaurantsDW;
// 判定数据库表是否存在。如已存储,则删除。
DROP TABLE IF EXISTS dbo.LowRatedRestaurants;
// 指定列模式和索引,创建数据库表。
CREATE TABLE dbo.LowRatedRestaurants(
RestaurantId int,
Name string,
INDEX idx
CLUSTERED (Name DESC)
DISTRIBUTED BY HASH(Name),
Rating double,
OnlineOrder bool,
Phone string,
Location string,
Category string,
FavoriteDishId int
);
// 将Rowset数据插入到新建的U-SQL数据库表中。
INSERT INTO dbo.LowRatedRestaurants
SELECT * FROM @lowRatedRestaurants;
类似于数据库视图,U-SQL视图也不对数据做物理保存,只是对存储在数据库表或文件中的数据提供一种视图。视图可以基于数据库表,也可以基于文件的抽取数据。
下面的示例脚本展示了如何基于所抽取的数据创建视图。
USE DATABASE RestaurantsDW;
// 判断视图是否存在。如已存在,则删除。
DROP VIEW IF EXISTS RestaurantsView;
// 基于抽取数据创建视图。
CREATE VIEW RestaurantsView AS
EXTRACT rest_id int,
name string,
address string,
online_order bool,
book_order bool,
rate double,
votes int,
phone string,
location string,
rest_type string,
favorite_dish_id int
FROM "/Samples/Data/restaurants_raw_data.csv"
USING Extractors.Csv(skipFirstNRows:1); // 跳过包含有表头的第一行
视图操作代码如下:
@result = SELECT * FROM RestaurantsDW.dbo.RestaurantsView;
OUTPUT @result
TO "/output/Restaurants_View.csv"
USING Outputters.Csv();
U-SQL支持标量函数和表值函数(TVF)。函数可输入0到多个参数,返回单个标量值,或是一个数据库表,其为一个由列和行组成的数据集。
下面的示例代码片段首先展示了如何创建TVF,进而展示了如何调用该TVF函数。函数接收单个参数输入,返回一个数据库表。
CREATE DATABASE IF NOT EXISTS RestaurantsDW;
USE DATABASE RestaurantsDW;
DROP FUNCTION IF EXISTS tvf_SearchRestaurants;
// 创建TVF,输入参数是字符串类型的餐馆数据,返回包含匹配餐馆详细数据的数据库表。
CREATE FUNCTION tvf_SearchRestaurants(@RestaurantType string)
RETURNS @searchRestaurants TABLE(rest_id int, name string, address string,
online_order bool, book_order bool, rate double,
votes int, phone string, location string,
rest_type string, favorite_dish_id int)
AS
BEGIN
@allRestaurants =
EXTRACT rest_id int,
name string,
address string,
online_order bool,
book_order bool,
rate double,
votes int,
phone string,
location string,
rest_type string,
favorite_dish_id int
FROM "/Samples/Data/restaurants_raw_data.csv"
USING Extractors.Csv(skipFirstNRows:1); // 跳过包含有表头的第一行
@searchRestaurants =
SELECT *
FROM @allRestaurants
WHERE rest_type == @RestaurantType;
RETURN;
END;
调用该TVF,只需创建并传递“Bakery”参数。该TVF函数将返回所有类型为“Bakery”的餐馆。
OUTPUT RestaurantsDW.dbo.tvf_SearchRestaurants("Bakery")
TO "/output/BakeryRestaurants.csv"
USING Outputters.Csv();
下面给出一个研究实例,重点关注如何在一个已运作多年的大型数字转换战略计划中使用Azure 数据湖分析和U-SQL语言。实例的客户是一家大型保险专业机构,在过去一年中收购了多家保险公司和经纪商。因此,客户使用了多个客户系统,以电子邮件、文本短消息、Web、移动聊天和呼叫(入站和出站)等方式与其顾客交互。由于采用了多种折衷方案,分析客户交互数据是非常困难的。
由此,该客户考虑着手建立全渠道平台和整合的客服中心,希望通过多种联系渠道(包括电子邮件、文本、聊天机器人、联络中心语音呼叫等)为顾客提供服务。客户最直接的技术选择是去分析来自不同来源的数据,包括电子邮件,文本短信、聊天和通话记录等。
为解决如何对来自各系统不同格式数据分析的迫切需求,该研究实例中开发了一个基于Azure 数据湖的解决方案,将多源系统迁移到Azure 数据湖存储,进而使用Azure 数据湖分析和U-SQL进行分析。
图10:Azure Data Analytics流水线
Azure 数据湖存储和分析与Azure HDInsight和Azure Databricks一并,已成为执行大数据和分析工作负载的强大工具。尽管该服务集仍处于起步阶段,尚不支持流数据和事件处理功能,但新的U-SQL提供了强大的功能。U-SQL语言将SQL的简单性和普遍性与Mirosoft的旗舰产品,即强大的C#语言,结合在一起。此外,Microsoft的开发工具(例如Visual Studio)和本地开发/测试功能,支持U-SQL在大数据和分析领域具有强大的竞争力。
Aniruddha Chakrabarti 已在策略,咨询,产品开发和IT服务等领域深耕19年,在包括解决方案体系结构、售前、技术体系结构、交付领导力和计划管理等职能部门具有丰富的工作经验。作为Mphasis的数字化高级副总裁,Chakrabarti负责大型数字交易和计划的预售、解决方案、RFP/RFI和技术架构。在加入Mphasis之前,他曾在埃森哲、微软、Target、Misys和Cognizant担任过多种领导职务,以及围绕架构的多种职务。他的关注重点包括云、大数据及其分析、AI/ML、NLP、IoT、分布式系统、微服务和DevOps。
原文链接:
领取专属 10元无门槛券
私享最新 技术干货