【问题标题】:Do SQLite FTS tables need to be manually populated?SQLite FTS 表是否需要手动填充?
【发布时间】:2026-02-03 11:40:01
【问题描述】:

SQLite FTS implies 的文档表明应该使用 INSERT、UPDATE、DELETE 等填充和更新 FTS 表。

这就是我所做的 - 添加行、删除行等,但最近我注意到,一旦我创建 FTS 表,它就会使用源中的数据自动填充。我是这样创建的:

CREATE VIRTUAL TABLE notes_fts USING fts4(content="notes", notindexed="id", id, title, body)

如果我在“notes”表中添加一行,它也会自动添加到 notes_fts。我想这就是虚拟表。

但是,为什么会有关于填充 FTS 表的章节呢?甚至有什么意义,例如,如果我删除一行,如果它仍在源表中,它将回来。

对此有任何想法吗? FTS 真的需要填充吗?

【问题讨论】:

  • 我不知道旧版本,但是具有外部内容表的 FTS5 需要在内容表中添加、删除或更改行时更新 fts 表,以便索引更新。也许您忽略了一些触发器设置来做到这一点?
  • 最好对问题所在发表评论。我无法重现它demo
  • @LukaszSzozda,该消息实际上是相关触发器中的错误。不知何故,Sqlite 不显示触发器的名称,这让人感到困惑。

标签: sqlite full-text-search fts4


【解决方案1】:

进一步阅读后发现 FTS 表确实需要手动与内容表保持同步。运行CREATE VIRTUAL TABLE 调用时,FTS 表会自动填充,但之后必须手动完成删除、插入和更新。

在我的情况下,我使用以下触发器完成了它:

CREATE VIRTUAL TABLE notes_fts USING fts4(content="notes", notindexed="id", id, title, body

CREATE TRIGGER notes_fts_before_update BEFORE UPDATE ON notes BEGIN
    DELETE FROM notes_fts WHERE docid=old.rowid;
END

CREATE TRIGGER notes_fts_before_delete BEFORE DELETE ON notes BEGIN
    DELETE FROM notes_fts WHERE docid=old.rowid;
END

CREATE TRIGGER notes_after_update AFTER UPDATE ON notes BEGIN
    INSERT INTO notes_fts(docid, id, title, body) SELECT rowid, id, title, body FROM notes WHERE is_conflict = 0 AND encryption_applied = 0 AND new.rowid = notes.rowid;
END

CREATE TRIGGER notes_after_insert AFTER INSERT ON notes BEGIN
    INSERT INTO notes_fts(docid, id, title, body) SELECT rowid, id, title, body FROM notes WHERE is_conflict = 0 AND encryption_applied = 0 AND new.rowid = notes.rowid;
END;

【讨论】:

  • 使用触发器制作表格并使其保持同步是一个很好的解决方案!感谢您的提示!
【解决方案2】:

根据sqlite document

要删除条目,要么

-- Insert a row with rowid=14 into the fts5 table.
INSERT INTO ft(rowid, a, b, c) VALUES(14, $a, $b, $c);

-- Remove the same row from the fts5 table.
INSERT INTO ft(ft, rowid, a, b, c) VALUES('delete', 14, $a, $b, $c);

CREATE TRIGGER tbl_ad AFTER DELETE ON tbl BEGIN
  INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES('delete', old.a, old.b, old.c);
END;

基于修改后的虚拟表重建

INSERT INTO ft(ft) VALUES('rebuild');

【讨论】: