从区划边界geojson中查询经纬度坐标对应的省市区县乡镇名称,开源Java工具,内存占用低、高性能

2022-06-30

坐标边界查询工具:AreaCity-Query-Geometry

本工具核心功能:使用jts库省市区县乡镇边界数据AreaCity-JsSpider-StatsGov开源库)或geojson边界数据文件中查找出和任意点、线、面有相交的矢量边界,内存占用低,性能优良。

GitHub地址:https://github.com/xiangyuecn/AreaCity-Query-Geometry
Gitee镜像库:https://gitee.com/xiangyuecn/AreaCity-Query-Geometry

主要特性:

  • 查询一个坐标点对应的城市信息;
  • 查询一条路径经过的所有城市;
  • 查询一个矢量范围覆盖的所有城市;
  • 查询一个城市或下一级所有边界数据(WKT格式);
  • 支持通过HTTP API服务进行查询调用;
  • 支持通过Java代码进行查询调用;
  • 源码简单,包括测试bat脚本共5个文件,无需IDE即可修改和运行,copy即用。

可以只copy AreaCityQuery.java 文件到项目中使用,项目中引入jts库,就能使用 AreaCityQuery 中的所有查找功能了。也可以clone整个项目代码双击 编译和运行Test.java直接测试.bat 即可直接运行测试。

API和图形界面:此工具自带了一个HTTP API服务,运行测试然后通过菜单启动此服务,然后就可以直接在浏览器上访问这些接口;此API接口可以直接在 ECharts Map四级下钻在线测试和预览 页面的自定义数据源中进行调用测试,页面会立即绘制查询出来的边界图形。

效果图:

HTTP API图形界面:
HTTP API图形界面

控制台运行:
控制台运行

性能测试数据

测试数据源:AreaCity-JsSpider-StatsGov开源库2021.220321.220428版本下载的ok_geo.csv文件按省市区导出成不同的geojson文件。

测试采用开启多线程进行随机坐标点的查询(Test.java控制台5号菜单),测试机器配置:8核 2.20GHz CPU,SSD 硬盘。

测试一:Init_StoreInWkbsFile 内存占用很低(性能受IO限制)

数据源 文件大小 数据量 内存占用 7核QPS 单核QPS 单次查询耗时
省市区三级 176MB 3632条 41MB 6212 887 1.13ms
仅区级 107MB 3208条 24MB 13818 1974 0.51ms
仅省级 20MB 34条 4MB 19832 2833 0.35ms

Init_StoreInWkbsFile:用加载数据到结构化数据文件的模式进行初始化,推荐使用本方法初始化,边界图形数据存入结构化数据文件中,内存占用很低,查询时会反复读取文件对应内容,查询性能消耗主要在IO上,IO性能极高问题不大。

测试二:Init_StoreInMemory 内存占用和json文件差不多大(性能豪放)

数据源 文件大小 数据量 内存占用 7核QPS 单核QPS 单次查询耗时
省市区三级 176MB 3632条 161MB 77242 11034 0.091ms
仅区级 107MB 3208条 96MB 121228 17318 0.058ms
仅省级 20MB 34条 18MB 465940 66562 0.015ms

Init_StoreInMemory:用加载数据到内存的模式进行初始化,边界图形数据存入内存中,内存占用和json数据文件大小差不多大,查询性能极高;另外可通过设置 AreaCityQuery.SetInitStoreInMemoryUseObject=true 来进一步提升性能,但内存占用会增大一倍多,省市区三级单核可达到 15000 QPS。

参考:数据库查询测试对比

数据源 数据量 查询坐标 MySQL单次查询耗时 SQL Server单次查询耗时
省市区三级 3632条 深圳-龙华区 163ms 25ms
省市区三级 3632条 北京-房山区 173ms 47ms

数据库查询坐标点:POINT(114.044346 22.691963) 深圳市 龙华区;POINT(116.055588 39.709385) 北京市 房山区(查询受内蒙envelope干扰影响性能)

查询坐标对应的省市区县乡镇名称

使用此工具进行坐标省市区县乡镇查询,先要准备一个省市区县乡镇的边界geojson数据文件。

数据中有哪一级的边界就能查询出哪一级的名称;比如你只有区级的数据,那么给一个坐标就能查询出此坐标所在的区县名称(需另外查找出上级的省市名称);如果有省市区三级的边界,那一次性就能查询出省市区三级的名称,如果有乡镇的边界,就能查询出乡镇这级的名称。

步骤一:准备好省市区县乡镇边界的geojson文件

如果你没有边界json文件,可以按以下步骤获得最新的全国省市区县乡镇边界数据json文件:

  1. 到开源库下载省市区边界数据ok_geo.csv文件: https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov (github可换成gitee);
  2. 下载开源库里面的AreaCity-Geo格式转换工具软件
  3. 打开转换工具软件,选择ok_geo.csv,然后导出成geojson文件即可(默认会导出全国的省级数据,通过填写不同城市名前缀可以导出不同城市)。

如果你有多个geojson文件,需要合并成一个才行,可以通过上面下载的 AreaCity-Geo格式转换工具软件 中的 高级功能-GeoJSON多个文件合并成一个文件 来合并。

步骤二:运行测试程序进行初始化

双击 编译和运行Test.java直接测试.bat 运行测试控制台程序;根据控制台菜单命令进行初始化,有两种初始化方式,随便哪种都行:

  1. Init_StoreInWkbsFile:内存占用很低,但查询速度相对StoreInMemory慢很多,但也很快的,推荐用此方法初始化;
  2. Init_StoreInMemory:内存占用大一点,但查询速度非常快。

选择了初始方式后会要求填写geojson文件路径,填写上一步准备好的json文件完整路径即可;或者直接将json文件放到程序根目录,会自动初始化。

步骤三:查询坐标获得省市区名称

初始化完成后,所有的菜单都可以使用了,可以直接在控制台中使用对应的菜单进入菜单查询功能,然后输入坐标查询即可。

建议使用HTTP API来进行查询,在菜单中启动好HTTP服务后,就能通过网址访问查询接口,或者直接使用在线的可视化界面进行查询操作:

坐标查询可视化效果

附:通过Java代码进行查询

//先初始化,全局只会初始化一次,每次查询前都调用即可(查询会在初始化完成后进行),两种初始化方式根据自己业务情况二选一
//首次初始化会从.json或.geojson文件中读取边界图形数据,速度比较慢,会自动生成.wkbs结尾的结构化文件,下次初始化就很快了
AreaCityQuery.Init_StoreInWkbsFile("geojson文件路径", "geojson文件路径.wkbs", true);
//AreaCityQuery.Init_StoreInMemory("geojson文件路径", "geojson文件路径.wkbs", true);

//AreaCityQuery.OnInitProgress=(initInfo)->{ ... } //初始化过程中的回调,可以绑定一个函数,接收初始化进度信息

//查询包含一个坐标点的所有边界图形的属性数据,可通过res参数让查询额外返回wkt格式边界数据
QueryResult res1=AreaCityQuery.QueryPoint(114.044346, 22.691963, null, null);

//查询和一个图形(点、线、面)有交点的所有边界图形的属性数据,可通过res参数让查询额外返回wkt格式边界数据
Geometry geom=new WKTReader(AreaCityQuery.Factory).read("LINESTRING(114.233963 30.546038, 114.468109 30.544264)");
QueryResult res2=AreaCityQuery.QueryGeometry(geom, null, null);

//读取省市区的边界数据wkt格式,这个例子会筛选出武汉市所有区县
QueryResult res3=AreaCityQuery.ReadWKT_FromWkbsFile("wkt_polygon", null, (prop)->{return prop.contains("武汉市 ");}, null);


System.out.println(res1+"\n"+res2+"\n"+res3);

【END】