JIT
修改函数以使用FTS5 ngram分词器的实现建议
中文注释。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("数据库连接已关闭。")

I'll modify the function to use FTS5 with ngram tokenizer (ngram=1) instead of jieba for better single-character and full-title search support. Here's the updated version:

Updated files
v1
中文回答。连接到数据库: d:\img\webdata.db 数据库连接成功。 步骤 1: 正在删除旧的 FTS 索引表 (magnet_fts)... 旧的 magnet_fts 表已删除(如果存在)。 步骤 2: 正在重新创建 FTS 索引表 (magnet_fts)... 执行 SQL: CREATE VIRTUAL TABLE magnet_fts USING fts5( title, tokenize='ngram ngram_len=1' ) 数据库操作时发生错误: parse error in tokenize directive 操作已回滚。 数据库连接已关闭。 FTS 索引重建失败。

看起来在创建 FTS5 表时遇到了 tokenize 指令的语法错误。我们需要调整 ngram 分词器的语法格式。以下是修正后的版本:

主要修改点:

  1. 修正了 ngram 分词器的语法,使用 tokenchars 参数指定要索引的字符集
  2. 移除了 jieba 相关的代码和参数
  3. 直接插入原始文本,由 SQLite 的 ngram 分词器处理分词

这个版本应该能正确处理单字搜索和完整标题搜索。如果需要调整分词字符集,可以修改 tokenchars 参数中的字符列表。

Updated files
v2
重新生成一个文件,在右侧。

主要改进:

  1. 简化了 ngram 分词器配置,使用最基本的 tokenize="ngram" 语法
  2. 默认支持中文单字分词,无需额外配置字符集
  3. 添加了 if __name__ == "__main__": 以便直接运行脚本
  4. 保留了所有错误处理和事务管理逻辑
  5. 移除了所有 jieba 相关代码,完全依赖 SQLite 内置的 ngram 分词器

这个版本应该能正确处理:

  • 单字搜索
  • 完整标题搜索
  • 中文分词
  • 批量插入优化
  • 错误回滚机制
Updated files
v3