数据质检业务模块代码设计

default

设计

1. 框架架构设计

1
2
3
4
5
6
7
8
graph TD
    A[配置中心] --> B[质检引擎]
    B --> C[数据适配层]
    B --> D[规则执行器]
    D --> E[基础校验模块]
    D --> F[空间拓扑模块]
    D --> G[自定义扩展模块]
    B --> H[结果处理器]

1.1 核心模块

  1. 配置中心

    • 采用YAML/JSON管理质检规则

    • 支持按图层配置检查项

    • 示例配置:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      layers:
        - name: building
          checks:
            - type: AttributeCheck
              field: height
              validators: [NotEmpty, Range(0,1000)]
            - type: TopologyCheck
              rule: NoOverlap
        - name: road
          checks:
            - type: GeometryCheck
              rule: LineNoSelfIntersect
      
  2. 质检引擎

    • 控制检查流程
    • 支持并行/串行执行策略
    • 实现进度监控和中断机制
  3. 数据适配层

    • 封装GeoTools DataStore访问
    • 实现分页查询优化(游标分页)
    • 几何对象缓存策略
  4. 规则执行器

    • 基础校验:字段非空、格式正则、值域范围
    • 空间拓扑:重叠/缝隙检查(使用JTS拓扑运算)
    • 自定义扩展:通过SPI机制加载
  5. 结果处理器

    • 错误分级(ERROR/WARNING)
    • 多种输出方式:GeoJSON/CSV/数据库
    • 错误可视化预览

2. 关键技术实现

2.1 空间检查优化

1
2
3
4
5
6
7
8
9
// 使用STRtree加速空间查询
STRtree spatialIndex = new STRtree();
features.forEach(f -> {
    spatialIndex.insert(f.getGeometry().getEnvelopeInternal(), f);
});
spatialIndex.build();

// 执行拓扑检查时快速检索相邻要素
List<Feature> candidates = spatialIndex.query(queryEnv);

2.2 规则接口设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public interface QualityChecker {
    /**
     * @param layer 当前检查图层配置
     * @param feature 要素对象
     * @param context 包含其他图层的空间索引
     */
    List<QualityError> execute(QCLayerConfig layer, 
                             Feature feature, 
                             QCContext context);
}

2.3 典型检查项实现

面层拓扑检查示例:

1
2
3
4
5
6
7
8
9
public class PolygonNoGapChecker implements QualityChecker {
    @Override
    public List<QualityError> execute(...) {
        Geometry union = context.getCachedUnionGeometry();
        if(!union.covers(feature.getGeometry())){
            return new QualityError("GEOM_001", "面存在缝隙");
        }
    }
}

字段关联性检查:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class FieldLogicChecker implements QualityChecker {
    public List<QualityError> execute(...) {
        if("住宅".equals(feature.getProperty("type")) {
            Object parking = feature.getProperty("parking");
            if(parking == null) {
                return new QualityError("ATTR_003", "住宅必须含停车位属性");
            }
        }
    }
}

3. 执行流程

1
2
3
4
5
6
7
8
9
sequenceDiagram
    Main->>+Engine: 启动任务
    Engine->>+Config: 加载质检配置
    loop 每个图层
        Engine->>DataStore: 创建空间索引
        Engine->>RuleEngine: 执行检查项
        RuleEngine-->>Result: 写入错误记录
    end
    Engine->>Reporter: 生成报告

4. 扩展设计

4.1 插件机制

  1. 实现QualityChecker接口
  2. META-INF/services注册SPI
  3. 配置文件中直接引用新检查器

4.2 自定义检查示例

1
2
3
public class CustomCheck implements QualityChecker {
    // 实现具体逻辑
}

5. 性能优化方案

  1. 数据分片:按空间网格分区检查
  2. 缓存复用:跨检查项共享空间索引
  3. 批量处理:使用FeatureCollection批量操作
  4. 异步IO:采用响应式流处理数据

6. 结果输出示例

GeoJSON错误标注:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "type": "Feature",
    "properties": {
        "layer": "building",
        "error_code": "TOP_004",
        "description": "与相邻地块存在重叠"
    },
    "geometry": {
        "type": "Polygon",
        "coordinates": [...]
    }
}

统计报表:

图层 检查项 错误数 样例要素ID
road 线自相交 12 10023,10045

7. 部署方案

  1. 独立服务:打包为Spring Boot应用
  2. 数据库集成:在PostGIS中创建 report 表
  3. 定时任务:通过Quartz调度夜间执行
  4. 可视化:集成Leaflet展示错误位置
方法 精度 效率 复杂度 适用场景
Haversine 0.5% 误差 极高 简单 快速估算,小范围距离计算
Geodesy (Vincenty) 毫米级 中等 高精度测量(如测绘、导航)
GeoTools 复杂 GIS 系统、复杂地理分析

Demo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// 1. 质检引擎主类
public class QualityInspectionEngine {
    private ConfigManager configManager;
    private DataAdapter dataAdapter;
    private ResultProcessor resultProcessor;

    public void execute(String configPath) throws Exception {
        // 加载配置
        List<QCLayerConfig> layers = configManager.loadConfig(configPath);

        // 遍历所有图层
        for (QCLayerConfig layerConfig : layers) {
            processLayer(layerConfig);
        }

        // 生成最终报告
        resultProcessor.generateReport();
    }

    private void processLayer(QCLayerConfig layerConfig) {
        // 创建空间索引上下文
        QCContext context = new QCContext();
        
        try (FeatureIterator features = dataAdapter.getFeatures(layerConfig)) {
            // 构建空间索引(用于跨要素检查)
            STRtree spatialIndex = buildSpatialIndex(features);
            context.addSpatialIndex(layerConfig.getName(), spatialIndex);

            // 分页处理要素(示例:每页500条)
            int pageSize = 500;
            FeatureCollection collection = dataAdapter.getFeaturesByPage(layerConfig, pageSize);
            
            while (!collection.isEmpty()) {
                // 执行当前页的质检
                processFeatureCollection(layerConfig, collection, context);
                
                // 获取下一页
                collection = dataAdapter.getNextPage();
            }
        }
    }

    private void processFeatureCollection(QCLayerConfig layerConfig, 
                                         FeatureCollection features,
                                         QCContext context) {
        try (FeatureIterator it = features.features()) {
            while (it.hasNext()) {
                Feature feature = it.next();
                
                // 遍历该图层的所有检查项
                for (CheckItem check : layerConfig.getChecks()) {
                    QualityChecker checker = CheckerFactory.createChecker(check.getType());
                    
                    // 执行检查并收集结果
                    List<QualityError> errors = checker.execute(layerConfig, feature, context);
                    
                    // 处理检查结果
                    resultProcessor.handleErrors(layerConfig.getName(), feature.getID(), errors);
                }
            }
        }
    }

    // 空间索引构建(使用JTS STRtree)
    private STRtree buildSpatialIndex(FeatureIterator features) {
        STRtree index = new STRtree();
        while (features.hasNext()) {
            Feature f = features.next();
            Geometry geom = (Geometry) f.getDefaultGeometryProperty().getValue();
            index.insert(geom.getEnvelopeInternal(), f);
        }
        index.build();
        return index;
    }
}

数据读取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class PostgisDataAdapter implements DataAdapter {
    private DataStore dataStore;
    private int currentOffset = 0;

    public FeatureCollection getFeaturesByPage(QCLayerConfig config, int pageSize) {
        Query query = new Query(config.getName());
        query.setMaxFeatures(pageSize);
        query.setStartIndex(currentOffset);
        
        try {
            FeatureSource source = dataStore.getFeatureSource(config.getName());
            return source.getFeatures(query);
        } finally {
            currentOffset += pageSize;
        }
    }

    public FeatureCollection getNextPage() {
        // 实现类似分页逻辑...
    }
}

质检实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 拓扑检查实现
public class OverlapChecker implements QualityChecker {
    @Override
    public List<QualityError> execute(QCLayerConfig layer, 
                                    Feature feature,
                                    QCContext context) {
        List<QualityError> errors = new ArrayList<>();
        
        // 从上下文获取空间索引
        STRtree index = context.getSpatialIndex(layer.getName());
        
        // 查询可能相交的要素
        List<Feature> candidates = index.query(feature.getBounds());
        
        for (Feature other : candidates) {
            if (feature == other) continue;
            
            if (feature.getGeometry().intersects(other.getGeometry())) {
                errors.add(new QualityError(
                    "TOP-001", 
                    "要素与其他要素存在重叠",
                    other.getID()
                ));
            }
        }
        return errors;
    }
}

程序入口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Main {
    public static void main(String[] args) {
        QualityInspectionEngine engine = new QualityInspectionEngine();
        
        // 初始化组件
        engine.setConfigManager(new YamlConfigManager());
        engine.setDataAdapter(new PostgisDataAdapter(pgParams));
        engine.setResultProcessor(new GeoJsonResultHandler());
        
        // 启动质检流程
        engine.execute("qc_rules.yaml");
    }
}
Licensed under CC BY-NC-SA 4.0
Comments
  • Latest
  • Oldest
  • Hottest
No comment yet.
Powered by Waline v2.15.8
Gear(夕照)的博客。记录开发、生活,以及一些不足为道的思考……