動態

詳情 返回 返回

向量數據庫在 UGC 社區個性化推薦的落地指南 - 動態 詳情

作者:Gundy

1. 場景與目標

UGC 社區典型特點:內容量大、更新快、長尾重。推薦系統要同時兼顧“眼下的即時興趣”和“用户的穩定偏好”,並在一次請求內完成多路候選召回與融合,保證毫秒級延遲。 本文給出一套雙向量用户興趣 + 一次 SQL 多路召回的實踐方案,數據庫層使用 OceanBase 原生向量能力,結構化與向量同庫,避免“兩庫同步/一致性坑”。


2. 為什麼選 OceanBase(直説三點)

一體化:結構化表 + VECTOR 列 + HNSW/IVF 向量索引在同一庫裏,天然支持事務一致性(更新瀏覽計數與短期向量可放在一個事務裏)。

兼容 MySQL 技術棧:接入/運維成本低,遷移平滑。

分佈式彈性:內容庫增長和 QPS 抖動時,水平擴展更從容。


3. 表結構(貼近你 PPT 的建模)

內容表(帖子/短視頻等)

CREATE TABLE posts (
  post_id        BIGINTPRIMARY KEY,
  author_id      BIGINT,
  title          VARCHAR(255),
  content        TEXT,
  created_at     DATETIME,
  status         TINYINT DEFAULT1,          -- 1上線
  pop_7d         FLOATDEFAULT0,            -- 近7日人氣
  content_vector VECTOR(768),                -- 原生向量
  VECTOR KEY idx_vec (content_vector)
    WITH (DISTANCE = COSINE, TYPE = HNSW, M=16, EF_CONSTRUCTION=200, EF_SEARCH=64)
);

用户表(雙向量:短期 + 長期)

CREATE TABLE users (
  user_id            BIGINT PRIMARY KEY,
  short_term_vector  VECTOR(768),  -- 即時興趣(秒級更新)
  long_term_vector   VECTOR(768),  -- 穩定偏好(天級/小時級更新)
  region             VARCHAR(32),
  updated_at         DATETIME
);

行為表(去重/特徵)

CREATE TABLE user_actions (
  user_id  BIGINT,
  post_id  BIGINT,
  action   ENUM('view','like','collect','comment','share'),
  ts       DATETIME,
  PRIMARY KEY(user_id, post_id, action, ts)
);

4. 雙向量興趣:怎麼產出 & 怎麼更新

4.1 訓練與產出(簡述)

長期向量:雙塔/對比學習,將歷史多天行為聚合(mean/attention pooling),日更或小時更。

短期向量:會話級序列(最近 N 次曝光/點擊)用輕量 Transformer/SASRec 產出,實時/秒級更新

4.2 在線更新

同一事務中更新瀏覽計數與短期向量,避免“計數+畫像不同步”:

BEGIN;
UPDATE posts SET view_count = view_count + 1 WHERE post_id = ?;
UPDATE users SET short_term_vector = ? WHERE user_id = ?;
COMMIT;

短期向量的在線融合

def update_short_term_vector(user_id, post_vec, action):
    w = {'view':0.1, 'like':0.3, 'collect':0.5}.get(action, 0.1)
    new_vec = 0.85 * current_short_vec(user_id) + 0.15 * w * post_vec
    sql("UPDATE users SET short_term_vector=? WHERE user_id=?", [new_vec, user_id])

直觀點:短期追新,長期守穩;兩者同時存在才不會“越推越窄”或“越推越慢”。


5. 一次查詢,多路召回(核心 SQL)

目標:一次請求同時召回“短期興趣近鄰”“長期興趣近鄰”,併疊加新鮮度人氣,再統一排序。

關鍵點:強過濾先行(上架、時間窗、地域/類目等),不做過濾等着 P95 爆炸。

-- 取出用户雙向量
WITH user_vectors AS (
SELECT short_term_vector AS svec, long_term_vector AS lvec
FROM users WHERE user_id = :uid
),
-- 路1:短期興趣召回(響應快,抓當前關注)
short_pool AS (
SELECT p.post_id, p.title,
         COSINE_SIMILARITY(p.content_vector, uv.svec) AS sim,
         p.created_at, p.pop_7d, 'short'AS src
FROM posts p, user_vectors uv
WHERE p.status=1
    AND p.created_at > DATE_SUB(NOW(), INTERVAL7DAY)           -- 新鮮度強過濾
    ANDNOTEXISTS (SELECT1FROM user_actions ua
                    WHERE ua.user_id=:uid AND ua.post_id=p.post_id) -- 去已看
ORDERBY p.content_vector <-> uv.svec
  LIMIT 200
),
-- 路2:長期興趣召回(穩定偏好)
long_pool AS (
SELECT p.post_id, p.title,
         COSINE_SIMILARITY(p.content_vector, uv.lvec) AS sim,
         p.created_at, p.pop_7d, 'long'AS src
FROM posts p, user_vectors uv
WHERE p.status=1
    AND p.created_at > DATE_SUB(NOW(), INTERVAL30DAY)
ORDERBY p.content_vector <-> uv.lvec
  LIMIT 200
),
-- 融合 + 評分(語義相似 + 新鮮度 + 人氣)
merged AS (
SELECT post_id, title, src,
         (CASE src WHEN'short'THEN0.7ELSE0.3END) * sim      -- 雙向量權重(PPT思路)
         +0.1*LOG(1+ pop_7d)
         +0.2*EXP(- TIMESTAMPDIFF(HOUR, created_at, NOW()) /72.0) AS score
FROM short_pool
UNIONALL
SELECT post_id, title, src,
         (CASE src WHEN'short'THEN0.7ELSE0.3END) * sim
         +0.1*LOG(1+ pop_7d)
         +0.2*EXP(- TIMESTAMPDIFF(HOUR, created_at, NOW()) /72.0) AS score
FROM long_pool
)
SELECT post_id, title, MAX(score) AS final_score
FROM merged
GROUPBY post_id, title
ORDERBY final_score DESC
LIMIT 50;

要點

1.COSINE_SIMILARITY直接用相似度(0~1),不要 distance 再 1-distance,閾值語義清晰。

2.新鮮度、人氣做輕權重加成,防止純語義把“陳年老貼”頂上來。

3.已看過過濾必須在 DB 層完成,避免服務端側再次 Join 帶來不一致。


6. 精排與多樣性(簡化可上線)

精排:先上輕量 GBDT/LightGBM,把 sim_short、sim_long、pop_7d、age 等作為特徵;預算充足再上 DNN。

多樣性:MMR(最大邊際相關性)對相似帖子做懲罰,控制主題/作者/價格帶佔比,避免信息繭房。

業務約束:狀態、合規、黑白名單、廣告混排(統一歸一化,避免量綱衝突)。


7. 性能與運維(踩坑直説)

強過濾先行status、時間窗、地域/類目 一定要在 KNN 之前過濾,減少參與向量搜索的數據量。

索引參數:HNSW 的 M/EF_SEARCH 做 A/B 壓測(召回@K vs P95);內容超大時熱冷分層(熱:HNSW;冷:IVF-PQ)。

一致性:用户短期向量更新與行為寫入同事務;模型換代時記得做向量版本與灰度

度量:在線監控 CTR/CVR、P50/P95、短期/長期池貢獻佔比、已看過命中率、新鮮度指標。


8. MVP 路線(兩週能落地)

建表posts / users / user_actions(如上)。

向量:離線產出 long_term_vector;實時流更新 short_term_vector

召回:用上面“一次 SQL 多路召回”,直接能跑;

精排:先用 GBDT,支持快速特徵迭代;

監控:打點記錄 sim_top1、來源池(短/長)、延遲、去重率、曝光→點擊漏斗

迭代:每週校準 HNSW 參數與權重 0.7/0.3、新鮮度衰減係數。


9. 常見問題(按坑給答案)

  • Q:只用一個用户向量行不行?

A:不建議。UGC 的興趣是多峯的,單向量容易“偏科”。短期追新 + 長期守穩是你 PPT 的精華。

  • Q:為什麼把融合和排序放在數據庫裏?

A:少一次網絡往返 + 數據局部性好,延遲更穩;SQL 清晰可審計,覆盤更容易。

  • Q:新內容如何冷啓動?

A:內容向量 + 新鮮度加權 + 小流量探索(ε-greedy/UCB)。有創作者關係的,優先推給關注者的短期近鄰。


結語

UGC 社區的推薦不需要花哨堆棧,核心就三件事:

一是雙向量建模同時覆蓋即時興趣與穩定偏好;

二是用 OceanBase 原生向量把“結構化 + 向量 + 事務”放在同一庫裏;

三是通過 一次 SQL 多路召回把短期池、長期池、時間與人氣統一融合,端到端穩定提速。

根據本文結構化表、SQL 與更新策略上線,即可做出一個快、穩、可迭代的 UGC 個性化推薦系統。

最後為大家推薦這個 OceanBase 開源負責人老紀的公眾號「老紀的技術嘮嗑局」,會持續更新和 #數據庫、#AI、#技術架構 相關的各種技術內容。歡迎感興趣的朋友們關注!

「老紀的技術嘮嗑局」不僅希望能持續給大家帶來有價值的技術分享,也希望能和大家一起為開源社區貢獻一份力量。如果你對 OceanBase 開源社區認可,點亮一顆小星星✨吧!你的每一個Star,都是我們努力的動力。

user avatar zhidechaomian_detxs7 頭像 xzqcsj 頭像 edonsoft 頭像 openfuyao 頭像 wintersun 頭像 whaosoft143 頭像 databend 頭像 u_15316473 頭像 u_17397181 頭像 u_15641375 頭像 histry 頭像 huikaichedemianbao 頭像
點贊 27 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.