羅希意, 霍曉陽, 傅洛伊
(上海交通大學 電子信息與電氣工程學院, 上海 200240)
在全世界范圍內,每年自然科學和社會科學領域都會產出數以百萬計的知識文獻,包括學術論文、科技報告和書籍等,并且呈爆發式速度增長.面對學術大數據[1]時代浩如煙海的學術資源,有效地檢索或查詢是一項極為重要的工作,因此,美國計算機協會(ACM)和美國電氣與電子工程師協會(IEEE)分別構建了論文的電子數據庫,一些互聯網科技企業如谷歌、微軟和百度等分別推出了各自的學術搜索系統,以幫助科技工作者查詢學術文獻.
作為國內學術搜索研究領域的代表,可視化學術搜索系統AceMap以可視化的方式呈現了學術大數據中各學科學術領域論文之間的引用關系、論文作者之間的合作關系和師從關系、世界范圍內各學術機構和個人發表論文的統計信息等.AceMap系統已經收錄約 1.2 億篇學術論文的相關信息,包括論文、作者、學術機構、學術期刊和會議等學術實體及其關系,其數據主要來源于微軟學術圖譜[2]、ACM和IEEE的公開數據庫.所用方法:利用實體關系模型對這些學術實體及其關系進行抽象分析,并通過關系型數據庫MySQL[3]來實現,生成的主要數據表為論文(Papers)、作者(Authors)、機構(Affiliations)、期刊(Journals)、會議(Conferences)、學術領域(Field of Study)、論文與作者及其機構的關系(Paper Author Affiliations)和論文引用關系(Paper References)等.這些數據表包含上億條的數據,依靠傳統的MySQL數據庫難以應對高并發的應用場景,而且需要滿足AceMap搜索系統的可視化學術關系分析和實時統計功能的要求,僅憑借基于全文檢索的搜索引擎技術還不夠,需要基于實體關系模型的結構化查詢語言(SQL)的查詢技術,因而需要尋求合適的查詢優化方法.
本文結合實際應用場景提出了基于窗口函數(Window Functions)[4]的查詢優化方法和基于分布式集群(SQL-on-Hadoop: SparkSQL)計算引擎[5-6]的查詢優化方法,通過提取一些典型、引起系統性能瓶頸的分析型SQL查詢實例,以傳統的關系型數據庫MySQL上的查詢執行時間為基準進行性能對比實驗,從而驗證所提出的查詢優化方法的有效性和正確性.
窗口函數查詢優化是在實體關系模型中尋求解決方案,旨在單節點關系型數據庫的框架下優化分析型SQL查詢.
窗口函數又稱為OLAP[7]函數或分析函數,屬于SQL:2003標準[8]的新增部分.它通過提取數據集合中指定分組的行并用于聚合、排名或分析,所涉及的SQL查詢主要面向各類聚合操作,常用的聚合函數包括數值求和函數(sum)、計數函數(count)、最小值函數(min)和最大值函數(max)等.窗口函數使用分區來代替傳統SQL查詢的分組操作,使其能夠在各個分組中進行多次聚合.其輸出包括基礎數據行和聚合結果,而分組操作只返回聚合結果.分區(Partitioning)、排序(Ordering)和分幀(Framing)是窗口函數的3個核心部分,它們構成了窗口函數在SQL查詢中的語義和語法,三者之間的邏輯關系見圖1[4].

圖1 窗口函數的3個概念Fig.1 Three concepts of window function
(1) 分區.分區是通過分區操作子句(Partition by)而實現的,是窗口函數的基礎.根據分區操作子句指定的數據表字段,將其中數值相同的數據行劃分到同一個分區,以便于后續的聚合計算,但分區是執行邏輯分區,這與分組操作的物理分區不同.例如,以AuthorID分區是將所有具有相同AuthorID的數據行劃分到同一個分區.
(2) 排序.排序是通過排序子句(Order by)而實現的,即將每一個分區中的數據行按照指定的數據表字段進行排序.
(3) 分幀.分幀建立在分區的基礎上,依賴于排序所確定的分區內數據行之間的順序,具有行數(Rows)和數值范圍(Range)兩種限定模式,用于在數據分區內部劃分局部的數據幀以供后續計算.
傳統的MySQL數據庫不支持窗口函數,因而需要將存儲學術大數據的數據庫遷移至支持SQL:2003標準的數據庫PostgreSQL 9.4[9]上.
本文以AceMap系統中常見的分析型SQL查詢(查詢作者論文的SCI引用數)為例來驗證基于窗口函數的查詢優化方法.該實例查詢涉及了一個大型的數據表PaperAuthorAffiliations,以及存儲論文、作者和機構的映射關系,包含 338 222 414 行數據記錄.傳統的SQL的查詢程序為[4]
select count(*), sum(SCICitation) as sum
from PaperSciReferencesCount as tb1
inner join (select PaperID from PaperAuthor
Affiliations where AuthorID=@AuthorID) as tb2
on tb1.PaperReferenceID=tb2.PaperID
group by AuthorID
采用基于窗口函數的查詢優化方法的SQL查詢程序為
select distinct count(*), sum(SCICitation)
over(partition by AuthorID) as sum
from PaperSciReferencesCount as tb1
inner join PaperAuthorAffiliations as tb2
on tb1.PaperReferenceID=tb2.PaperID
where AuthorID=@AuthorID
采用一臺配置為兩個中央處理器(因特爾至強系列,型號E5-2630)、內存128 GB的服務器對3個學術系統中的典型SQL查詢進行優化,并將查詢執行時間作為性能評價指標.以原SQL查詢在傳統的MySQL數據庫上的查詢執行時間作為基準,對比采用基于窗口函數的查詢優化方法的查詢執行時間.表1列出了3個學術系統性能對比實驗所涉及的SQL查詢的具體內容,其查詢執行時間的對比如圖2所示.可以看出,采用基于窗口函數的查詢優化方法能夠在一定程度上提升查詢性能,使其查詢執行時間減少 18.6%(SQL-3).
表1 窗口函數查詢優化的SQL查詢列表
Tab.1 The SQL queries of window function query optimization

SQL查詢編號SQL查詢描述SQL-1統計某一學者所有論文的SCI引用次數SQL-2統計學術合作次數,查找與某兩名學者合作次數最多的學者SQL-3查找引用了某一篇論文的所有論文,并輸出其中出現頻次最多的關鍵詞

圖2 窗口函數的查詢優化方法的結果Fig.2 Contrast results of window function query optimization
與基于窗口函數的查詢優化方法的單節點計算模式不同,基于SparkSQL計算引擎的查詢優化旨在分布式計算的框架下,借助于其多節點和多核的優勢進行SQL查詢,適用于大規模海量數據的應用場景.
Spark[10]是類似于Hadoop的分布式計算系統 MapReduce 的計算引擎[11],通過分布式計算框架對大規模數據進行快速處理和計算.SparkSQL計算引擎在Spark的生態系統中作為SQL-on-Hadoop[11-12]系統存在,它是在分布式集群上進行SQL查詢的技術平臺.但是,SQL查詢不依賴于關系型引擎,它通過SparkSQL自帶的編譯器對SQL語言進行解析和編譯并將其轉化為Spark作業,再通過Spark計算引擎在集群上實現的.
SparkSQL計算引擎需要分布式存儲系統對其進行支撐.本文選擇HDFS(Hadoop Distributed File System)[11]作為Spark的文件系統.將數據由MySQL數據庫遷移到HDFS上,即SparkSQL采用此分布式文件系統存取數據.
基于HDFS的文件系統中Spark支持多種數據格式,包括列式存儲(Parquet)[10]和文本等.依據Spark計算引擎的官方技術文檔[10],SparkSQL在列式存儲中的查詢執行速度(文本格式查詢執行速度的約10倍)最快,而且平均可以節省約75%的存儲空間,因此,本文選擇列式存儲作為SparkSQL的數據格式.
采用SparkSQL自帶Catalyst優化器[10]能夠實現對SQL查詢的優化,并最終生成能夠在Spark集群上執行的作業.
SparkSQL采用內存列存儲優化(In-Memory Columnar Storage)技術[13],能夠查詢一些頻繁出現的聚合,將其中包含的數據列存儲到集群的同一個節點上,使其能夠快速地被讀入內存,從而提高查詢速度.
參數優化是充分發揮Spark集群計算優勢以高效執行作業的關鍵.一個作業在Spark集群中的執行需要由位于Spark集群主節點中的Driver進程與若干個從節點中的Executor進程協同完成[10],兩者之間的關系如圖3所示.其中,Driver負責集群資源的分配,Executor負責具體任務的執行.

圖3 Driver進程與Executor進程的關系Fig.3 Relationship between driver and executor processes
本文對以下參數[10]進行優化:
(1) 參數SPARK_EXECUTOR_INSTANCES.表示Spark集群能夠同時啟動的Executor實例個數的上限值,其對硬件資源的利用效率具有影響.結合實驗條件,本文最終選擇其值為20,經測試達到較優的查詢性能.
(2) 參數SPARK_EXECUTOR_CORES.表示每個Executor能夠使用的中央處理器(CPU)核的數量,它影響Spark執行任務時的并行度.本文將其值設置為10,相應的能夠同時并行執行的任務數為20×10=200.
(3) 參數SPARK_EXECUTOR_MEMORY.表示分配給每一個Executor的內存數量,同一個 Executor 的所有CPU核共用.經實際測試,將其值設置為10 GB時的查詢性能較優.
實驗在一個含4個節點的Spark集群上進行,包括一個Master主節點,配置一個中央處理器(因特爾酷睿系列,型號i5-4590,主頻率 3.3 GHz),內存12 GB;3個Slave從節點,配置均為兩個中央處理器(因特爾至強系列,型號E5-2630),內存128 GB.
本文對3個學術系統中涉及大規模數據的復雜SQL查詢進行優化,并以查詢執行時間作為性能評價指標.以在傳統的MySQL上的SQL查詢執行時間為基準,對比通過Spark集群優化后的查詢執行時間.表2列出了實驗所涉及的SQL查詢的具體內容,其查詢執行時間如圖4所示.可以看出,基于SparkSQL的查詢優化方法能夠大幅提升查詢性能,使其查詢執行時間降低 93.9%(SQL-2),相當于查詢速度加快16倍.

表2 SparkSQL查詢優化的SQL查詢列表Tab.2 The SQL queries of SparkSQL query optimization

圖4 基于SparkSQL查詢優化方法的查詢執行時間Fig.4 Contrast experimental results of SparkSQL query optimization
本文針對傳統的關系型數據庫MySQL的查詢速度較低的問題,利用基于窗口函數的查詢優化方法和基于SparkSQL的查詢優化技術分別對各自適宜的應用場景進行優化.結果表明:在MySQL的框架下,對于分析型SQL的查詢,利用基于窗口函數的查詢優化方法能夠在一定程度上提高查詢速度;在分布式集群計算的框架下,針對海量數據和更為復雜的查詢操作,采用基于SparkSQL的查詢優化方法能夠大幅提高系統的查詢性能.