일반적으로 Guava의 Table 인터페이스는 두 개의 키(행과 열)를 사용해 값을 매핑하는 2차원 데이터 구조로 이해할 수 있다. 하지만 실제 업무 로직에서 우리는 종종 세 번째, 혹은 그 이상의 차원이 필요한 경우가 있다. 예를 들어, 시간, 지역, 카테고리, 지표 등 여러 축으로 데이터를 조회해야 할 때다.
Guava는 기본적으로 3차원 이상의 Table을 제공하지 않지만, 기존의 Table과 자바 컬렉션을 조합함으로써 다차원 데이터 모델을 효과적으로 시뮬레이션할 수 있다.
1. 중첩된 Table을 통한 3차원 데이터 표현
가장 직관적인 방법은 Table<R, C, V>의 값(V) 자리에 또 다른 Table을 배치하는 것이다. 이를 통해 "행-열-층" 구조와 유사한 3차원 접근이 가능하다.
예를 들어, 날짜별, 지역별, 지표별(매출, 이익 등) 통계 데이터를 관리하고자 할 때 다음과 같은 구조를 고려할 수 있다:
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.junit.jupiter.api.Test;
import java.util.Map;
public class ThreeDimensionalDataTest {
@Test
public void createThreeDimensionalStructure() {
// 외부 Table: 날짜 → 지역 → (내부 Table)
Table<String, String, Table<String, Integer>> timeRegionMetrics = HashBasedTable.create();
// North 지역 데이터 구성
Table<String, Integer> northMetrics = HashBasedTable.create();
northMetrics.put("Revenue", 950);
northMetrics.put("Margin", 180);
// South 지역 데이터 구성
Table<String, Integer> southMetrics = HashBasedTable.create();
southMetrics.put("Revenue", 1100);
southMetrics.put("Margin", 250);
// 다중 차원에 데이터 삽입
timeRegionMetrics.put("2024-11-20", "North", northMetrics);
timeRegionMetrics.put("2024-11-20", "South", southMetrics);
// 특정 지표 조회: 2024-11-20, North 지역의 수익
Table<String, Integer> targetData = timeRegionMetrics.get("2024-11-20", "North");
Integer revenue = targetData.get("Revenue");
System.out.println("Revenue in North on 2024-11-20: " + revenue); // 출력: 950
Integer margin = targetData.get("Margin");
System.out.println("Profit Margin in North: " + margin); // 출력: 180
}
}
이 방식은 논리적으로 세 번의 키를 거쳐 최종 값을 도달하게 되며, 사실상 3차원 배열과 유사한 사용성을 제공한다.
2. 다중 차원 순회 및 필터링
복잡한 데이터셋에서는 전체를 순회하거나 조건에 맞는 부분집합을 추출하는 작업이 빈번하다. 중첩된 Table 구조에서도 rowKeySet(), columnKeySet(), cellSet() 등을 활용해 깊이 있는 탐색이 가능하다.
@Test
public void traverseMultiDimensionalData() {
Table<String, String, Table<String, Integer>> dataset = HashBasedTable.create();
Table<String, Integer> eastQ4 = HashBasedTable.create();
eastQ4.put("Sales", 3000);
eastQ4.put("Cost", 2200);
Table<String, Integer> westQ4 = HashBasedTable.create();
westQ4.put("Sales", 2800);
westQ4.put("Cost", 2000);
dataset.put("Q4", "East", eastQ4);
dataset.put("Q4", "West", westQ4);
// 모든 차원 순회
for (String period : dataset.rowKeySet()) {
System.out.println("Period: " + period);
for (String region : dataset.columnKeySet()) {
System.out.println(" Region: " + region);
Table<String, Integer> metrics = dataset.get(period, region);
for (Map.Entry<String, Integer> metric : metrics.entrySet()) {
System.out.println(" " + metric.getKey() + ": " + metric.getValue());
}
}
}
}
이러한 반복문 패턴은 대시보드 데이터 로딩, 보고서 생성 등大批량 데이터 처리 시 유용하다.
3. Map과 결합한 4차원 이상 확장
더 많은 차원이 필요할 경우, Table 자체를 맵의 값으로 중첩하면 된다. 예를 들어 연도, 분기, 지역, 지표로 구성된 4차원 데이터는 다음과 같이 표현할 수 있다.
@Test
public void fourDimensionalWithMap() {
// 연도 → (분기 → (지역 → 지표))
Map<String, Table<String, String, Table<String, Integer>>> multiYearData = new java.util.HashMap<>();
// 2024년 Q3 데이터 생성
Table<String, String, Table<String, Integer>> q3Data = HashBasedTable.create();
Table<String, Integer> centralMetrics = HashBasedTable.create();
centralMetrics.put("UnitsSold", 450);
centralMetrics.put("Returns", 23);
q3Data.put("Q3", "Central", centralMetrics);
// 2024년 데이터 저장
multiYearData.put("2024", q3Data);
// 2024년 Q3 Central 지역의 판매 수량 조회
Table<String, Integer> result = multiYearData.get("2024").get("Q3", "Central");
Integer units = result.get("UnitsSold");
System.out.println("Units Sold in Central during Q3 2024: " + units); // 출력: 450
}
이처럼 Map과 Table을 계층적으로 조합하면 제약 없이 N차원 데이터 모델을 구현할 수 있으며, 특히 재무 분석, BI 리포팅, IoT 센서 데이터 처리와 같은 도메인에서 유연한 데이터 관리가 가능해진다.
정리
Guava의 Table은 본질적으로 2차원이지만, 중첩과 합성 기법을 통해 3차원 이상의 데이터 표현이 현실적으로 가능하다. 핵심은 각 단계에서 의미 있는 키를 부여하고, 접근 로직을 명확히 설계하는 것이다. 이러한 패턴은 코드의 가독성과 유지보수성을 높이며, 복잡한 비즈니스 요구사항에도 대응할 수 있는 견고한 기반을 제공한다.