楊亞飛 湯軍 宋樹華 陳建美 李功權(quán)
摘 要:文章針對空間大數(shù)據(jù)的處理框架SpatialHadoop作了系統(tǒng)性的研究。鑒于其在空間大數(shù)據(jù)實際應(yīng)用中所存在的無法實現(xiàn)圖屬關(guān)聯(lián)以及大多數(shù)空間分析空間分析不支持的問題對其做了一定程度上的擴(kuò)展,首先為SpatialHadoop的默認(rèn)數(shù)據(jù)類型添加了唯一的標(biāo)識,并以此為基礎(chǔ)關(guān)聯(lián)了空間對象的屬性信息。其次還增加了SpatialHadoop對其他類型數(shù)據(jù)的解析功能,最后擴(kuò)展了空間操作對屬性信息的支持。擴(kuò)展后的SpatialHadoop將基本支持現(xiàn)有空間數(shù)據(jù)所常用的功能。
關(guān)鍵詞:SpatialHadoop;數(shù)據(jù)類型;空間索引;空間操作;空間數(shù)據(jù)
Hadoop孕育自對海量數(shù)據(jù)的分布式存儲和并行處理的應(yīng)用,但因為針對的領(lǐng)域不同,其在對空間數(shù)據(jù)的支持設(shè)計上存在著明顯的不足之處,它的核心框架不能對空間數(shù)據(jù)的空間特性做良好的支持?,F(xiàn)有基于Hadoop的空間數(shù)據(jù)應(yīng)用主要集中在特定的數(shù)據(jù)類型(如軌道的范圍查詢)和數(shù)據(jù)操作(如點集的最鄰近查詢)方面[1],SpatialHadoop應(yīng)運而生。
SpatialHadoop是第一個基于MapReduce計算框架的空間大數(shù)據(jù)處理框架,它對空間數(shù)據(jù)具有原生支持的特性[1]。
對于空間數(shù)據(jù)而言,位置和屬性都不可或缺。然而,SpatialHadoop的核心框架并沒有考慮空間對象的屬性信息,純粹的位置信息也不利于對空間數(shù)據(jù)進(jìn)行復(fù)雜的空間分析。為了契合實際應(yīng)用,必須對現(xiàn)有SpatialHadoop框架作必要的擴(kuò)展。
1 空間大數(shù)據(jù)框架
1.1 SpatialHadoop簡介
SpatialHadoop對Hadoop做了全面的擴(kuò)展[2],使其核心功能可以支持空間數(shù)據(jù)[1]。SpatialHadoop擴(kuò)展了高級語言Pig Latin并取名為Pigon,不僅保留了Pig Latin的原本特性,同時還增加了支持空間數(shù)據(jù)的特性。不僅如此,SpatialHadoop還在框架中增加了兩級空間索引結(jié)構(gòu)[1-4],較大程度地提高了處理空間數(shù)據(jù)的效率。另外,SpatialHadoop基于MapReduce框架還開發(fā)集成了兩種基本空間組件和一系列的空間操作[2-4],大大簡化了空間大數(shù)據(jù)應(yīng)用的開發(fā)工作[5]。
1.2 SpatialHadoop的基本功能
SpatialHadoop集群擴(kuò)展自Hadoop集群,它和Hadoop集群一樣都是擁有一個主節(jié)點和多個從節(jié)點的結(jié)構(gòu),主節(jié)點用來接收用戶的查詢請求,并將請求的任務(wù)(Map/Reduce任務(wù))分割為較小的任務(wù),這些小的任務(wù)將分配給不同的從節(jié)點來執(zhí)行[1-2,4]。
SaptialHadoop在分布式文件系統(tǒng)(Hadoop Distributed File System,HDFS)堆文件的基礎(chǔ)上增加了空間索引,通過增加索引克服了Hadoop僅支持無索引的堆文件的限制[1]。并將其組織成兩級空間索引結(jié)構(gòu),即全局索引和本地索引[1-4]。
全局索引保存在主節(jié)點的內(nèi)存中,而每一個本地索引都存儲在從節(jié)點的文件塊中[1-4]。將索引組織成全局和本地兩個層次是因為這樣的分離模式符合MapReduce的編碼范式[4]。全局索引用于準(zhǔn)備MapReduce工作,而本地索引用于處理Map任務(wù)[2]。
空間索引都在Hadoop的HDFS中得以實現(xiàn),這樣可以高效的訪問存儲在HDFS中的空間數(shù)據(jù),而不僅僅是讓數(shù)據(jù)成為堆在Hadoop中的文件[2-3]。對于空間信息而言,增加時間維度的信息具有重要的意義,在SpatialHadoop中可以通過在存儲層增加時空索引信息來實現(xiàn),分片時將考慮空間和時間兩種要素[2,4]。
SpatialHadoop為空間數(shù)據(jù)集建立了一套空間索引機制,那么在空間數(shù)據(jù)的處理和操作時怎樣獲取這些索引。為此SpatialHadoop在MapReduce層新增了兩個新的組件,SpatialFileSplitter和SpatialRecordReader[1-4],可以通過這兩個組件獲取空間數(shù)據(jù)建立的索引。
空間索引的建立以及MapReduce層新增的組件保證了SpatialHadoop可以實現(xiàn)高效的空間操作功能。SpatialHadoop實現(xiàn)了3種基本的空間操作,分別是范圍查詢、最鄰近點查詢和空間連接操作[3]。SpatialHadoop還調(diào)用CG_Hadoop計算幾何庫函數(shù)實現(xiàn)了計算幾何操作[4,7]。
SpatialHadoop并沒像HiveQL和Pig Latin等語言一樣從底層開發(fā)一種新的空間開發(fā)語言[2,5]。它在Pig Latin的基礎(chǔ)上進(jìn)行了空間方面的擴(kuò)展,增加了對空間數(shù)據(jù)類型、空間基礎(chǔ)功能以及空間操作的支持,并且遵循OGC的標(biāo)準(zhǔn)[5]。這樣不僅使其保留了Pig Latin語言的原始功能,同時也加入了空間結(jié)構(gòu)。由于Pig Latin不允許定義新的數(shù)據(jù)類型,所以Pigon重寫了ByteArray數(shù)據(jù)類型,以此來定義新的空間數(shù)據(jù)類型。Pigon還支持OGC標(biāo)準(zhǔn)的空間謂詞[3,5]。
1.3 SpatialHadoop的優(yōu)勢
SpatialHadoop修改了Hadoop的核心處理框架,使其更加適合處理空間數(shù)據(jù),Hadoop和SpatialHadoop的處理邏輯對比如圖1所示。
可以看到Hadoop和SpatialHadoop的處理方式是有區(qū)別的。
(1)Hadoop MapReduce層設(shè)計的目的是為了處理不帶索引的堆文件。而SpatialHadoop中的空間操作是以帶空間索引的文件為輸入的。
(2)在任務(wù)分割過程中,SpatialHadoop增加了一個過濾函數(shù)可以過濾不需要處理的數(shù)據(jù),從而減少map操作的任務(wù)量,以增加處理速率。
(3)Hadoop的map處理的是鍵值對的數(shù)據(jù),而SpatialHadoop直接處理的則是小任務(wù)的本地索引文件。此外,SpatialHadoop的一些空間操作,如空間連接等,是對二元操作,需要兩個輸入文件作為輸入條件,而Hadoop并不具備這樣的能力。
2 擴(kuò)展空間數(shù)據(jù)類型并關(guān)聯(lián)屬性信息
SpatialHadoop存儲的數(shù)據(jù)類型主要包含3種空間數(shù)據(jù)類型,即點、矩形和多邊形,默認(rèn)每種數(shù)據(jù)類型的數(shù)據(jù)僅僅存儲它們的空間信息,不包含任何其他額外的信息,所有類型都是二維的歐幾里得空間圖形[8]。
默認(rèn)情況下點類型(Point)數(shù)據(jù)以二維的空間點位(x,y)來表示。矩形(rectangle)以一對角點來表示的,一個是矩形左下角的那個拐角點,另一個是矩形右上角的那個拐角點。多邊形則以一系列的二維點來表示。
文本格式是SpatialHadoop中各類型空間數(shù)據(jù)的主要存儲格式,這將方便我們導(dǎo)入或?qū)С銎渌麘?yīng)用格式的文件。標(biāo)準(zhǔn)的格式是CVS格式,每條記錄都將存儲為一行。
純坐標(biāo)信息解決不了屬性缺失的問題,在SpatialHadoop中不需要記錄存儲文件的大小,因為他們都是標(biāo)準(zhǔn)的塊大小。SpatialHadoop也不需要記錄文件中不同空間對象的記錄條數(shù),因為塊夠小,對于并行計算的大數(shù)據(jù)來說遍歷就是最快的算法。而SpatialHadoop的空間數(shù)據(jù)類型又極具標(biāo)識性,自然而然也就不需要有對象類型的標(biāo)識。因此,只需要SpatialHadoop中的空間對象增加一個唯一標(biāo)識的ID,就可以解決關(guān)聯(lián)空間對象的屬性信息問題。
在Spatialhadoop中定義自己的數(shù)據(jù)類型,需要自己定義一個新的類并且實現(xiàn)shap接口。方便起見,直接擴(kuò)展現(xiàn)有的標(biāo)準(zhǔn)數(shù)據(jù)類型來實現(xiàn)自定義的數(shù)據(jù)類型,這樣就可以不用從頭開始編寫了。
文章定義了3個繼承自默認(rèn)數(shù)據(jù)類型的新類并為其添加ID字段,當(dāng)然,僅僅這樣還不夠,這3個類的對象必須能夠被序列化,讀取數(shù)據(jù)時要能識別這些數(shù)據(jù)類型,還要為新類型重寫clone方法。
利用Hadoop的Hbase來存儲空間對象的屬性信息,因為需要關(guān)聯(lián)空間數(shù)據(jù)所以Hbase中的屬性表必須有一個和空間數(shù)據(jù)中的ID標(biāo)識一一對應(yīng)的屬性,Hbase的Row Key就是一個不錯的選擇。這樣在Spatialhadoop中就為空間對象的實體信息和屬性信息建立了聯(lián)系。
3 不同類型的空間數(shù)據(jù)的解析
對于SpatialHadoop默認(rèn)的文本存儲格式而言,解析不同類型的數(shù)據(jù)其實只需要解析出不同格式的空間坐標(biāo)即可。但是對于擴(kuò)展后的數(shù)據(jù)類型而言,就不是這么簡單了,首先每個空間對象都需要生成一個唯一標(biāo)識的ID,然后將對象關(guān)聯(lián)的屬性信息導(dǎo)入到HBase中并關(guān)聯(lián)。另外,還有一個至關(guān)重要的問題,就是目前大多數(shù)空間數(shù)據(jù)的存儲格式都將空間對象劃分為點、線、面,這樣就存在一個問題,線類型數(shù)據(jù)在SpatialHadoop中到底應(yīng)該解析成什么類型的空間對象呢?很顯然,答案只能是矩形。
無論是二進(jìn)制文件還是如xml的文本文件,Java都有提供解析此類文件的庫函數(shù),如果知道文件的組織形式,解析起來就比較方便了。下面以ESRI的Shapefile文件類型舉例說明。
ESRI的Shapefile文件支持14種幾何類型,每種類型數(shù)據(jù)都用一個數(shù)字來標(biāo)識,1代表點狀類型數(shù)據(jù),3代表線狀類型數(shù)據(jù),5代表面面狀類型數(shù)據(jù),而標(biāo)識幾何類型的位置在shp文件的自起始位置0開始計數(shù)的第32個字節(jié)位置上,在第24個字節(jié)處記錄了文件的長度。從36到68這個區(qū)段還記錄了整個文件數(shù)據(jù)的最小點和最大點信息,可以據(jù)此提取出該文件的最小外包矩形[9]。
接下來就是解析實體信息的內(nèi)容了,空間實體對象在shp文件中用記錄段來存儲,記錄段包含記錄頭部和記錄內(nèi)容兩部分的內(nèi)容,記錄頭部包含記錄號和坐標(biāo)記錄長度,記錄內(nèi)容包括幾何類型和坐標(biāo)內(nèi)容。默認(rèn)情況下只需要把坐標(biāo)信息提取出來就可以了。擴(kuò)展后則需要為每條記錄生成一個ID。
最后就是提取屬性信息了,和實體信息關(guān)聯(lián)的HBase表的表名需要和存儲實體信息的文本文件名稱相同。由于shp文件中的空間對象和dbf中的記錄順序是一一對應(yīng)的,所以提取屬性信息就簡單得多,因為ID號是順序生成的,所以提取屬性信息時只需要知道首個ID號,之后只需順序讀寫屬性信息即可。
4 空間索引
空間索引是為了提高在空間數(shù)據(jù)集中查找或處理某個圖形對象的效率,不同于在一臺機器上建立索引,對于分布式存儲必然涉及兩種層次索引結(jié)構(gòu),一個是在集群中搜索數(shù)據(jù)存儲的節(jié)點位置,另一個則是在本地搜索數(shù)據(jù)所在的塊。這就需要在SpatialHadoop的主節(jié)點和從節(jié)點上分別建立空間索引文件。
4.1 索引布局
SpatialHadoop為空間數(shù)據(jù)集建立了全局和本地兩種層次的索引。每一個空間數(shù)據(jù)文件的索引都會包含一個存儲在主節(jié)點的內(nèi)存中的全局索引存文件,而分片的數(shù)據(jù)將存儲在本地索引文件中。
SpatialHadoop包含多種空間索引技術(shù),最常用的是網(wǎng)格索引、R樹和R+樹索引,網(wǎng)格文件一般只適合用于均勻分布的空間數(shù)據(jù),而R樹和R+樹則偏向用于傾斜的空間數(shù)據(jù),即空間分布不均勻的空間數(shù)據(jù)[1,3-4]。
SpatialHadoop創(chuàng)建索引的過程(見圖2):(1)用戶通過命令或者應(yīng)用發(fā)出建立索引請求。(2)主節(jié)點讀取空間數(shù)據(jù)的元數(shù)據(jù)信息,并為從節(jié)點分配建立索引的任務(wù)。(3)從節(jié)點構(gòu)建空間數(shù)據(jù)的本地索引,并以塊的形式存儲在從節(jié)點上。(4)將所有本地索引的元數(shù)據(jù)信息組織起來存儲到主節(jié)點的內(nèi)存中。
那么,SpatialHadoop中全局索引和本地索引具體是如何建立的呢?建立索引大致可分為3個部分,分片、建立本地索引和建立全局索引,下面首先來介紹一下SpatialHadoop提供的分片技術(shù),它是建立索引的必要技術(shù)。
4.2 空間分片
空間分片類似于Hadoop的分塊策略,需要分片的原因在于一個數(shù)據(jù)塊不能滿足存儲所有空間數(shù)據(jù)的需求,另外,并行計算也需要為數(shù)據(jù)集進(jìn)行必要的分割??臻g數(shù)據(jù)的分片策略不同于文件,分片的基礎(chǔ)是空間的區(qū)域性質(zhì)。如何高效地將空間數(shù)據(jù)以區(qū)域的形式分割成設(shè)定標(biāo)準(zhǔn)的塊的大小,并在分片后快速建立空間索引,是選擇不同分片策略的依據(jù)??臻g分片是空間索引過程中的第一步,所以分片的策略影響著后期索引的建立,并且對后期數(shù)據(jù)的訪問效率有著重要的影響。
目前,SpatialHadoop提供的空間索引包括網(wǎng)格,R樹,R+數(shù),四叉樹,STR,STR+,K-D樹,Z曲線和希爾伯特曲線索引[6]。
4.3 建立空間索引
通過MapReduce工作建立索引將經(jīng)歷了3個階段,即分區(qū)、本地索引和全局索引[1-2]。
(1)在分區(qū)階段,一個文件將被按照空間分布情況進(jìn)行分區(qū)。鄰近的對象將盡量被存儲在一起,也就是說一個分區(qū)中的對象不存在空間隔斷的現(xiàn)象。
確定分片數(shù)n:
確定n的大小依賴于以下公式[6]:
其中,S為空間數(shù)據(jù)集的大小,B為HDFS設(shè)置的存儲文件塊的大小,α是開銷比(默認(rèn)值為0.2),即重復(fù)記錄和本地索引所占用的開銷。
確定分區(qū)的邊界,每個單獨的分區(qū)都將有一個矩形作為它的邊界。由于普遍存在數(shù)據(jù)集空間分布不均勻的情況,計算出來的邊界的大小大多數(shù)是不一樣的。輸出的結(jié)果將以n個矩形代替n個分區(qū)。
(2)分區(qū),利用第二步確定的n個矩形初始化MapReduce的工作任務(wù)來對輸入的數(shù)據(jù)集進(jìn)行實際分區(qū),map程序結(jié)束后每條記錄(記作r)都會被劃分到一個確定的分片(記作p)中,這將生成一系列的
鍵值對[6],相同鍵p的鍵值對將被組織成一個分片p被傳入Reduce程序進(jìn)行下一步的操作。
為了防止分區(qū)太大而不能用一個塊完全存儲,可以將分區(qū)分割成每個達(dá)到64 M大小的小塊。同時,對于不能達(dá)到64 M大小的塊將通過添加冗余數(shù)據(jù)而保證每個塊都具有相同的大小[1-4]。
本地索引是通過Reduce函數(shù)來實現(xiàn)的,它將每個分片都用每行一條記錄的形式存儲起來作為分區(qū)中對象的索引。本地索引文件被組織為塊(64 M)的大小,以便進(jìn)行空間操作時能夠?qū)⒚恳粋€本地索引文件用一個map工作任務(wù)來處理[2-3,6]。
添加全局索引的目的是為了對所有分區(qū)進(jìn)行索引,一旦分區(qū)任務(wù)結(jié)束,SpatialHadoop將初始HDFS的concat命令,將所有的本地索引關(guān)聯(lián)成一個文件[6]。
主節(jié)點將在內(nèi)存中開辟一塊空間存儲這個文件,這就是SpatialHadoop的全局索引文件[3-4]。
4.4 獲取空間索引
全局索引的所有信息都存儲在主節(jié)點的內(nèi)存中??梢哉{(diào)用Spatialhadoop的API檢索全局索引[1-2]。
5 空間操作的擴(kuò)展
空間操作可以通過常規(guī)的MapReduce程序來實現(xiàn),相比本地的空間操作,SpatialHadoop的空間操作的輸入是空間數(shù)據(jù)的空間索引而不是空間數(shù)據(jù)本身,當(dāng)然,SpatialHadoop中的空間索引也和傳統(tǒng)的空間索引有所區(qū)別,SpatialHadoop的本地局部空間索引中包含了空間數(shù)據(jù)的實體信息。另外,相較于常規(guī)的MapReduce函數(shù),SpatialHadoop允許在map和reduce過程中實現(xiàn)過濾函數(shù)[1-4],過濾函數(shù)可以對計算的內(nèi)容進(jìn)行篩選,這樣可以盡可能地減少job的map任務(wù)數(shù)量。
空間數(shù)據(jù)的價值往往隱藏在數(shù)據(jù)之中,所以有空間數(shù)據(jù)就少不了空間數(shù)據(jù)的分析,為此SpatialHadoop提供了3種基本空間操作[1-4],同時還集成了計算幾何操作算法庫CG_Hadoop[4,7]。在提供了這些基本的空間操作之后,實現(xiàn)空間分析就簡單得多了。為了方便展示空間大數(shù)據(jù),SpatialHadoop還提供了可視化的操作。當(dāng)然,因為SpatialHadoop的出發(fā)點是不帶屬性的純坐標(biāo)形式的空間數(shù)據(jù),所以這些空間操作功能還需要一些必要的擴(kuò)展和改進(jìn)。
SpatialHadoop在眾多空間操作中選擇實現(xiàn)了3種基本空間操作,分別是范圍查詢、最鄰近查詢和連接操作[1-4]。CG_Hadoop是一套基于MapReduce的計算幾何操作算法庫,目前,它包含了5種基本的計算幾何操作,分別是合并多邊形、凸包、輪廓線、最遠(yuǎn)點對和最近點對[7]。但是,實際上的空間操作是離不開屬性信息的,而這3種操作都是基于純坐標(biāo)文本數(shù)據(jù)的,這并不能滿足我們的需求,為此,必須在原有的基礎(chǔ)上做屬性支持上的擴(kuò)展。
在前面的章節(jié)中,我們已經(jīng)對數(shù)據(jù)類型做了擴(kuò)展并關(guān)聯(lián)上了屬性信息,那么,這樣就比較簡單了,對于涉及屬性上的操作,只需要在屬性表中進(jìn)行相關(guān)操作,之后再通過ID映射到實體信息上即可。
空間數(shù)據(jù)的可視化對其應(yīng)用具有重要的意義,純粹的數(shù)字對大多數(shù)人來說是沒有意義的,只有將分析的結(jié)果以圖形的形式展示出來,才能極大地發(fā)揮空間數(shù)據(jù)的作用和價值。傳統(tǒng)的可視化技術(shù)依賴單一的機器來加載和處理數(shù)據(jù)的可視化,這種模式將無法處理大數(shù)據(jù)中的空間數(shù)據(jù)。
因此,SpatialHadoop提供了一套高效的可視化工具,尤其在空間數(shù)據(jù)量達(dá)到一定程度而我們又想通過圖像的形式展示出來時候,這些工具將會格外有用。
SpatialHadoop支持兩種類型的圖像,即單級和多級圖像。所謂單級圖像就是一張具有確定分辨率的圖像或者說一張圖片。在單級圖像可視化中,輸入數(shù)據(jù)集被可視化為一個用戶指定像素大小的單一的圖像。一個單級圖像的質(zhì)量具有有限的分辨率,這意味著用戶不能放大看到更多的細(xì)節(jié)。因此,SpatialHadoop還支持多級圖像,由不同縮放級別的瓦片組成。一個多級圖像是由在不同縮放級別的許多瓦片小圖像組成,而每個小圖像將展示不同的區(qū)域。這允許用戶縮放或平移圖像從而看到具體區(qū)域的更多細(xì)節(jié)。
自然而然地,這一套可視化工具也沒有考慮到屬性信息的可視化問題,由于實體信息和屬性是通過ID直接關(guān)聯(lián)的,因此,在制圖時直接將屬性信息一并顯示在地圖上就可以了。
6 結(jié)語
SpatialHadoop從存儲、MapReduce框架、操作以及開發(fā)語言4個方面對Hadoop做了一個全方位的擴(kuò)展,從而使得SpatialHadoop對于空間數(shù)據(jù)具有較強的親和力,顯著地增強了處理空間數(shù)據(jù)的能力。
但是在實際應(yīng)用中其存在的問題也尤為明顯,它不支持屬性數(shù)據(jù),同時也沒有線性數(shù)據(jù)類型。為此,需要對其進(jìn)行二次擴(kuò)展,關(guān)聯(lián)屬性信息,采用了HBase存儲關(guān)聯(lián)的屬性表,并且為空間對象添加了唯一的標(biāo)識。這不僅解決了屬性關(guān)聯(lián)的問題,同時也解決了在建立空間索引時空間對象位序錯亂的問題。另外由于HBase存在時間戳的關(guān)系也在一定程度上建立了時間維度的信息。為了解決復(fù)雜的空間操作的問題,我們也需要對現(xiàn)有的空間操作做一些必要的擴(kuò)展,目的是為了支持需要處理空間屬性的空間操作。
[參考文獻(xiàn)]
[1]ELDAWY A,MOKBEL M F.A demonstration of SpatialHadoop:an efficient mapreduce framework for spatial data[J].Proceedings of the Vldb Endowment,2013(12):1230-1233.
[2]ELDAWY A,MOKBEL M F.The ecosystem of SpatialHadoop[J].Sigspatial Special,2015(3):3-10.
[3]ELDAWY A,MOKBEL M F.SpatialHadoop:a MapReduce framework for spatial data[C].Seoul:IEEE International Conference on Data Engineering,2015:1352-1363.
[4]ELDAWY A.SpatialHadoop:towards flexible and scalable spatial processing using mapreduce[C].Zeyna:ACM SIGMOD Phd Symposium,2014:46-50.
[5]ELDAWY A,MOKBEL M F.Pigeon:A spatial MapReduce language[C].Chicago:IEEE International Conference on Data Engineering,2014:1242-1245.
[6]ELDAWY A,ALARABI L,MOKBEL M F.Spatial partitioning techniques in SpatialHadoop[J].Proceedings of the Vldb Endowment,2015(12):1602-1605.
[7]ELDAWYA,LI Y,MOKBEL M F,et al.CG_Hadoop:computational geometry in MapReduce[C].Orlando:ACM Sigspatial International Conference on Advances in Geographic Information Systems,2013:294-303.
[8]SpatialHadoop.Analyze your spatial data efficiently[EB/OL].(2017-12-13)[2018-01-16].http://spatialhadoop.cs.umn.edu/.
[9]百度文庫.shp文件詳細(xì)格式[EB/OL].(2014-06-23)[2018-01-16].https://wenku.baidu.com/view/e0bb64702f60ddccdb38a038.html.