ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【GIS系列】挑战千万级数据:Java和Elasticsearch在GIS中的叠加分析实践 [打印本页]

作者: 嚴華    时间: 2024-6-13 20:39
标题: 【GIS系列】挑战千万级数据:Java和Elasticsearch在GIS中的叠加分析实践
作者:后端小肥肠
  创作不易,未经答应严禁转载。
  目次
1. 媒介
2. 叠加分析场景方案对比
2.1. Geotools
2.2. PostGIS
2.3. Elasticsearch
3. 基于ElastcSearch实现叠加分析代码实践
3.1. 开发环境搭建
3.1.1. 所需版本和工具
3.1.2. pom依赖
3.2. 数据导入
3.3. 返回布局计划
3.4. 核心代码讲解
3.4.1. 将面要素wkt转换为GeoPoint类型的数组
3.4.2. 编写叠加分析方法函数
3.5. 效果测试
4. 结语


1. 媒介

在处理千万级图斑叠加分析时,传统的后端GIS工具,如Geotools和PostGIS,往往难以满足实时性和高效性的要求。在这一挑战背景下,引入Elasticsearch作为空间叠加查询的解决方案,成为了一种创新且高效的选择。本文将探讨怎样利用Java和Elasticsearch实现GIS中的千万级图斑叠加分析,以项目场景为基础,通过对传统后端GIS工具与Elasticsearch的性能比较,旨在为读者展示Elasticsearch作为一种新兴的空间数据处理工具的价值和潜力,为解决雷同问题的开发者提供新的思路息争决方案。
本文得当有Elasticsearch和GIS后台编程基础的jym,如本文对你有帮助和启示,请三连支持一下小肥肠~
2. 叠加分析场景方案对比

假设叠加分析的场景为求一个面要素下包含的点要素,点要素图层有1000万个点,要求在短时间内返回叠加分析效果。以后端为JAVA的背景下,常用的叠加分析方案有Geotools,Postgis,ES,目前将从技术方案特点,性能,优缺点,以及处理千万级图斑的可行性这几个方面依次介绍这几种技术方案。

2.1. Geotools


2.2. PostGIS


2.3. Elasticsearch


3. 基于ElastcSearch实现叠加分析代码实践

3.1. 开发环境搭建

3.1.1. 所需版本和工具

依赖版本Spring Boot2.6.3Java1.8以上Elasticsearch7.9.3 3.1.2. pom依赖

  1. <dependencies>
  2.     <dependency>
  3.         <groupId>org.springframework.boot</groupId>
  4.         <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  5.     </dependency>
  6.     <dependency>
  7.         <groupId>org.locationtech.jts</groupId>
  8.         <artifactId>jts-core</artifactId>
  9.     </dependency>
  10.     <dependency>
  11.         <groupId>org.springframework.boot</groupId>
  12.         <artifactId>spring-boot-starter-web</artifactId>
  13.     </dependency>
  14. </dependencies>
复制代码
3.2. 数据导入

基于工具将点要素图层导入Elasticsearch,这里怎么导入的不细讲,相关资料可自行百度:

留意看Shape字段类型要如上图才能支持面包含点类型的叠加分析。 
3.3. 返回布局计划

  1. {
  2.     "code": 200,
  3.     "status": "success",
  4.     "message": "OK",
  5.     "data": {
  6.         "list": [
  7.             {
  8.                 "name": "地类名称",
  9.                 "code": "地类编码",
  10.                 "count": 178,
  11.                 "hectares": 541213,
  12.                 "ares": 3243,
  13.                 "squareMetres": 32432
  14.             }
  15.         ]
  16.     }
  17. }
复制代码
由返回布局可看出,我们需要返回点要素的name,code和面积属性(平方米,公亩,公顷)。
3.4. 核心代码讲解

3.4.1. 将面要素wkt转换为GeoPoint类型的数组

  1.     private List<GeoPoint> parseWKTGeometry(String wkt) {
  2.         List<GeoPoint> points = new ArrayList<>();
  3.         GeometryFactory geometryFactory = new GeometryFactory();
  4.         WKTReader reader = new WKTReader(geometryFactory);
  5.         try {
  6.             Geometry geometry = reader.read(wkt);
  7.             if (geometry instanceof Polygon) {
  8.                 Polygon polygon = (Polygon) geometry;
  9.                 LinearRing ring = (LinearRing) polygon.getExteriorRing();
  10.                 Coordinate[] coordinates = ring.getCoordinates();
  11.                 for (Coordinate coord : coordinates) {
  12.                     double lat = coord.y;
  13.                     double lon = coord.x;
  14.                     points.add(new GeoPoint(lat, lon));
  15.                 }
  16.             }
  17.         } catch (ParseException e) {
  18.             e.printStackTrace();
  19.         }
  20.         return points;
  21.     }
复制代码
3.4.2. 编写叠加分析方法函数

  1. public ResponseStructure overlayAnalysis(OverlayDTO overlayDTO) {
  2.         try {
  3.             if(StringUtils.isEmpty(overlayDTO.getGeometry())){
  4.                 return ResponseStructure.failed("空间范围不可为空");
  5.             }
  6.             String geometry=overlayDTO.getGeometry();
  7.             // 1. 指定检索 Index
  8.             SearchRequest request = new SearchRequest();
  9.             request.indices(ALIAS);
  10.             // 2. 指定检索方式
  11.             SearchSourceBuilder builder = new SearchSourceBuilder();
  12.             // 3. 解析 WKT 格式的多边形
  13.             List<GeoPoint> points = parseWKTGeometry(geometry);
  14.             // geoPolygonQuery 代表着的是多边形查询
  15.             builder.query(QueryBuilders.geoPolygonQuery("Shape", points)).trackTotalHits(true).size(0);
  16.             // 4. 添加聚合查询
  17.             TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("code").field(FIELD_CODE)
  18.                     .subAggregation(AggregationBuilders.sum("MJ").field("YJJBNTMJ")).size(500);
  19.             builder.aggregation(termsAggregationBuilder);
  20.             request.source(builder);
  21.             // 5. 执行查询
  22.             SearchResponse resp = restHighLevelClient.search(request, RequestOptions.DEFAULT);
  23.             // 6.1 输出总数
  24.             long total = resp.getHits().getTotalHits().value;
  25.             // 6.2 聚合结果
  26.             List<DataVo> lists = new ArrayList<>();
  27.             Terms terms = resp.getAggregations().get("code");
  28.             List<? extends Terms.Bucket> buckets = terms.getBuckets();
  29.             for (Terms.Bucket bucket : buckets) {
  30.                 // 获取分组总面积
  31.                 Sum mj = bucket.getAggregations().get("MJ");
  32.                 Double sum = mj.getValue();
  33.                 log.info("面积:{}", sum);
  34.                 // 获取代码
  35.                 String code = bucket.getKeyAsString();
  36.                 log.info("代码:{}", code);
  37.                 QuickStatistics quickStatistics = quickStatisticsMapper.selectOne(new LambdaQueryWrapper<QuickStatistics>()
  38.                         .eq(QuickStatistics::getCode, code).eq(QuickStatistics::getType, FIELD_CODE));
  39.                 // 如果大数据库查到的代码没有在 pg 库的数据字典中,忽略不统计
  40.                 if (quickStatistics == null) {
  41.                     log.info("未统计的代码:{}", code);
  42.                     continue;
  43.                 }
  44.                 String name = quickStatistics.getName();
  45.                 lists.add(new DataVo(name, code, bucket.getDocCount(), sum, sum / 100, sum / 10000));
  46.             }
  47.             JBNTVO jbntvo = new JBNTVO(lists);
  48.             return ResponseStructure.success(jbntvo);
  49.         } catch (Exception e) {
  50.             log.error(e.getMessage(), e);
  51.             return ResponseStructure.failed("叠加分析异常");
  52.         }
  53.     }
复制代码
上述方法使用Elasticsearch进行查询,根据指定的几何图形执行地理多边形查询,并添加聚合查询以计算特定区域内的指标数据。最后,它将查询效果进行处理,包括统计各个区域的指标数据和计算相关指标,然后封装成特定的VO对象返回。如果在执行过程中出现异常,则记录错误信息并返回相应的错误响应。 
3.5. 效果测试


由上图可知,只需要输入叠加面要素的wkt格式数据,便可在短时间内拿到叠加分析效果。 
4. 结语

本文以千万级图斑叠加分析为背景,起首对比了常规技术栈和ES的优缺点,最后以现实代码讲解了怎样基于ES实现千万级图斑叠加分析,如有更好的想法欢迎在批评区留言进行讨论~


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4