Update README and project cleanup

This commit is contained in:
inkling
2026-04-08 14:52:09 +08:00
commit fafd267288
71 changed files with 14865 additions and 0 deletions

108
db/init.js Normal file
View File

@@ -0,0 +1,108 @@
/**
* DMP 数据库初始化
*
* 📚 性能设计要点:
* 1. 位图索引Bitmap Index
* - 每个标签对应一个位数组bit[i]=1 表示第 i 个用户拥有该标签
* - 多标签交叉计算 = 位数组 AND/OR 运算 → O(n/64) 复杂度
* - 这是 OLAP 数据库ClickHouse / Druid的核心思想
*
* 2. 预聚合
* - 标签人数在写入时就维护好,查询时直接读取
* - 避免 COUNT(*) 全表扫描
*
* 3. 连接管理
* - WAL 模式支持读写并发
* - busy_timeout 避免锁等待超时
*/
const Database = require('better-sqlite3');
const path = require('path');
const DB_PATH = path.join(__dirname, '..', 'dmp.db');
function getDb(dbSuffix = '') {
const dbFile = dbSuffix ? `dmp_${dbSuffix}.db` : 'dmp.db';
const dbPath = path.join(__dirname, '..', dbFile);
const db = new Database(dbPath);
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
db.pragma('busy_timeout = 5000');
db.pragma('cache_size = -64000'); // 64MB cache
db.pragma('synchronous = NORMAL');
return db;
}
function initializeDatabase(dbSuffix = '') {
const db = getDb(dbSuffix);
// 用户表 — 宽表设计,一行一个用户
db.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uid TEXT UNIQUE NOT NULL,
name TEXT,
email TEXT,
created_at TEXT DEFAULT (datetime('now')),
extra_json TEXT DEFAULT '{}'
)
`);
// 标签分类(列)
db.exec(`
CREATE TABLE IF NOT EXISTS tag_categories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
sort_order INTEGER DEFAULT 0,
color TEXT DEFAULT '#6366f1'
)
`);
// 标签定义
db.exec(`
CREATE TABLE IF NOT EXISTS tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
category_id INTEGER NOT NULL REFERENCES tag_categories(id),
description TEXT DEFAULT '',
coverage INTEGER DEFAULT 0,
coverage_rate REAL DEFAULT 0,
trend REAL DEFAULT 0,
sort_order INTEGER DEFAULT 0
)
`);
// 用户-标签关联(核心表,需要最强索引)
db.exec(`
CREATE TABLE IF NOT EXISTS user_tags (
user_id INTEGER NOT NULL,
tag_id INTEGER NOT NULL,
PRIMARY KEY (user_id, tag_id)
) WITHOUT ROWID
`);
// WITHOUT ROWID = clustered index on PK查询更快
db.exec(`
CREATE INDEX IF NOT EXISTS idx_user_tags_tag ON user_tags(tag_id, user_id);
`);
// 数据导入批次记录
db.exec(`
CREATE TABLE IF NOT EXISTS import_batches (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source TEXT NOT NULL,
record_count INTEGER DEFAULT 0,
status TEXT DEFAULT 'pending',
error_message TEXT,
started_at TEXT DEFAULT (datetime('now')),
finished_at TEXT
)
`);
console.log(`✅ 数据库表初始化完成 [${dbSuffix || 'default'}]`);
db.close();
}
module.exports = { getDb, initializeDatabase };