本文由做者王改革受權網易雲社區發佈。前端
1、背景和實現目標後端
在開發嚴選數據產品(大麥商品數據運營平臺和移動數據工做臺VIPAPP)的時候,最多的業務場景就是對實時和離線數據模型中查詢、處理、統一數據結構返回給前端。因此在開發的同時也一直在思考如何將這些類似的數據處理流程統一塊兒來,更關注數據指標自己。緩存
開發中常常遇到的幾個問題是:數據結構
數據查詢鏈接管理分散 併發
模型查詢結果緩存分散 框架
對於模型數據查詢結果缺乏統一的數據變換模塊支持,每日產出的實時數據指標以及離線數據指標通過後端邏輯作接口返回的時候,會有大量的get、set操做,若是同時須要計算指標同比、環比、佔比、對比值等複合指標時,就會充斥大量的重複髒代碼。spa
依賴的數據服務對存儲在MySQL、GP、Kylin、HBase等存儲引擎的數據模型暫時沒有多模型的鏈接支持。線程
因此針對以上問題,咱們但願可以設計出可以在數據產品中使用的通用指標查詢計算模塊(DPRequestManager),主要實現以下目標:設計
管理數據模型查詢,封裝對於 統一查詢服務(DQS)、MySQL等查詢請求,提供查詢鏈接池。excel
提供靈活的數據變換能力
可以經過配置對相應指標(包括指標值、環比、佔比、同比等)自動計算,減小過多的冗餘代碼。
支持數據對象映射,減小頻繁的取值和賦值操做
支持查詢級別的緩存(能夠根據系統需求自定義緩存時間、能夠設定緩存條件),減小對依賴服務的查詢壓力。
2、通用指標查詢計算模塊(DPRequestManager)組織結構
紅色部分的併發查詢器負責管理數據產品與底層數據查詢存儲引擎的鏈接,統一管理各類數據查詢。DPRequestManager會做爲數據產品模型查詢的統一入口,封裝底層數據模型存儲引擎,爲數據查詢提供線程池服務。同時此部分還提供模型退化的能力。
統一緩存模塊負責對數據查詢作條件緩存,對於每日數據未產出或者其餘狀況能夠對查詢結果約定一些必要條件來決定是否緩存查詢結果(緩存級別爲請求級別)。
橙色部分的數據變換模塊能夠對DQS獲取的多表數據進行靈活數據變換
配置模塊能夠對數據關係映射以及相應的複合指標計算作相應配置,統一輩子成結果,減小冗餘代碼
3、數據變換模塊支持操做
對於從模型存儲引擎查詢結果處理成List<Map<String, Object>>結構的,並提供提供如下數據變換操做。
命名規則:模塊內部將使用數據dataKey存放查詢處理結果,dateKey對應的list結果能夠類比excel行列表,其中的列名對應Map結構的key值。
如今主要提供以下數據操做:
compose({"group_id", "group_name"}, "result_A", "resultB")
rename ("dk", {"sale_amount_day", "sale_qty_day"}, {"sale_amount, sale_qty"})
group(row -> new StringJoiner("_").add(row.get("week").add(row.get("group_id")))
aggregation({"week", "group_id", "group_name"}, {sum("sale_amount"), sum("sale_qty")})
4、指標計算配置以及對象關係映射
這個地方主要解決兩個問題:
模型數據查詢結果到數據對象的映射,減小頻繁的取值和賦值,如今通用的ORM框架都能解決這個問題,DPRequestManager爲了配合複合指標計算經過反射來實現數據對象映射部分。
映射過程當中的指標計算(指標表達式計算、環比、同比、佔比等複合指標的計算)
DPRequestManager主要是經過兩個配置來配合解決複合指標計算的問題。
第一個配置主要是定義數據對象映射的數據篩選規則(目標數據集合、環比數據集合、佔比數據集合等)
{
"clazz": StockDTO.class, "useDate": "2018-12-07", // 指定目標值日期 "hbDate": "2018-12-06", // 指定環比日期 "hbKey": "group_id", // 計算環比使用 "filterKey": "", // 過濾器 "filterValue": ""
}
第二個配置是數據對象DTO的配置(經過註解對複合指標計算進行配置定義)
DTO配置主要使用了三個註解,@FromDO,@FunctionDO,@IgnoreAssign
@From 定義簡單按key取值
@FunctionDO定義複合指標計算規則(hb,tb,zb,avg,sum等)
@IgnoreAssign 對象映射是字段忽略
同時支持定義的複合指標對象的指標計算賦值。
@Datapublic class StockSingleVO extends BaseVO { // 簡單取值,默認駝峯轉下劃線取字段group_id
private Long groupId; @FromDO("'商品組:'+group_name") private String groupName; // 簡單取值,直接在庫量 @FromDO("stock_cnt_zhuzhan_1d") private Number stockCnt; // 環比,對在庫量字段計算環比 @FromDO("stock_cnt_zhuzhan_1d") @FunctionDO(types = FunctionTypeEnum.HB) private Number stockCntHB; // 簡單取值,計算在庫+在途量 @FromDO(value = "stock_cnt_zhuzhan_1d+onway_cnt_zhuzhan_1d") private Number stockAndOnwayCnt; // 環比計算,計算在庫+在途的環比 @FromDO(value = "stock_cnt_zhuzhan_1d+onway_cnt_zhuzhan_1d") @FunctionDO(types = FunctionTypeEnum.HB) private Number stockAndOnwayCntHB; // 佔比計算 @FromDO(value = "stock_cnt_zhuzhan_1d+onway_cnt_zhuzhan_1d") @FunctionDO(types = FunctionTypeEnum.ZB) private Number stockAndOnwayCntZB;
}
數據過濾規則配置和數據對象中定義的複合指標計算配置一塊兒支持數據對象映射,這樣能夠減小大量重複賦值取值以及手動計算複合指標的工做。同時配合使用數據變換模塊和數據對象映射可以釋放更大的靈活性,將數據變換模塊、數據對象映射、複合指標計算模塊解耦。
模塊查詢代碼示例:
/**
*/EngineRequest request1 = new EngineRequest(EngineType.DQS, condition1, EngineResultTypeEnum.LIST); // 構造查詢請求1EngineRequest request2 = new EngineRequest(EngineType.DQS, condition2, EngineResultTypeEnum.LIST); // 構造查詢請求2// 構造配置1(數據過濾配置 -> 配置目標日期、環比日期、計算環比目標分組key)EngineConvertConfig config = new EngineConvertConfig<>(StockSingleVO.class, "2018-12-07", "group_id", null, null);
config.setHbDate("2018-12-06");
Listlist = requestEngineManager.initThreadLocal()
.addRequest(dk1, request1) .addRequest(dk2, request2) .execute() .compose(true, Arrays.asList("date_id", "group_id"), dk_new, dk1, dk2) // 請求結果鏈接 .converToList(dk_new, config); // 數據對象映射// 前端數據結構組裝SmartQueryResult result = BaseVO.assembleResult(list, StockSingleVO.class);
5、總結
數據產品中不少通用的部分能夠抽出來做爲單獨模塊或者服務。文中介紹的複合指標查詢模塊已經在大麥商品數據運營平臺中實踐,它把數據產品指標查詢、計算以及對象映射等公共部分提取出來,有效的提升開發效率並可以下降開發成本。
文章來源: 網易雲社區