計數系統設計

wxwall發表於2024-10-23

在營銷的場景裡有三要素

  1. 使用者
  2. 商品
  3. 優惠

在這三個要素裡,再加一些如時間,數量,頻次等變數,會演化出各種組合,使得業務變得非常靈活。各業務線為了滿足業務,一般都會各自實現,且多數情況下都會重複實現,而且實現起來各地方都會產生交叉配置,交叉互斥的問題。在觀察到這些問題後,總結並嘗試用一個計數頻次中介軟體形態的系統統一解決。一是解決了複雜度、重複建設;二是統一處理後,資料層面上將整體打通,對於使用者監控、風控、特徵、行為上提供完整資料。

在電商的系統中,有商品、使用者、優惠三種要素。這三種要素分別在數量,時間,頻次上又有多維度的分類。
如商品限量100份(數量)對使用者每天(時間)每人購買限量2份(頻次),按這種規律下,使用者使用優惠也同樣遵循這種規則,即
優惠券總數100張(數量),使用者每場(時間)可使用1張(頻次)
抽獎優惠也一樣,即
優惠總數100張,使用者每天(時間)可領取1張(頻次)
發放優惠也一樣,即
優惠總額100元,使用者每天(時間)可優惠1次(頻次)


分類法

  1. 按主體,維度分類
主體\維度 數量 時間 頻次
商品 總數 指定週期,天,小時,周 不限,1份,多份
使用者 總數 指定週期,天,小時,周 不限,1份,多份
優惠 總數 指定週期,天,小時,周 不限,1份,多份
活動 總數 指定週期,天,小時,周 不限,1份,多份

按上面這個分類,主體會變,維度會變,先設計領域模型,分別為實體(entity);維度(dimensions);實體維度關係(entityDimensionsRel),關係領域將表示,主體將擁有多個維度,並在多個維度中設定維度值,如商品每天限購1份,那麼將在entityDimensionsRel中的limit_value中設定1,time_interval設定為1天

領域模型

資料模型

資料庫表模型

  1. 主體表 (Entities)
  • EntityID: 主鍵,唯一標識某個主體(如商品、優惠、活動等)
  • EntityType: 主體型別(如商品、優惠、抽獎等)
  • EntityName: 主體名稱
CREATE TABLE Entities (
    EntityID INT PRIMARY KEY,
    EntityType VARCHAR(50),
    EntityName VARCHAR(100)
);
  1. 維度定義表 (Dimensions)
  • DimensionID: 主鍵,唯一標識某個維度(如數量、時間、頻次)
  • DimensionName: 維度名稱(如“數量”、“時間”、“頻次”)
  • DimensionType: 維度型別(如整數、日期、時間區間等)
CREATE TABLE Dimensions (
    DimensionID INT PRIMARY KEY,
    DimensionName VARCHAR(50),
    DimensionType VARCHAR(50)
);
  1. 主體-維度關係表 (EntityDimensions)
  • EntityDimensionID: 主鍵,唯一標識某個主體-維度關係
  • EntityID: 外來鍵,關聯到Entities表
  • DimensionID: 外來鍵,關聯到Dimensions表
  • LimitValue: 該維度的限制值(如限量、限次等)
  • TimeInterval: 時間間隔(如每天,每場活動等),適用於時間維度
CREATE TABLE EntityDimensions (
    EntityDimensionID INT PRIMARY KEY,
    EntityID INT,
    DimensionID INT,
    LimitValue INT,
    TimeInterval VARCHAR(50),
    FOREIGN KEY (EntityID) REFERENCES Entities(EntityID),
    FOREIGN KEY (DimensionID) REFERENCES Dimensions(DimensionID)
);

上面這些表可以完整記錄主體在各維度的限制值。還需要一張實時記錄主體資料在各維度的過程資料

  1. 例項資料記錄表 (EntityDimensionRecords)
  • RecordID: 主鍵,唯一標識某條記錄
  • EntityID: 外來鍵,關聯到Entities表
  • DimensionID: 外來鍵,關聯到Dimensions表
  • UserID: 外來鍵,關聯到使用者表(適用時)
  • Value: 在該維度上記錄的數值
  • RecordDate: 記錄的日期或時間。
CREATE TABLE EntityDimensionRecords (
    RecordID INT PRIMARY KEY,
    EntityID INT,
    DimensionID INT,
    UserID INT,
    Value INT,
    RecordDate DATETIME,
    FOREIGN KEY (EntityID) REFERENCES Entities(EntityID),
    FOREIGN KEY (DimensionID) REFERENCES Dimensions(DimensionID)
);


資料流轉

樣例1

使用者參與大轉盤活動,活動週期內只能抽一次獎

主體:大轉盤活動

維度:時間,計數

關係:限制值(一次);限制時間(活動週期);

簡單填入資料,業務就可以滿足了。

現在又有新的業務需求,即這個活動週期為1個月,使用者每天都要能參與一次,現有的表模型就不支援了!

關係表(EntityDimensions)的時間欄位TimeInterval是個varchar,表示1天、1小時等列舉值是可以,如果表示時間段,每天等帶頻次的複雜時間是不夠的,所以,最好的辦法之一就是將時間維度拆出一張表

CREATE TABLE TimePeriods (
    TimePeriodID INT PRIMARY KEY,
    PeriodName VARCHAR(50),       
    TimeInterval VARCHAR(50),     -- 時間週期(每天、每小時、每半小時、每分鐘)
    StartTime TIME,               -- 時間段開始時間
    EndTime TIME                  -- 時間段結束時間
);

有了這張表後,就可以表示週期時間段的計數關係了。

有了這張表後,業務在查詢EntityDimensionRecords,就知道這條記錄的週期,開始時間結束時間。

如果時間頻次TimeInterval是天,當前時間為2022-12-12時,EntityDimensionRecords.RecordDate值為2022-12-11時,那麼EntityDimensionRecords需要重新生成一條記錄,並且RecordDate值為2022-12-12;

越往深入,能夠列舉出的維度是有限的,在大的方向上,每一個維度也可以拆分出一個領域也是可行的。因為維度值不一樣,單純用維度一個變數有點滿足不了需求,如時間維度和數量維度,維度值用一個變數就表示不了,時間範圍最少需要2個欄位。所以在不同的業務發展時期,只有當時最合適的設計,沒有永遠對的設計。在考慮擴充套件性的同時,也需要考慮研發成本。


如果以後有需求對計數的方式有變化,比如一次計數消耗2次機會,那相應的,再在EntityDimensions.LimitValue欄位上做一個新表來表示計數的複雜方式。萬變不離其宗,好的設計一定是支援業務慢慢成長起來的。糟糕的設計是不停的妥協設計,隨著時間推移開發和維護將會越來越困難!

相關文章