개선(improvement) #2626
open개선(improvement) #2310: [BE] Optimize Memory, CPU API search list flight
[BE] CRITICAL-2: O(n³) Nested Loop Anti-Pattern in getForFilter()
0%
Description
Parent Issue: #2310 [BE] Optimize Memory, CPU API search list flight
- Summary
Triple nested loop structure in `getForFilter()` method causing O(n³) complexity, with inner linear searches escalating to O(n⁴) performance.
- Location
File: `web-api/src/main/java/com/ohmy/api/service/flight/FlightListItineraryService.java`
Method: `getForFilter()`
Lines: 134-618 (485 lines)
- 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); } } }
- 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
- Required Fix
- 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`
- 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
- 3. Consider Caching
Cache filter results by fare signature if filters don't change between requests.
- 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
- 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
- Related Issues
- #2610 - CRITICAL-1: Excessive JsonNode Traversal (Fixed ✅)
- #2611 - AtomicReference Memory Retention (Fixed ✅)
- Part of Phase 3: Major Refactoring in optimization roadmap
- Reference
See `docs/flight-list-itinerary/VERIFIED_ISSUES.md` - CRITICAL-2 section for complete analysis.