使用Guava Table实现多维数据建模
在处理复杂业务场景时,常常需要对具有多个分类维度的数据进行组织和查询。虽然 Guava 的 Table 接口本质上是一个二维结构(由行键和列键共同定位值),但通过结合嵌套集合或层级映射的方式,我们可以有效模拟出三维甚至更高维度的数据模型。
利用嵌套表构建三维结构
一种常见的扩展方式是将 Table 的值类型设为另一个 Table 或 Map,从而形成层次化索引。例如,在分析销售数据时,可以将"时间"作为外层行键,"区域"作为列键,而每个单元格存储一个包含"指标-数值"映射的内层表。
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.junit.jupiter.api.Test;
import java.util.Map;
public class ThreeDimensionalDataModelTest {
@Test
public void buildThreeLevelIndex() {
// 外层表:日期 → 区域 → (指标 → 数值)
Table<String, String, Table<String, Integer>> timeRegionMetricTable = HashBasedTable.create();
// 构造北方区域的数据
Table<String, Integer> northMetrics = HashBasedTable.create();
northMetrics.put("Revenue", 9800);
northMetrics.put("Cost", 4200);
northMetrics.put("Orders", 156);
// 构造南方区域的数据
Table<String, Integer> southMetrics = HashBasedTable.create();
southMetrics.put("Revenue", 8700);
southMetrics.put("Cost", 3800);
southMetrics.put("Orders", 134);
// 填入外层表
timeRegionMetricTable.put("2024-11-15", "North", northMetrics);
timeRegionMetricTable.put("2024-11-15", "South", southMetrics);
// 查询指定维度组合的值
Table<String, Integer> targetData = timeRegionMetricTable.get("2024-11-15", "North");
Integer revenue = targetData.get("Revenue");
System.out.println("North region revenue on 2024-11-15: " + revenue); // 输出: 9800
}
}
上述代码中,我们通过两层 Table 实现了三个逻辑维度的索引路径:date → region → metric → value。这种结构适合固定维度顺序且访问模式明确的场景。
遍历多级数据集
当需要扫描全部记录时,可以通过逐层迭代完成。以下示例展示了如何遍历所有日期、区域及其对应的各项指标。
@Test
public void traverseHierarchicalData() {
Table<String, String, Table<String, Integer>> dataTable = HashBasedTable.create();
Table<String, Integer> data1 = HashBasedTable.create();
data1.put("Revenue", 7500);
data1.put("Profit", 2100);
dataTable.put("2024-11-10", "East", data1);
Table<String, Integer> data2 = HashBasedTable.create();
data2.put("Revenue", 6800);
data2.put("Profit", 1950);
dataTable.put("2024-11-10", "West", data2);
// 多重循环访问完整数据集
for (Map.Entry<String, Map<String, Table<String, Integer>>> rowEntry : dataTable.rowMap().entrySet()) {
String date = rowEntry.getKey();
System.out.println("Processing date: " + date);
for (Map.Entry<String, Table<String, Integer>> colEntry : rowEntry.getValue().entrySet()) {
String region = colEntry.getKey();
System.out.println(" Region: " + region);
Table<String, Integer> metrics = colEntry.getValue();
for (Map.Entry<String, Integer> metricEntry : metrics.cellSet()) {
System.out.printf(" %s: %d%n", metricEntry.getRowKey(), metricEntry.getValue());
}
}
}
}
该方法利用 rowMap() 获取按行组织的视图,并进一步展开每一项的列与内部数据,实现完整的深度遍历。
扩展至四维及以上结构
若需支持四个或更多维度(如年份、月份、地区、产品类别),可引入标准 Map 作为顶层容器,其值指向一个二维 Table,再嵌套另一层映射结构。
@Test
public void fourDimensionModel() {
// 四维模型:Year → Month → (Region × Metric → Value)
java.util.Map<String, Table<String, String, Table<String, Integer>>> yearSlice =
new java.util.HashMap<>();
// 初始化某月数据
Table<String, Integer> monthlyMetrics = HashBasedTable.create();
monthlyMetrics.put("Sales", 22000);
monthlyMetrics.put("Returns", 800);
Table<String, String, Table<String, Integer>> monthTable = HashBasedTable.create();
monthTable.put("North", "Q4", monthlyMetrics);
yearSlice.put("2024", monthTable);
// 查询:2024年北区第四季度的销售额
Table<String, Integer> q4Data = yearSlice.get("2024").get("North", "Q4");
Integer sales = q4Data.get("Sales");
System.out.println("2024 Q4 North Sales: " + sales); // 输出: 22000
}
这种方式虽牺牲了一定的统一性,但极大增强了灵活性,适用于维度动态变化或多层级聚合分析的应用。