第09章 - 性能优化与加速

第09章 - 性能优化与加速

9.1 性能优化概述

9.1.1 性能考量因素

geometry-api-java 的性能受以下因素影响:

  1. 几何复杂度:顶点数量、环数量
  2. 操作类型:拓扑操作比关系判断更耗时
  3. 数据规模:处理的几何对象数量
  4. 内存使用:大几何对象的内存占用
  5. 算法效率:不同实现方式的效率差异

9.1.2 优化策略概览

性能优化策略
├── 几何加速(Geometry Acceleration)
│   └── 光栅化和四叉树预处理
├── 空间索引
│   ├── QuadTree
│   └── Envelope2DIntersector
├── 批量处理
│   └── GeometryCursor
├── 内存优化
│   ├── 对象复用
│   └── 流式处理
└── 算法选择
    └── 根据场景选择合适的操作

9.2 几何加速

9.2.1 加速原理

geometry-api-java 通过预处理几何对象来加速重复的空间操作:

// 加速结构
GeometryAccelerators
├── RasterizedGeometry2D  // 光栅化表示
└── QuadTree              // 四叉树索引

加速适用场景

  • 一个几何与大量其他几何进行关系判断
  • 重复查询同一个几何

9.2.2 使用几何加速

Polygon largePolygon = createLargeComplexPolygon();
SpatialReference sr = SpatialReference.create(4326);

// 获取支持加速的算子
OperatorContains containsOp = OperatorContains.local();

// 检查是否可以加速
boolean canAccelerate = containsOp.canAccelerateGeometry(largePolygon);
System.out.println("可加速: " + canAccelerate);

if (canAccelerate) {
    // 执行加速预处理
    containsOp.accelerateGeometry(
        largePolygon, 
        sr, 
        Geometry.GeometryAccelerationDegree.enumMedium
    );
}

// 批量查询(现在会更快)
List<Point> points = getMillionsOfPoints();
int containedCount = 0;

for (Point point : points) {
    if (containsOp.execute(largePolygon, point, sr, null)) {
        containedCount++;
    }
}

System.out.println("包含点数: " + containedCount);

// 完成后释放加速资源
Operator.deaccelerateGeometry(largePolygon);

9.2.3 加速级别

public enum GeometryAccelerationDegree {
    enumMild,    // 轻度:64×64×2 位光栅
    enumMedium,  // 中度:256×256×2 位光栅 + 线段四叉树
    enumHot      // 高度:1024×1024×2 位光栅 + 线段四叉树
}

选择建议

  • enumMild:内存有限或几何简单时
  • enumMedium:大多数场景的推荐选择
  • enumHot:大量查询且内存充足时

9.2.4 加速的开销

// 加速有预处理开销
// 只有在查询次数足够多时才值得

// 规则:
// - 少于 10 次查询:不值得加速
// - 10-100 次查询:enumMild
// - 100-1000 次查询:enumMedium
// - 超过 1000 次查询:enumHot

int expectedQueries = estimateQueryCount();
Geometry.GeometryAccelerationDegree degree;

if (expectedQueries < 10) {
    degree = null; // 不加速
} else if (expectedQueries < 100) {
    degree = Geometry.GeometryAccelerationDegree.enumMild;
} else if (expectedQueries < 1000) {
    degree = Geometry.GeometryAccelerationDegree.enumMedium;
} else {
    degree = Geometry.GeometryAccelerationDegree.enumHot;
}

9.3 空间索引

9.3.1 QuadTree

// 创建四叉树
Envelope2D extent = new Envelope2D();
extent.setCoords(0, 0, 1000, 1000);
int height = 8;  // 树高度,影响精度

QuadTree quadTree = new QuadTree(extent, height);

// 向四叉树添加元素
List<Geometry> geometries = getGeometries();
for (int i = 0; i < geometries.size(); i++) {
    Envelope2D env = new Envelope2D();
    geometries.get(i).queryEnvelope2D(env);
    
    // 插入元素,返回元素句柄
    int elementHandle = quadTree.insert(i, env);
}

// 查询与包围盒相交的元素
Envelope2D queryEnv = new Envelope2D();
queryEnv.setCoords(100, 100, 200, 200);

QuadTree.QuadTreeIterator iterator = quadTree.getIterator(queryEnv, 0.0);
int elementHandle;
while ((elementHandle = iterator.next()) != -1) {
    int elementIndex = quadTree.getElement(elementHandle);
    Geometry candidate = geometries.get(elementIndex);
    // 进行精确检查...
}

9.3.2 Envelope2DIntersector

用于批量包围盒相交检测:

// 创建相交器
Envelope2DIntersector intersector = new Envelope2DIntersector();

// 添加几何的包围盒
List<Geometry> geometries = getGeometries();
for (int i = 0; i < geometries.size(); i++) {
    Envelope2D env = new Envelope2D();
    geometries.get(i).queryEnvelope2D(env);
    intersector.addEnvelope(i, env);
}

// 启动相交检测
intersector.startIntersecting();

// 获取相交对
while (intersector.next()) {
    int handle1 = intersector.getHandle_1();
    int handle2 = intersector.getHandle_2();
    
    // 这两个几何的包围盒相交
    Geometry g1 = geometries.get(handle1);
    Geometry g2 = geometries.get(handle2);
    
    // 进行精确的空间关系检查
}

9.3.3 IntervalTree

用于一维区间的快速查询:

// 创建区间树
IntervalTreeImpl intervalTree = new IntervalTreeImpl();

// 添加区间
intervalTree.addInterval(0, 10);   // 区间 [0, 10]
intervalTree.addInterval(5, 15);   // 区间 [5, 15]
intervalTree.addInterval(12, 20);  // 区间 [12, 20]

// 查询与给定区间相交的区间
IntervalTreeImpl.IntervalTreeIteratorImpl iterator = 
    intervalTree.getIterator(8, 14);

int handle;
while ((handle = iterator.next()) != -1) {
    double min = intervalTree.getIntervalMin(handle);
    double max = intervalTree.getIntervalMax(handle);
    System.out.println("相交区间: [" + min + ", " + max + "]");
}

9.4 批量处理优化

9.4.1 使用 GeometryCursor

// 低效方式:逐个处理
List<Geometry> results = new ArrayList<>();
for (Geometry geom : geometries) {
    Geometry buffered = GeometryEngine.buffer(geom, sr, 10.0);
    results.add(buffered);
}

// 高效方式:使用 Cursor
SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geometries);
GeometryCursor resultCursor = OperatorBuffer.local().execute(
    inputCursor, sr, new double[]{10.0}, false, null);

List<Geometry> results2 = new ArrayList<>();
Geometry result;
while ((result = resultCursor.next()) != null) {
    results2.add(result);
}

9.4.2 自定义 GeometryCursor

/**
 * 从数据库流式读取几何的 Cursor
 */
public class DatabaseGeometryCursor extends GeometryCursor {
    private ResultSet resultSet;
    private int currentId = -1;
    
    public DatabaseGeometryCursor(ResultSet rs) {
        this.resultSet = rs;
    }
    
    @Override
    public Geometry next() {
        try {
            if (!resultSet.next()) {
                return null;
            }
            currentId = resultSet.getInt("id");
            byte[] wkb = resultSet.getBytes("geom");
            return OperatorImportFromWkb.local().execute(
                0, Geometry.Type.Unknown, ByteBuffer.wrap(wkb), null);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public int getGeometryID() {
        return currentId;
    }
}

9.4.3 并行处理

/**
 * 并行缓冲区计算
 */
public List<Geometry> parallelBuffer(List<Geometry> geometries, 
        SpatialReference sr, double distance) {
    
    return geometries.parallelStream()
        .map(geom -> GeometryEngine.buffer(geom, sr, distance))
        .collect(Collectors.toList());
}

/**
 * 使用 ForkJoinPool 进行并行空间查询
 */
public List<Geometry> parallelSpatialQuery(Geometry query, 
        List<Geometry> candidates, SpatialReference sr) {
    
    return candidates.parallelStream()
        .filter(geom -> !GeometryEngine.disjoint(query, geom, sr))
        .collect(Collectors.toList());
}

9.5 内存优化

9.5.1 对象复用

// 复用 Envelope2D
Envelope2D env = new Envelope2D();
for (Geometry geom : geometries) {
    geom.queryEnvelope2D(env);  // 复用 env
    // 使用 env...
}

// 复用 Point2D
Point2D pt = new Point2D();
Polyline line = getPolyline();
for (int i = 0; i < line.getPointCount(); i++) {
    line.getXY(i, pt);  // 复用 pt
    // 使用 pt...
}

9.5.2 内存估算

// 估算几何内存占用
long estimatedSize = geometry.estimateMemorySize();
System.out.println("估计内存: " + estimatedSize + " 字节");

// 批量估算
long totalSize = 0;
for (Geometry geom : geometries) {
    totalSize += geom.estimateMemorySize();
}
System.out.println("总内存: " + (totalSize / 1024 / 1024) + " MB");

9.5.3 流式处理大文件

/**
 * 流式处理大型 GeoJSON 文件
 */
public void processLargeGeoJsonFile(String filePath, 
        Consumer<Geometry> processor) throws IOException {
    
    try (BufferedReader reader = new BufferedReader(
            new FileReader(filePath))) {
        
        // 假设是 FeatureCollection,逐个处理 Feature
        // 实际实现需要更复杂的 JSON 流式解析
        
        String line;
        while ((line = reader.readLine()) != null) {
            if (line.contains("\"geometry\"")) {
                // 提取并解析几何
                String geomJson = extractGeometry(line);
                Geometry geom = parseGeoJson(geomJson);
                processor.accept(geom);
            }
        }
    }
}

9.6 算法优化

9.6.1 预过滤

/**
 * 使用包围盒预过滤优化空间查询
 */
public List<Geometry> optimizedSpatialQuery(Geometry query, 
        List<Geometry> candidates, SpatialReference sr) {
    
    // 获取查询几何的包围盒
    Envelope2D queryEnv = new Envelope2D();
    query.queryEnvelope2D(queryEnv);
    
    List<Geometry> results = new ArrayList<>();
    Envelope2D candidateEnv = new Envelope2D();
    
    for (Geometry candidate : candidates) {
        // 快速包围盒检查
        candidate.queryEnvelope2D(candidateEnv);
        if (!queryEnv.isIntersecting(candidateEnv)) {
            continue;  // 快速排除
        }
        
        // 精确检查
        if (!GeometryEngine.disjoint(query, candidate, sr)) {
            results.add(candidate);
        }
    }
    
    return results;
}

9.6.2 简化大几何

/**
 * 对大几何进行预简化以提高性能
 */
public Geometry optimizeForQuery(Geometry geometry, double tolerance) {
    if (geometry instanceof MultiVertexGeometry) {
        MultiVertexGeometry mvg = (MultiVertexGeometry) geometry;
        if (mvg.getPointCount() > 1000) {
            // 简化以减少顶点
            return OperatorGeneralize.local().execute(
                geometry, tolerance, true, null);
        }
    }
    return geometry;
}

9.6.3 分块处理

/**
 * 将大范围查询分块处理
 */
public List<Geometry> chunkedSpatialQuery(Geometry query, 
        List<Geometry> candidates, SpatialReference sr, int chunkSize) {
    
    List<Geometry> results = new ArrayList<>();
    
    // 分块处理
    for (int i = 0; i < candidates.size(); i += chunkSize) {
        int end = Math.min(i + chunkSize, candidates.size());
        List<Geometry> chunk = candidates.subList(i, end);
        
        // 处理块
        for (Geometry candidate : chunk) {
            if (!GeometryEngine.disjoint(query, candidate, sr)) {
                results.add(candidate);
            }
        }
        
        // 可选:显式触发 GC
        if (i % (chunkSize * 10) == 0) {
            System.gc();
        }
    }
    
    return results;
}

9.7 性能监控

9.7.1 操作计时

public class GeometryTimer {
    
    public static <T> T timed(String operation, Supplier<T> task) {
        long start = System.nanoTime();
        T result = task.get();
        long duration = System.nanoTime() - start;
        System.out.printf("%s: %.2f ms%n", operation, duration / 1_000_000.0);
        return result;
    }
    
    public static void timed(String operation, Runnable task) {
        long start = System.nanoTime();
        task.run();
        long duration = System.nanoTime() - start;
        System.out.printf("%s: %.2f ms%n", operation, duration / 1_000_000.0);
    }
}

// 使用
Geometry result = GeometryTimer.timed("Buffer", 
    () -> GeometryEngine.buffer(polygon, sr, 10.0));

9.7.2 内存监控

public class MemoryMonitor {
    
    public static void printMemoryUsage(String label) {
        Runtime runtime = Runtime.getRuntime();
        long used = runtime.totalMemory() - runtime.freeMemory();
        long max = runtime.maxMemory();
        
        System.out.printf("%s - 已用: %.1f MB, 最大: %.1f MB%n",
            label, used / 1024.0 / 1024.0, max / 1024.0 / 1024.0);
    }
    
    public static void forceGC() {
        System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

9.8 性能基准测试

9.8.1 基准测试框架

public class GeometryBenchmark {
    
    private static final int WARMUP_ITERATIONS = 5;
    private static final int MEASURE_ITERATIONS = 20;
    
    public static BenchmarkResult benchmark(String name, Runnable task) {
        // 预热
        for (int i = 0; i < WARMUP_ITERATIONS; i++) {
            task.run();
        }
        
        // 测量
        long[] times = new long[MEASURE_ITERATIONS];
        for (int i = 0; i < MEASURE_ITERATIONS; i++) {
            long start = System.nanoTime();
            task.run();
            times[i] = System.nanoTime() - start;
        }
        
        return new BenchmarkResult(name, times);
    }
    
    public static class BenchmarkResult {
        public final String name;
        public final double avgMs;
        public final double minMs;
        public final double maxMs;
        
        public BenchmarkResult(String name, long[] timesNs) {
            this.name = name;
            this.avgMs = Arrays.stream(timesNs).average().orElse(0) / 1_000_000.0;
            this.minMs = Arrays.stream(timesNs).min().orElse(0) / 1_000_000.0;
            this.maxMs = Arrays.stream(timesNs).max().orElse(0) / 1_000_000.0;
        }
        
        public void print() {
            System.out.printf("%s: avg=%.2fms, min=%.2fms, max=%.2fms%n",
                name, avgMs, minMs, maxMs);
        }
    }
}

9.8.2 常见操作基准

public class GeometryBenchmarks {
    
    public static void main(String[] args) {
        SpatialReference sr = SpatialReference.create(4326);
        Polygon polygon = createComplexPolygon(10000);  // 10000 顶点
        Point point = new Point(0.5, 0.5);
        
        // 缓冲区基准
        GeometryBenchmark.benchmark("Buffer", 
            () -> GeometryEngine.buffer(polygon, sr, 0.01)).print();
        
        // 包含判断基准
        GeometryBenchmark.benchmark("Contains", 
            () -> GeometryEngine.contains(polygon, point, sr)).print();
        
        // 简化基准
        GeometryBenchmark.benchmark("Simplify", 
            () -> GeometryEngine.simplify(polygon, sr)).print();
        
        // 加速后的包含判断
        OperatorContains op = OperatorContains.local();
        op.accelerateGeometry(polygon, sr, 
            Geometry.GeometryAccelerationDegree.enumMedium);
        
        GeometryBenchmark.benchmark("Contains (accelerated)", 
            () -> op.execute(polygon, point, sr, null)).print();
        
        Operator.deaccelerateGeometry(polygon);
    }
}

9.9 本章小结

本章详细介绍了 geometry-api-java 的性能优化:

  1. 几何加速:预处理几何以加速重复查询
  2. 空间索引:QuadTree、Envelope2DIntersector
  3. 批量处理:使用 GeometryCursor 流式处理
  4. 内存优化:对象复用、内存估算、流式处理
  5. 算法优化:预过滤、简化、分块处理
  6. 性能监控:计时和内存监控
  7. 基准测试:性能测量方法

优化建议总结

  • 批量操作使用 GeometryCursor
  • 重复查询使用几何加速
  • 大数据集使用空间索引
  • 始终使用包围盒预过滤
  • 监控内存使用避免 OOM
  • 进行基准测试验证优化效果

← 上一章:OGC兼容开发 | 下一章:大数据集成 →

posted @ 2025-12-03 15:15  我才是银古  阅读(5)  评论(0)    收藏  举报