Project

General

Profile

Actions

개선(improvement) #2626

open

개선(improvement) #2310: [BE] Optimize Memory, CPU API search list flight

[BE] CRITICAL-2: O(n³) Nested Loop Anti-Pattern in getForFilter()

Added by Dante Le 3 months ago. Updated 3 months ago.

Status:
신규(New)
Priority:
긴급(Emergency)
Assignee:
Start date:
Due date:
12/15/2025 (about 3 months late)
% Done:

0%

Estimated time:
8.00 h
Part:
Build env.:

Description

Parent Issue: #2310 [BE] Optimize Memory, CPU API search list flight

  1. Summary

Triple nested loop structure in `getForFilter()` method causing O(n³) complexity, with inner linear searches escalating to O(n⁴) performance.

  1. Location

File: `web-api/src/main/java/com/ohmy/api/service/flight/FlightListItineraryService.java`
Method: `getForFilter()`
Lines: 134-618 (485 lines)

  1. Problem Code Pattern
    // Lines 169-600: Triple nested loop structure
    for (JsonNode fareJsonNode : responseJsonNode.at("/result/combinedFares")) {         // Loop 1: fares
        for (int itineraryIndex = 0; itineraryIndex < itineraryIndexes.size(); ...) {    // Loop 2: itineraries
            for (JsonNode segmentJsonNode : ...) {                                        // Loop 3: segments
                // Lines 290-294: Linear search INSIDE triple loop
                ObjectNode cabinClassJsonNode = StreamSupport.stream(cabinClassArrayNode.spliterator(), false)
                        .filter(x -> x.get("code").textValue().equals(cabinClassCode))
                        .findFirst()
                        .map(x -> (ObjectNode) x)
                        .orElse(null);
            }
        }
    }
    
  1. Performance Impact

Computational Complexity:
- Base iterations: 500 fares × 3 itineraries × 10 segments = 15,000 iterations
- With inner linear searches: O(n⁴) = 45M+ operations in worst case
- Causes significant CPU spikes under concurrent load

Real-world Impact:
- Contributes to memory exhaustion under ~50 concurrent requests
- Part of the 1.5 GB peak memory allocation issue
- Slows response time proportionally to result set size

  1. Required Fix
  1. 1. Pre-compute Lookup Maps
    Replace linear searches with O(1) HashMap lookups:
    - Cabin classes map: `Map<String, ObjectNode> cabinClassByCode`
    - Airlines map: `Map<String, JsonNode> airlineByCode`
    - Alliances map: `Map<String, JsonNode> allianceByCode`
  1. 2. Extract to Smaller Methods
    Break down 485-line method into focused functions:
    - `buildFilterContext()` - Pre-build all lookup maps
    - `filterFaresByItinerary()` - Single responsibility per iteration level
    - `matchSegmentCriteria()` - Segment-level filtering logic
  1. 3. Consider Caching
    Cache filter results by fare signature if filters don't change between requests.
  1. Acceptance Criteria

MUST maintain 100% identical API response (no logic changes)
✅ Reduce computational complexity from O(n⁴) to O(n²) or better
✅ Pre-build lookup maps once per request
✅ Verify performance improvement with load testing
✅ Measure CPU reduction under 50 concurrent requests

  1. Constraints

⚠️ NO LOGIC CHANGES ALLOWED - This is a performance optimization only
- Do not modify filter behavior or output format
- Do not alter calculation results
- API response must remain byte-for-byte identical

  1. Related Issues

- #2610 - CRITICAL-1: Excessive JsonNode Traversal (Fixed ✅)
- #2611 - AtomicReference Memory Retention (Fixed ✅)
- Part of Phase 3: Major Refactoring in optimization roadmap

  1. Reference

See `docs/flight-list-itinerary/VERIFIED_ISSUES.md` - CRITICAL-2 section for complete analysis.

Actions

Also available in: Atom PDF

Add picture from clipboard (Maximum size: 50 MB)