目錄
前言
一、天地圖POI分類簡介
1、數據表格
2、分類結構
二、從CSV導入到PG數據庫
1、CSV解析流程
2、數據轉換及入庫
3、入庫成果及檢索
三、總結
前言
????????在之前的博客中,曾經對高德地圖和百度地圖的POI分類以及使用PostGIS數據庫來進行管理的模式進行了詳細的介紹。之前的博文列表:
序號 | 博客地址 |
1 | 基于ApachePOI實現百度POI分類快速導入PostgreSQL數據庫實戰 |
2 | 基于ApachePOI實現高德POI分類快速導入PostgreSQL數據庫實戰 |
????????相信大家在平時的日常生活中,用的比較多的肯定是百度地圖和高德地圖。雖然天地圖在移動端的使用市場沒有前兩者的份額多。但是作為官方的標準,天地圖還是擁有自己得天獨厚的優勢,除了本身最具權威的地理數據,同時還有承載著官方標準的執行。因此天地圖的POI數據也是非常重要的,因此可以作為我們日常數據分析和處理的一個可靠的信息來源。不同的平臺對POI的分級分類都有所不同,相信看過上面兩篇博文的朋友一定知道,不同的廠商,對于POI分類時,它的大類和小類的定義一定是不一樣的。但是天地圖POI的分類存在非常大的差異,層次結構也是不一樣的。如下圖:
?????????天地圖的POI分類從大類來說就跟高德和百度不一樣。單從一級大類的數量來說,百度擁有?32個,而高德只區分了25個,天地圖居然有58個,在數量上天地圖是比較多的(是否可以再精簡和合并呢,需要討論),比前兩個加起來都多。另外從層級上來說,高德通常只區分了3級分類,而百度竟然有5級分類,然而天地圖在層級上非常簡單,只有2級展示,從扁平的角度來說,天地圖的扁平化做的不錯。
????????那么本文即來重點講講天地圖POI分類與高德POI分類以及百度POI分類存在什么不一樣的地方,同時結合代碼深入講解使用Java標準庫來讀取天地圖的POI 分類兵如何進行數據導入到PostGIS空間數據庫中,也為各類基于 POI 分類數據的地理信息系統開發、商業智能分析以及城市規劃應用等,鋪設一條從數據獲取到存儲利用的高效路徑,助力行業在空間數據賦能下實現精準決策與創新發展。
一、天地圖POI分類簡介
????????本節將首先重點介紹天地圖地圖的POI分類信息,在之前的博客中我們設計了用于POI管理的物理表,這里可以繼續用來存儲天地圖對應的POI分類信息。然后使用數據庫腳本的方法對POI分類信息進行錄入管理。對于天地圖而言,其POI的分類較多,但是層級簡單,因此這一節我們來詳細的解讀一下天地圖的POI分類,讓大家對分類信息有進一步的了解,為下一步對數據層級組裝和批量解析入庫打下牢固的基礎。
1、數據表格
? ? ? ? 與之前介紹的內容一樣,大家可以從天地圖的地圖開放平臺中獲取其最新的POI分類的CSV表格(是的,你沒有看錯,官方提供的確實是CSV而不是Excel,如果需要使用Excel也可以將CSV轉一下格式),這里我將從官網下載的類型截取一部分給大家參考。下載鏈接傳送門:分類編碼表。下面來看下官方在數據檢索的相關介紹:
1.1.1輸入參數說明
參數值 | 參數說明 | 參數類型 | 是否必備 | 備注(值域) |
keyWord | 搜索的關鍵字 | String | 必填 | 無 |
specify | 指定行政區的國標碼(行政區劃編碼表)嚴格按照行政區劃編碼表中的(名稱,gb碼) | String | 必填 | 下載行政區劃編碼表。9位國標碼,如:北京:156110000或北京。 |
queryType | 服務查詢類型參數 | String | 必填 | 12:行政區劃區域搜索服務。 |
start | 返回結果起始位(用于分頁和緩存)默認0 | String | 必填 | 0-300,表示返回結果的起始位置。 |
count | 返回的結果數量(用于分頁和緩存) | String | 必填 | 1-300,返回結果的條數。 |
dataTypes | 數據分類(分類編碼表) | String | 可選 | 下載分類編碼表,參數可以分類名稱或分類編碼。多個分類用","隔開(英文逗號)。 |
show | 返回poi結果信息類別 | String | 可選 | 取值為1,則返回基本poi信息; 取值為2,則返回詳細poi信息 |
????????這里不進行贅述,需要原始CSV表格的,可以去網站上下載。打開下載后的表格數據如下:
?
?
????????從上面這張圖可以看出天地圖的POI分類確實分的比較簡單。 同時也能看到一個比較明顯的區別,與百度的POI分類不一樣的是,天地圖有編碼的概念。同樣的,基于天地圖地圖的POI檢索可以從返回接口中看到其對應的POI分類值為:
{"eaddress": "","address": "榮濱南路東段11號附28附近","city": "","provinceCode": "156500000","cityCode": "","county": "榮昌區","typeName": "副食專賣店","source": "0","typeCode": "130207","lonlat": "105.590250,29.416870","countyCode": "156500153","ename": "","province": "重慶市","phone": "18716232760","poiType": "101","name": "李氏鹵鵝","hotPointID": "50166082CE55CFF5"
}
????????其中typeCode對應poi分類的類別編碼,而typeName則表示具體的類別名稱。
2、分類結構
????????在了解了天地圖的POI分類之后,下面我們基于之前設計的數據庫物理表和分類信息構建樹形的信息。因此需要對其分類采取細致的分類管理。在進行樹形層次構建時,我們根據分類名稱來進行統一管理:
?
?????????這個結構是天地圖POI分類管理的基礎,也是后面的數據程序解析的基礎。我們將使用編碼來進行數據的解析及入庫。 在CSV中,很大的大類和種類都是重復的,因此需要在入庫時將類別進行去重分類,最終構建一棵完整的POI分類樹。?
二、從CSV導入到PG數據庫
????????本節將詳細介紹在Java中使用標準庫實現從CSV中解析到存儲至PostgreGIS中,主要包含兩個方面,第一個是如何使用Java標準庫來進行CSV解析。第二個方面是如何基于Mybatis實現程序的批量入庫。關于數據處理流程與高德和百度POI入庫的流程一致,基本分為三個步驟:第一步是批量讀取數據源,第二步是將數據源解析出POI分類數據,最后將分類好的數據導入到PG數據庫中。
1、CSV解析流程
? ? ? ? 首先還是對天地圖下載的CSV格式的POI分類進行解析,在進行POI的分類進行構建時尤其重要,為了防止各層級在構建時出現重復的情況,這里采用LinkedHashMap集合來進行重復判斷,在存儲集合對象時,將分類編碼作為map的key,而具體分類對象作為value。在天地圖的POI分類編碼中,可以發現將編碼的前四位和后兩位可以拆開,后兩位如果是00的一般都是父類節點,通過我們的觀察可以看到在后續的對象去重判斷時,key就是重復的標記。為了實現從CSV格式的文件中讀取數據,這里首先介紹一下CSV的解析流程。在正式講解數據導入時,需要明確一個信息,就是在CSV數據的每一行中,只要遇到-這個字符就基本表示再往后讀一個單元格,當前行的數據讀取任務結束。
????????第一步:一些不要的輔助信息,比如需要定義需要處理的文件本地路徑地址。代碼如下:
@Autowired
private IPoiCategoryService poiCateGoryService;
private static final String TDT_POI_CSV_FILE = "C:/Users/Administrator/Desktop/天地圖及相關信息/天地圖Type-數據分類(分類編碼表).csv";
private static final String TRIGGER_CHAR = "-";
????????第二步:CSV解析實現
????????為了能夠正確的解析CSV數據,這里需要額外定外定義兩個參數,以此保證數據的準確解析。關于CSV的解析實現代碼如下:
// 自定義CSV行解析(處理帶逗號的字段)
private static String[] parseCsvLine(String line) {java.util.List<String> fields = new java.util.ArrayList<>();StringBuilder field = new StringBuilder();boolean inQuotes = false;for (char c : line.toCharArray()) {if (c == '"') {inQuotes = !inQuotes; // 切換引號狀態} else if (c == ',' && !inQuotes) {fields.add(field.toString());field.setLength(0); // 重置} else {field.append(c);}}fields.add(field.toString()); // 添加最后一個字段return fields.toArray(new String[0]);
}// 清理單元格值
private static String cleanCellValue(String value) {// 去除首尾空格和引號value = value.trim();if (value.startsWith("\"") && value.endsWith("\"")) {value = value.substring(1, value.length() - 1);}// 處理轉義的雙引號return value.replace("\"\"", "\"");
}
????????第三步:CSV數據解析,實現最基本的數據解析讀取和基礎配置之后,下面就可以來實現對CSV數據的具體讀取,這里采取的是直接的Java標準庫解析的方法。實例代碼如下:
private static LinkedHashMap<String,PoiCategory> csv2Map(){// UTF-8, GBK, GB2312, ISO-8859-1, Windows-1252Charset charset = Charset.forName("GBK"); // 根據實際文件編碼設置LinkedHashMap<String,PoiCategory> amapPoiTypeMap = new LinkedHashMap<String, PoiCategory>(); try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(TDT_POI_CSV_FILE), charset))) {String line = "";int rowNum = 0;while ((line = br.readLine()) != null) {rowNum++;String[] cells = parseCsvLine(line); // 使用自定義解析方法處理帶逗號的字段boolean foundTrigger = false;List<String> poiCategories = new ArrayList<String>();String poiCategoryCode = "";//獲取每一行的的每個格子的數據for (int i = 0; i < cells.length; i++) {String cellValue = cleanCellValue(cells[i]);//System.out.println(cellValue);if (cellValue.contains(TRIGGER_CHAR)) {foundTrigger = true;//System.out.println("[行 " + rowNum + "] 觸發單元格: " + cellValue);if (i + 1 < cells.length) {String nextValue = cleanCellValue(cells[i + 1]);poiCategoryCode = nextValue;//System.out.println("→ 終止單元格: " + nextValue);} else {System.out.println("→ 終止單元格: (空)");}break;}else {poiCategories.add(cellValue);}}if (!foundTrigger) {System.out.println("行 " + rowNum + ": 未找到觸發字符");}//執行分類預處理if(foundTrigger) {String prefix_head = poiCategoryCode.substring(0,4);String prefix_tail = poiCategoryCode.substring(4);if(prefix_tail.equalsIgnoreCase("00")) {//00表示大類String levelFirst = poiCategoryCode;//處理一級,添加到集合中if(!amapPoiTypeMap.containsKey(levelFirst)) {PoiCategory category = new PoiCategory(IdWorker.getId(),1944421516292726785L,"0,100,1944421516292726785",String.join("/", poiCategories),StringUtils.EMPTY,levelFirst);amapPoiTypeMap.put(levelFirst, category);}}else {//剩下表示小類if(!amapPoiTypeMap.containsKey(poiCategoryCode)) {String _parentKey = prefix_head + "00";PoiCategory parentCategory = amapPoiTypeMap.get(_parentKey);String ancestors = parentCategory.getAncestors() + "," + parentCategory.getPkId();PoiCategory category = new PoiCategory(IdWorker.getId(),parentCategory.getPkId(),ancestors,String.join("/", poiCategories),StringUtils.EMPTY,poiCategoryCode);amapPoiTypeMap.put(poiCategoryCode, category);}}}}} catch (IOException e) {e.printStackTrace();}return amapPoiTypeMap;
}
2、數據轉換及入庫
????????將CSV數據成功的解析轉換成LinkedHashMap之后,事情還遠遠沒結束,接下來需要將獲取的LinkedHashMap轉換成ArrayList。為了在查詢數據的時候方便,在正式入庫之前還需要增加一家額外的輔助信息,信息如下:
/**
* - 將map集合轉換成list集合
* @param amapPoiTypeMap
* @return
*/
private static List<PoiCategory> convertMap2DataList(LinkedHashMap<String,PoiCategory> amapPoiTypeMap) {List<PoiCategory> categoryData = new ArrayList<PoiCategory>();Date now = DateUtils.getNowDate();for (PoiCategory value : amapPoiTypeMap.values()) {value.setPlatform("tianditu");value.setDelFlag(0);value.setStatus(0);value.setOrderNum(1);value.setCreateTime(now);categoryData.add(value);}return categoryData;
}
????????到這里,我們就已經實現了如何使用Java標準庫來解析CSV文件,并且將數據都讀到了LinkedHashMap對象中,接下來就調用上述的方法來組裝成一個完整的數據導入實例,核心代碼如下:
@Test
public void writer2DB() {//step1、讀取CSV到Map集合中LinkedHashMap<String,PoiCategory> map = csv2Map();//step2、將map轉成list集合List<PoiCategory> categoryData = convertMap2DataList(map);//step3、插入到數據庫中for (PoiCategory poiCategory : categoryData) {System.out.println(poiCategory);}//step4、數據入庫 poiCateGoryService.batchInsertPoiCategory(categoryData);System.out.println("finished...");
}
3、入庫成果及檢索
????????完成以上的程序編寫,并運行操作后就完成了天地圖POI分類數據的PostGIS數據庫導入操作,程序執行完成后,可以在控制臺看到以下輸出:
????????為了驗證是否在數據庫中是否也保存了這些數據,可以使用以下SQL語句進行查詢:?
select * from biz_poi_category t where platform = 'tianditu';
??????????在客戶端軟件中執行以上SQL后可以看到以下結果:
三、總結
????????以上就是本文的主要內容,支持對天地圖的POI分類的CSV入庫及檢索就基本完成,后續我們將深入使用POI信息以及如何進行相應數據的采集。那么本文即來重點講講天地圖POI分類與高德和百度POI分類存在什么不一樣的地方,需要注意的是,本文讀取的文件不是Excel而是CSV格式,因此也深入講解了如何使用Java標準庫來解析天地圖的POI分類文件,同時深入講解天地圖?POI 分類如何進行數據導入,如何將CSV數據轉為LinkedHashMap,再到ArrayList,最后批量入庫。也為各類基于 POI 分類數據的地理信息系統開發、商業智能分析以及城市規劃應用等,鋪設一條從數據獲取到存儲利用的高效路徑,助力行業在空間數據賦能下實現精準決策與創新發展。行文倉促,難免有許多不足之處,如有不足,在此懇請各位專家博主在評論區不吝留言指出,不勝感激。