Page cover

😢2024.07.26

일일 회고 3회차

할일 및 한일

경험 및 배움

회사 업무

영상 입력 처리 실패 해결

폐쇄망 환경의 기관에 납품되어 있는 시스템에서 영상을 입력하다가 실패했다는 얘기를 전달받았다. 두 Geometry 타입의 객체를 intersection 했을 때 self-intersection 이 되어 있는 경우 발생하는 에러였으며 에러 메시지는 다음과 같다.

Exception in thread "main" org.locationtech.jts.geom.TopologyException: found non-noded intersection between LINESTRING ( 120.65259965054962 31.285279777143465, 120.67974663557145 31.288251142146198 ) and LINESTRING ( 120.65273638403228 31.28526053475525, 120.6525866745773 31.28529679390149 ) [ (120.65263910444314, 31.2852840955574, NaN) ]
	at org.locationtech.jts.noding.FastNodingValidator.checkValid(FastNodingValidator.java:139)
	at org.locationtech.jts.geomgraph.EdgeNodingValidator.checkValid(EdgeNodingValidator.java:80)
	at org.locationtech.jts.geomgraph.EdgeNodingValidator.checkValid(EdgeNodingValidator.java:45)
	at org.locationtech.jts.operation.overlay.OverlayOp.computeOverlay(OverlayOp.java:229)
	at org.locationtech.jts.operation.overlay.OverlayOp.getResultGeometry(OverlayOp.java:181)
	at org.locationtech.jts.operation.overlay.OverlayOp.overlayOp(OverlayOp.java:84)
	at org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp.getResultGeometry(SnapIfNeededOverlayOp.java:75)
	at org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp.overlayOp(SnapIfNeededOverlayOp.java:37)
	at org.locationtech.jts.geom.GeometryOverlay.overlay(GeometryOverlay.java:76)
	at org.locationtech.jts.geom.GeometryOverlay.intersection(GeometryOverlay.java:119)
	at org.locationtech.jts.geom.Geometry.intersection(Geometry.java:1330)
	at org.jetbrains.kotlin.idea.scratch.generated.ScratchFileRunnerGenerated$ScratchFileRunnerGenerated.<init>(tmp.kt:15)
	at org.jetbrains.kotlin.idea.scratch.generated.ScratchFileRunnerGenerated.main(tmp.kt:20)

위 에러는 에러가 발생하는 케이스를 찾아서 테스트 코드를 작성하여 다음과 같이 해결하는 작업을 완료했었다.

chevron-rightbuffer(0.0) ??hashtag

코드에서 buffer(0.0)을 호출하는 부분은 JTS (Java Topology Suite) 라이브러리의 Geometry 객체에 대해 버퍼 연산을 수행하는 부분입니다. buffer() 메서드는 주어진 지오메트리 주변에 지정된 거리만큼의 버퍼 영역을 생성합니다. 이 경우, 버퍼 거리로 0.0이 지정되어 있습니다.

buffer(0.0)의 목적과 작동 원리:

  • 목적: buffer(0.0)을 사용하는 주된 목적은 지오메트리의 간소화(simplification) 또는 정규화(normalization)를 수행하여 작은 기하학적 불규칙성이나 자기 교차(self-intersections) 같은 문제를 해결하는 것입니다. 이러한 문제들은 종종 지오메트리를 처리하거나 공간 분석을 수행할 때 오류의 원인이 됩니다.

  • 작동 원리: buffer(0.0) 호출은 지오메트리에 0의 거리만큼 버퍼를 추가합니다. 즉, 실제로 지오메트리의 크기를 변경하지 않습니다. 그러나 이 과정에서 JTS 라이브러리는 지오메트리의 내부 구조를 다시 계산하게 됩니다. 이는 지오메트리의 불규칙성을 제거하고, 깨끗하고 정확한 지오메트리 표현을 확보하는 효과가 있습니다. 특히, 자기 교차나 매우 가까운 선분들이 서로 '스냅(snap)'되어 더 일관성 있는 구조로 정렬될 수 있습니다.

사용 사례:

  • 자기 교차 제거: 폴리곤이나 라인스트링이 자기 자신과 교차하는 경우, 이를 해결하기 위해 사용될 수 있습니다.

  • 작은 불규칙성 수정: 지오메트리의 경계에 매우 작은 불규칙성이 있을 때, 이를 평활화하여 보다 정규화된 형태로 만들 수 있습니다.

  • 로버스팅(robustness) 향상: 공간 연산 중 발생할 수 있는 작은 오류나 불안정성을 줄여, 연산의 안정성을 향상시킬 수 있습니다.

buffer(0.0)는 지오메트리를 변경하지 않는 것처럼 보이지만, 실제로는 내부적으로 지오메트리를 '정리'하고, 오류 가능성을 줄이는 데 도움이 됩니다. 그러나 모든 경우에 이 방법이 적합한 것은 아니며, 특히 큰 지오메트리 데이터셋을 처리할 때는 성능 저하를 초래할 수 있으므로 주의가 필요합니다.

하지만 동일하게 문제가 발생되어 기관으로 출장가신 개발자분에게 확인을 요청했으나 정확한 문제를 알아내지 못 하셨다. 어떤 데이터를 사용해서 호출했을 때 문제가 발생하는지 알 수 없으므로 다른 방법으로 문제 해결을 진행했다.

intersection을 수행하기 전에 Geometry가 유효하지 않을 경우 buffor(0.0)를 사용하여 값을 변환한 후에 intersection 하도록 수정했었다. 이 부분이 문제가 발생하므로 해당 기능을 PostGIS를 사용하여 처리되도록 변경을 진행했다.

다음 네이티브 쿼리를 사용하여 intersection을 수행하도록 변경한 후에 테스트 코드로 검증하고, 도커 이미지를 테스트 서버에 배포하여 영상을 넣었을 때 정상적으로 동작하는 것을 확인했다.

다음주 월요일에 어떤 데이터가 문제가 발생하는지 확인한 후에 해당 데이터가 네이티브 쿼리로 정상동작 하는지 검증하고 서버를 업데이트 할 예정이다.

개인 공부

Spring Events 학습

어제 해결하던 테스트 코드를 이어서 살펴봤다.

위와 같이 예외가 발생하며 이벤트가 수신됐으면 "Handling custom event." 가 출력되지만 해당 문자열이 출력되지 않았으므로 이벤트가 수신되지 않은 것을 알 수 있다. MockBean으로 AnnotationDrivenEventListener를 등록하니 실제 Bean이 아닌 MockBean으로 등록되어 Spring에서 이벤트를 전달하지 않는 것으로 판단된다.

다음과 같이 코드를 수정한 후에 실행해보니 정상적으로 "Handling custom event." 가 출력되는 것을 확인할 수 있었다.

Mock을 사용하여 테스트하는 것은 불가능할 것으로 판단되어 다른 방법으로 테스트 하는 것을 진행했다. Event를 테스트 하는 방법에 대해 찾아보던 중, 다음과 같이 @RecordApplicationEvents 와 ApplicationEvents를 활용하여 이벤트가 잘 발행되었는지 확인하는 방법을 찾았다. 이 방법을 사용하여 테스트를 수행해보니 테스트가 성공하는 것을 확인했다.

circle-info

@RecordApplicationEvents

Spring 테스트 컨텍스트 프레임워크에서 제공하는 애노테이션으로, 테스트 중 발생하는 이벤트를 기록한다. 이를 통해 테스트 중에 발생하는 이벤트를 쉽게 검증할 수 있다.

circle-info

ApplicationEvents

ApplicationEvents는 @RecordApplicationEvents 애노테이션과 함께 사용되며, 테스트 중 기록된 이벤트를 조회하고 검증하는 데 사용된다.

위 테스트는 이벤트 발행 로직은 검증할 수 있지만 이벤트 수신 로직을 검증할 수 없어서, 이벤트 수신 로직은 직접 이벤트를 넣어서 호출하는 형태로 테스트를 해야 할 것 같다.

개선 및 목표

  • 다음주 월요일에 기관에 출장가서 잘 해결할 수 있도록 코드 준비 및 해결 가이드 정리 필요

  • Spring Events 튜토리얼 완료하기

Last updated