频道 2.1 万条评论灌进本地库,我被长度字段坑了一晚上

场景:自己的频道,2.1 万条评论,从 YouTube Data API v3 的 commentThreads 分页拉下来,存成 JSON 分批落盘。环境是 macOS + Python 3.11,目标是把它们塞进本地 SQLite,做按视频、按时间、按作者聚合,顺便试一下 LIKE 能不能撑住中文搜索。数据量不大,单表 2 万行,理论上几秒钟的事。

第一次跑就出问题:2.1 万条里有 137 条插入时报 string or blob too big,另有几十条评论正文变成半截。原因不是 API 限流,是我在写库前做了一次「清洗」,把换行和多余空白压掉,用了 text[:500] 这种截断。中文评论里混着 emoji、日文、韩文,Python 的切片按码点走,截在代理对中间,SQLite 那边就炸了。

做法改成先按字节判断,再按码点截,并且把原始 JSON 原文一块存下来,方便回查:

import json, sqlite3

def safe_clip(s, max_bytes=2000):
    b = s.encode('utf-8')
    if len(b) <= max_bytes:
        return s
    return b[:max_bytes].decode('utf-8', errors='ignore')

con = sqlite3.connect('comments.db')
con.execute('''CREATE TABLE IF NOT EXISTS c(
  id TEXT PRIMARY KEY, vid TEXT, author TEXT, published TEXT,
  text TEXT, raw TEXT)''')
for row in rows:
    con.execute('INSERT OR REPLACE INTO c VALUES(?,?,?,?,?,?)', (
        row['id'], row['vid'], row['author'], row['published'],
        safe_clip(row['text']), json.dumps(row, ensure_ascii=False)))
con.commit()

为什么这样:SQLite 的 TEXT 没有硬上限,但单条记录受 SQLITE_MAX_LENGTH 约束,默认 1e9 字节,真正卡住我的是截断时产生的非法 UTF-8。errors='ignore' 会丢字符,代价是评论末尾可能少一两个字,所以原文必须另存一列 raw,后面要还原随时能还原。

哪里会失效:errors='ignore' 在截断点落在多字节字符中间时,会静默吞掉那半个字符,如果你的分析依赖精确字数统计,得改用 errors='strict' 加循环回退。另外 INSERT OR REPLACE 会重写整行,如果以后加了外键或触发器,行为会变,建议改成 ON CONFLICT(id) DO UPDATE。还有,API 返回的 publishedAt 是 UTC,我一开始直接按字符串排序,跨时区看数据会错位,后来统一存 ISO 格式再转本地时区。

现在库能查了,但中文 LIKE 在 2 万行上已经要 200ms 左右,分词搜索还没上。你们把评论落到本地之后,是直接上 FTS5,还是先做一层作者/视频的降维再搜?

0
赞同度 100% · 0 条评论 · 1 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。