一、事實表分類
1. 以粒度劃分
(1) 事務事實表(Transaction Grain Fact Table)
一條記錄代表了業務系統中的一個事件。事務出現後,就會在事實中出現一條記錄。以訂單域舉例:下單是一個事實;付款是一個事實;退款是一個事實。
(2) 週期快照事實表(Periodic Snapshot Grain Fact Table)
記錄指定週期內一些聚集事務值或者度量狀態。如:庫存日快照事實表
(3) 累積快照事實表(Accumulating Snapshot Grain Fact Table)
用於研究業務過程中各里程碑事件之間的時間間隔,一般會用一個字段記錄最後更新時間。如:訂單各種狀態的開始結束時間。
2. 以用途劃分
(1)原子事實表(Atom Fact Table)
保存最細粒度數據的事實表
(2)聚集事實表(Aggregated Fact Table)
原子事實表上的彙總,也稱彙總事實表。通過彙總原始數據來提升下游查詢的效率
聚集原則:
不跨越數據域:數據域是對數據分類的高層抽象,如訂單域、用戶域,不同數據域的數據不要聚集在一起
不跨越事實:對於橫向鑽取,是針對多個事實基於一致的維度進行分析,即融合表,是一種導出模式而不是聚集模式。
(3)合併事實表(Consolidated Fact Table)
位於不同事實表中處於相同粒度的事實進行組合建模而成的一種事實表。即新建立一個事實表,它的維度是兩個或多個事實表的相同維度的集合;事實是幾個事實表中感興趣的事實。
二、IOT場景下用電量事實表
需求:計算電錶每次上報間隙的用電量。
架構:Kafka + Flink + HBASE
事實表類型:累計快照事實表
事實表設計:
字段名 | 類型 | 備註 |
rowkey | String | md5 哈希 meter_id + 開始時間戳 |
meter_id | String | 電錶 id |
date_sid | String | 日期維表代理鍵 |
start_time | String | 起始時間 |
start_poi_data | String | 起始讀數 |
end_time | String | 結束時間 |
end_poi_data | String | 結束讀數 |
amount | String | 用電量 |
Flink實現:
利用數量滑動窗口提取相鄰兩次的數據 countWindow(2L, 1L)...
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
FlinkKafkaConsumer011<Meter> source = ...
DataStream<Meter> input = env.addSource(source).keyBy("meterId").countWindow(2L, 1L).process(new MyProcessFunction());
input.writeUsingOutputFormat(new HBaseOutputFormat());
...
public class MyProcessFunction extends ProcessWindowFunction<Meter, EnergyFact, Tuple, GlobalWindow> {
private static final long serialVersionUID = -3225885887285163148L;
@Override
public void process(Tuple key, ProcessWindowFunction<Meter, EnergyFact, Tuple, GlobalWindow>.Context context,
Iterable<Meter> elements, Collector<EnergyFact> out) throws Exception {
...
EnergyFact fact = new EnergyFact();
...
out.collect(fact);
}
}
public abstract class HBaseOutputFormat<T> implements OutputFormat<T> {
...
@Override
public void writeRecord(T record) throws IOException {
org.apache.hadoop.conf.Configuration conf = HBaseConfiguration.create();
conn = ConnectionFactory.createConnection(conf);
table = conn.getTable(TableName.valueOf(tableName));
byte[] rowkey = ...
Put put = new Put(rowkey);
...
table.put(put);
}
}
三、注意事項:
1. 創建HBASE表需要預分區,有效提高讀寫性能
2. HBASE表的RowKey利用md5哈希,均勻分佈在不同的分區。
3. Flink計算做好異常處理,避免錯誤數據影響計算結果。
參考博文: