From 41952ff1ca8cae4b4c8558c61aee6f954672178d Mon Sep 17 00:00:00 2001 From: YaroslavVlasenko Date: Fri, 18 Sep 2026 20:23:34 +0300 Subject: [PATCH] PERF: Cache computed WKT areas to improve performance Introduced a caching mechanism to store pre-computed areas for WKT strings, ensuring each area is calculated only once. Added tests to verify caching behavior and maintain functionality consistency. This change reduces redundant computations, enhancing overall efficiency. --- .../examples/console/areas/Calculations.java | 41 +++++++++++++++++-- .../console/areas/CalculationsTest.java | 12 ++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/console/src/main/java/fiftyone/ipintelligence/examples/console/areas/Calculations.java b/console/src/main/java/fiftyone/ipintelligence/examples/console/areas/Calculations.java index cd1053b..b3499f4 100644 --- a/console/src/main/java/fiftyone/ipintelligence/examples/console/areas/Calculations.java +++ b/console/src/main/java/fiftyone/ipintelligence/examples/console/areas/Calculations.java @@ -34,6 +34,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Used to work out the common values for areas in the examples. @@ -55,6 +57,23 @@ public class Calculations { private static final ThreadLocal wktReader = ThreadLocal.withInitial(WKTReader::new); + /** + * Parsed geometry and area in square meters for each WKT string seen, + * so that an area is only worked out once. + */ + private static final Map wktAreas = + new ConcurrentHashMap<>(); + + private static class CachedArea { + final Geometry geo; + final double area; + + CachedArea(Geometry geo, double area) { + this.geo = geo; + this.area = area; + } + } + /** * A grid of latitude and longitude rectangles. Used to work out the * geographic area using individual polygons no larger than 1 unit of @@ -79,13 +98,29 @@ public static Result getAreas( String wkt, double latitude, double longitude) throws Exception { - Geometry geo = wktReader.get().read(wkt); - if (geo != null) { - return getAreas(geo, latitude, longitude); + CachedArea cached = wktAreas.get(wkt); + if (cached == null) { + Geometry geo = wktReader.get().read(wkt); + cached = new CachedArea(geo, geo == null ? 0 : getAreas(geo)); + wktAreas.put(wkt, cached); + } + if (cached.geo != null) { + return new Result( + (int) Math.round(cached.area / 1_000_000), + cached.geo.getNumGeometries(), + cached.geo.contains(cached.geo.getFactory().createPoint( + new Coordinate(longitude, latitude)))); } return new Result(0, 0, false); } + /** + * Number of WKT strings with a cached area. + */ + public static int getCachedWktCount() { + return wktAreas.size(); + } + /** * Returns the result for the geometric area, and geographic point. * @param geo geometric area(s) diff --git a/console/src/test/java/fiftyone/ipintelligence/examples/console/areas/CalculationsTest.java b/console/src/test/java/fiftyone/ipintelligence/examples/console/areas/CalculationsTest.java index 41503c0..8ebeda2 100644 --- a/console/src/test/java/fiftyone/ipintelligence/examples/console/areas/CalculationsTest.java +++ b/console/src/test/java/fiftyone/ipintelligence/examples/console/areas/CalculationsTest.java @@ -144,6 +144,18 @@ public void testPolygonSplitByGridCell() throws Exception { Calculations.getAreas(shape, 0, 0).getSquareKms()); } + @Test + public void testWktAreaIsCached() throws Exception { + String wkt = createRectangle(10, 51, 1).toText(); + + Calculations.getAreas(wkt, 0, 0); + int first = Calculations.getCachedWktCount(); + Result again = Calculations.getAreas(wkt, 51.5, 10.5); + + assertEquals(first, Calculations.getCachedWktCount()); + assertTrue(again.getContains()); + } + @Test public void testContains() throws Exception { Result result = Calculations.getAreas(