中文注释。win11系统,修改这个函数,原先使用jieba创建分词,创建的fts索引。但有个缺点,搜索单个字,或者全部标题,不能用。
现在改为 FTS5 的 ngram 分词器,ngram 1
其他部分不要动。
我已经下载sqlite-dll-win-x64-3500300.zip,解压文件到:c:\users\2\appdata\local\programs\python\python39\DLLs\
.
def rebuild_fts_index():
# db_path = r"d:\img\webdata.db"
db_path = r"/home/adm12/web/q7x7.com/public_html/webdata.db"
fts_table_name = "magnet_fts"
main_table_name = "magnet"
main_table_id_column = "id" # 主表中代表唯一 ID 的列
main_table_indexed_column = "title" # 主表中需要被索引的文本列
fts_version = "fts5" # 或 'fts4'
# jieba 分词模式: 'cut' (精确模式) 或 'cut_for_search' (搜索引擎模式)
jieba_mode = 'cut_for_search'
# 批量插入的大小,减少单次提交次数,提高效率
batch_size = 100000
# -------------
conn = None
processed_count = 0
total_records = 0
# 检查数据库文件是否存在
if not os.path.exists(db_path):
print(f"错误:数据库文件未找到: {db_path}")
sys.stderr.write("FTS 索引重建失败。\n")
return
try:
print(f"连接到数据库: {db_path}")
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
print("数据库连接成功。")
# --- 1. 删除旧的 FTS 索引表 ---
print(f"步骤 1: 正在删除旧的 FTS 索引表 ({fts_table_name})...")
cursor.execute(f"DROP TABLE IF EXISTS {fts_table_name}")
conn.commit()
print(f" 旧的 {fts_table_name} 表已删除(如果存在)。")
# --- 2. 重新创建 FTS 索引表 ---
# 注意:这次创建时不指定 content 和 content_rowid,因为我们将手动插入。
# FTS 仍然会使用其内部的分词器处理我们插入的、已经用 jieba 分好词的字符串。
# 使用默认的 FTS 分词器(如 simple 或 unicode61)通常可以很好地处理空格分隔的词语。
print(f"步骤 2: 正在重新创建 FTS 索引表 ({fts_table_name})...")
# 只定义需要被 FTS 索引的列
create_sql = f"CREATE VIRTUAL TABLE {fts_table_name} USING {fts_version}({main_table_indexed_column})"
print(f" 执行 SQL: \n{create_sql}")
cursor.execute(create_sql)
conn.commit()
print(f" 新的 {fts_table_name} 表已创建。")
# --- 3. 从主表读取数据 ---
print(f"步骤 3: 正在从 '{main_table_name}' 表读取数据...")
select_sql = f"SELECT {main_table_id_column}, {main_table_indexed_column} FROM {main_table_name}"
cursor.execute(select_sql)
print(f" 执行 SQL: {select_sql}")
# --- 4. 逐条处理、分词并批量插入 FTS 表 ---
print(f"步骤 4: 正在使用 jieba ({jieba_mode} 模式) 分词并插入 FTS 表 (每 {batch_size} 条提交一次)...")
rows_batch = []
while True:
# 分批获取数据,避免一次性加载过多数据到内存
fetched_rows = cursor.fetchmany(batch_size)
if not fetched_rows:
break # 没有更多数据了
total_records += len(fetched_rows)
for row in fetched_rows:
original_id = row[0]
original_title = row[1]
if original_title is None: # 跳过 title 为空的记录
print(f" 警告: 跳过 ID {original_id},因为 title 为空。")
continue
# 使用 jieba 分词
if jieba_mode == 'cut_for_search':
seg_list = jieba.cut_for_search(original_title)
else:
seg_list = jieba.cut(original_title)
# 将分词结果用空格连接成字符串
segmented_text = " ".join(seg_list)
# 准备插入 FTS 表的数据 (rowid, indexed_column)
rows_batch.append((original_id, segmented_text))
# 批量插入
if rows_batch:
insert_sql = f"INSERT INTO {fts_table_name} (rowid, {main_table_indexed_column}) VALUES (?, ?)"
try:
cursor.executemany(insert_sql, rows_batch)
conn.commit()
processed_count += len(rows_batch)
print(f" 已处理 {processed_count} / {total_records} (估算)...", end='\r') # 显示进度
rows_batch = [] # 清空批次
except sqlite3.Error as insert_err:
print(f"\n 批量插入时发生错误: {insert_err}")
print(f" 错误发生在处理 ID 范围大约在 {rows_batch[0][0]} 附近。")
conn.rollback() # 回滚这批次的插入
# 可以选择跳过这批次或停止脚本
print(" 跳过此批次。")
rows_batch = [] # 清空批次以继续下一批
print(f"\n 数据分词与插入完成,共处理 {processed_count} 条有效记录。")
# --- 5. (可选但推荐) 优化 FTS 索引 ---
print("步骤 5: (可选) 正在优化 FTS 索引...")
optimize_sql = f"INSERT INTO {fts_table_name}({fts_table_name}) VALUES('optimize')"
print(f" 执行 SQL: {optimize_sql}")
cursor.execute(optimize_sql)
conn.commit()
print(" 索引优化完成。")
print("\nFTS 索引 (使用 jieba 分词) 重建成功完成。")
except sqlite3.Error as e:
print(f"\n数据库操作时发生错误: {e}")
if conn:
try:
conn.rollback()
print("操作已回滚。")
except sqlite3.Error as rb_err:
print(f"回滚时发生错误: {rb_err}")
sys.stderr.write("FTS 索引重建失败。\n")
except ImportError:
print("\n错误:未找到 'jieba' 库。请先安装: pip install jieba")
sys.stderr.write("FTS 索引重建失败。\n")
except Exception as e:
print(f"\n发生意外错误: {e}")
if conn:
try:
conn.rollback()
print("操作已回滚。")
except sqlite3.Error as rb_err:
print(f"回滚时发生错误: {rb_err}")
sys.stderr.write("FTS 索引重建失败。\n")
finally:
if conn:
conn.close()
print("数据库连接已关闭。")