目錄
一、前言
看到這個題目有人肯定會說這有什么可寫的,最簡單的我只要用文件系統一個個查找、打開就可以實現,再高級一點我可以提取出所有數據的元數據,做個元數據管理系統就可以實現查找功能,有必要用geotrellis用分布式嗎?這不是殺雞用牛刀嗎?理論上是這樣的,但是要看我們考慮問題的尺度,如果你只是一些簡單的數據用傳統方法當然好,省事、省時、簡單、速度快,但是當我們將數據的量放大到一個區域乃至全球的時候恐怕事情就不是那么簡單了,比如我們有了全球Landsat數據,如何查看某一地區此數據的情況,傳統方法可能要自己先計算出此區域的Landsat的帶號,然后再找到此數據並打開之。如果覺得這海不麻煩,那么當用戶需要考察Landsat的雲量或者NDVI的時候是不是又要用戶自己打開數據並使用Arcgis等自行計算?是不是很麻煩,而本文介紹的方法是只需要用戶輸入有關此點的信息(帶號或者點位信息),系統能夠自動呈現此區域的數據(或者雲量、NDVI等結果),這樣是不是逼格立馬上去了呢?
二、前台實現
此功能的前台也不可謂不復雜,但是難不倒我這個全棧工程師(請忽略此話),費了半天勁,基本實現了前台的功能。總體就是一個搜索框加一個按鈕,然后發送搜索關鍵詞到后台,后台返回數據列表,前台逐條展示之,單機每條數據的時候在地圖中(地圖框架采用leaflet)呈現此數據的情況,類似Google、百度。這里面我主要介紹以下知識點。
2.1 在地圖中添加、刪除標記
要給用戶呈現數據情況,最重要的就是數據的空間范圍,簡單的說就是將四個(或多個)頂點逐一連成線在地圖中顯示出來。leaflet可以簡單的使用如下語句實現該功能:
geoJsonOverlay = L.geoJson(geoJson);
geoJsonOverlay.addTo(map);
其中map為L.map('map')對象,geoJson就是想要添加的標記對象,此處用的是GeoJson,GeoJson簡單來說就是將空間對象轉成相應的json對象,便於交互、傳輸等。
再次查詢或其他情形下可能又需要將上述的標記層去掉,這時候只需下述語句即可:
map.removeLayer(geoJsonOverlay);
2.2 空間數據的顯示
當用戶想要查看某個檢索出來的數據情況的時候就需要將此數據顯示到地圖當中,后台暫且不表,如果用到瓦片技術那么顯示在leaflet中的方式就是添加一層,同樣移除數據就是刪除該層。代碼如下:
//add
WOLayer = new L.tileLayer(baseurl + '/{z}/{x}/{y}', {
format: 'image/png',
transparent: true,
attribution: 'SJZX'
});
WOLayer.addTo(map);
map.lc.addOverlay(WOLayer, "Landsat");
//delete
map.lc.removeLayer(WOLayer);
map.removeLayer(WOLayer);
三、后台實現
后台牽涉到的東西較多,主要是數據檢索、數據范圍生成GeoJson、數據存放、數據處理、數據發送等。
3.1 數據檢索
這塊與傳統方式相同,但是本文采用全文檢索的方式,該內容涉及到的問題也比較多,會在后續另立新篇,詳細介紹本系統全文檢索以及空間檢索的實現,總體上根據前台傳入的關鍵詞返回與之相關聯的數據,相當於地理信息系統版的Google。
3.2 數據范圍生成GeoJson
簡單說來就是從元數據中讀出數據的空間范圍,將此范圍生成GeoJson對象發送到前台。具體元數據信息可以通過上面的數據檢索獲取,此處假設已經取到了空間范圍的WKT標記對象,剩下的工作就是將WKT轉成GeoJson,代碼如下:
import geotrellis.vector.io.json.Implicits._
val geom = WKT.read(wkt)
geom.toGeoJson
當然此處還需要考慮geometry對象的投影變換等問題,要考慮前台、后台以及數據等的投影方式,轉換成自己需要的投影方式。
3.3 數據存放
這塊是本系統的核心,面對如此大的數據量只有合理的數據存放方式才能實現快速響應。目前采用的方式是前面文章講述過的將數據導入到Accumulo,這種方式的好處是請求數據快,但同時造成的一個問題是數據量大(相當於數據保存了2-3份,如果再考慮HDFS的備份特性,相當於6-9份),以上述Landsat為例,采用此種方式必須要將全球的Landsat數據都導入到Accumulo中,這個量是非常大的,如果有多套數據需要采用此種方式檢索,那么這個數據量確實非常大,但是分布式框架本身就是為了解決大數據量的問題。目前也正在尋找折中的解決方案。
3.4 數據處理
比如Landsat數據我們可以實時計算用戶查找區域的雲量以及NDVI等並將之呈現給用戶,這樣用戶能夠對數據的質量有一個更加深刻的認識,而不需要用戶再進行下載數據分析處理等。
3.5 數據發送
數據發送的目的是將上述處理好的數據或原始數據發送到前台,前台進行展示。此處需要注意的是要根據請求的范圍對請求結果進行掩蓋,因為用戶感興趣(查找)的是某一個或某幾個數據,如果不加掩蓋,前台獲取到的仍然是全球的數據,這樣就沒有意義。單個瓦片的請求在前面的文章中已經講過,這里重點講一下掩蓋操作。前台的區別就是在請求數據的時候要多發送一個請求范圍,比如為用戶檢索數據時后台發送的數據空間范圍GeoJson對象,后台首先根據請求的x、y、z取到對應的瓦片,然后判斷此瓦片與GeoJson對象的空間關系,取出在范圍內的數據,其他數據賦為無值,這樣就可以得到掩蓋后的瓦片,看似復雜其實Geotrellis已經為我們實現了該過程,只需要簡單幾行代碼即可實現:
import geotrellis.vector.io.json.Implicits._
val extent = attributeStore.read[TileLayerMetadata[SpatialKey]](id, Fields.metadata).mapTransform(key)
val geom = geoJson.parseGeoJson[Geometry]
tile.mask(extent, geom)
其中attributeStore是Accumulo操作的實例,id為表示請求層的對象,key為表示請求瓦片的x、y,geoJson就是傳入的空間范圍對象,根據上述代碼就能實現范圍掩蓋操作。
四、總結
本文簡單為大家介紹了如何實現海量空間數據的搜索以及詳情查看,有些部分會在后續詳細介紹,本文僅為框架介紹。
Geotrellis系列文章鏈接地址http://www.cnblogs.com/shoufengwei/p/5619419.html