다차원 데이터의 효과적인 표현 방식
기본적으로 Guava Table은 행과 열의 교차를 기반으로 한 2차원 데이터 저장소로, 키 기반의 이중 인덱싱을 제공합니다. 하지만 실제 비즈니스 시나리오에서는 날짜, 지역, 제품군 등 세 개 이상의 차원을 동시에 고려해야 하는 경우가 많습니다. 이때 Table 자체는 다차원 구조를 직접 지원하지 않지만, Map과의 결합, 또는 Table 내부에 또 다른 Table을 중첩하여 유연하게 다차원 데이터를 모델링할 수 있습니다.
1. 중첩된 테이블로 3차원 구조 구성
예를 들어, 특정 일자별 각 지역의 매출 및 이익 데이터를 저장하려면, 날짜를 행 키, 지역을 열 키로 하여, 각 셀에 다시 Table<String, Integer> 형태의 지표 데이터를 넣는 방식이 가능합니다.
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.util.Map;
public class MultiLevelDataStorage {
private final Table<String, String, Table<String, Integer>> timeRegionMetrics;
public MultiLevelDataStorage() {
this.timeRegionMetrics = HashBasedTable.create();
}
public void addMetric(String date, String region, Map<String, Integer> metrics) {
Table<String, Integer> metricTable = HashBasedTable.create();
metrics.forEach(metricTable::put);
timeRegionMetrics.put(date, region, metricTable);
}
public Integer getMetricValue(String date, String region, String key) {
Table<String, Integer> regionData = timeRegionMetrics.get(date, region);
return regionData != null ? regionData.get(key) : null;
}
}
2. 다차원 탐색 및 반복 처리
모든 차원을 순회하거나 조건에 맞는 데이터를 추출하려면, 외부 rowKeySet()와 columnKeySet()를 사용해 계층적 접근이 필요합니다. 이는 복잡한 분석 작업에도 유용합니다.
public void printAllMetrics() {
for (String date : timeRegionMetrics.rowKeySet()) {
System.out.println("=== " + date + " ===");
for (String region : timeRegionMetrics.columnKeySet()) {
Table<String, Integer> data = timeRegionMetrics.get(date, region);
if (data != null) {
System.out.println(" Region: " + region);
data.entrySet().forEach(entry ->
System.out.println(" " + entry.getKey() + ": " + entry.getValue())
);
}
}
}
}
3. 더 높은 차원을 위한 맵 기반 중첩 구조
4차원 이상의 데이터를 관리하려면, Map<String, Table<...>> 형태로 계층을 확장하는 것이 효율적입니다. 예를 들어 연도 → 월 → 지역 → 지표라는 구조를 만들 수 있습니다.
import java.util.HashMap;
import java.util.Map;
public class FourDimensionalStorage {
private final Map<String, Table<String, String, Table<String, Integer>>> yearMonthRegionData;
public FourDimensionalStorage() {
this.yearMonthRegionData = new HashMap<>();
}
public void storeMonthlyData(String year, String month, String region, Map<String, Integer> values) {
Table<String, String, Table<String, Integer>> monthTable = HashBasedTable.create();
Table<String, Integer> regionTable = HashBasedTable.create();
values.forEach(regionTable::put);
monthTable.put(month, region, regionTable);
yearMonthRegionData.put(year, monthTable);
}
public Integer getSales(String year, String month, String region) {
Table<String, String, Table<String, Integer>> monthlyData = yearMonthRegionData.get(year);
if (monthlyData == null) return null;
Table<String, Integer> regionData = monthlyData.get(month, region);
return regionData != null ? regionData.get("Sales") : null;
}
}
이러한 패턴은 복잡한 데이터 분석, 보고서 생성, 혹은 시간 기반의 다차원 스냅샷 저장에 적합하며, Guava Table의 정교한 인덱싱 메커니즘을 활용하면서도 코드의 가독성과 유지보수성을 높일 수 있습니다.