我正在使用 SQLite 的 FTS 模块来尝试使用结果的窗口化(或某些人可能称之为分页)以及突出显示每个窗口内的搜索命中来实现全文搜索。据我所知,对搜索命中进行窗口化或突出显示是很简单的,但不能两者兼而有之。
为了实现窗口化,我运行 FTS 并检索每个命中的 docid 并将其存储在临时表中,如下所示:
CREATE VIRTUAL TABLE FullTextIndex USING FTS4 ( fulltext TEXT );
...
CREATE TEMP TABLE SearchResults ( id INTEGER );
INSERT INTO SearchResults
SELECT docid FROM FullTextIndex WHERE fullText MATCH 'mySearchExpression';
当我准备好根据窗口标准检索实际全文时,我会执行以下操作:
SELECT FullTextIndex.fullText FROM FullTextIndex
INNER JOIN SearchResults
ON FullTextIndex.docid = SearchResults.id
WHERE *windowing criteria applied to SearchResults*;
这部分效果很好并且非常有效,因为它是一个 rowid 匹配。
但是,此时我无法使用 SQLite 的snippet
函数(或任何其他 FTS 辅助函数)来突出显示我的搜索命中,因为我没有在查询中使用文本索引。因此我尝试了这个:
SELECT snippet(FullTextIndex) FROM FullTextIndex
WHERE FullTextIndex.docID IN
(SELECT id FROM SearchResults WHERE *windowing criteria*)
AND FullTextIndex.fullText MATCH 'mySearchExpression';
它可以工作,但它几乎与原始 FTS 一样长,因为它显然首先运行 FTS,而没有应用基于的缩小标准SearchResults
(我认为从根本上它不能因为 FTS 索引的工作方式)。
到目前为止,我最好的解决方案是创建第二个临时表 - 一个临时全文索引,其中仅包含每个窗口的搜索命中。本质上是这样的:
CREATE VIRTUAL TABLE temp.TextResultsWindow USING FTS4 (id INTEGER, fullText text);
INSERT INTO temp.TextResultsWindow
SELECT FullTextIndex.docid, FullTextIndex.fullText
FROM FullTextIndex
WHERE FullTextIndex.docid IN
(SELECT id from SearchResults WHERE *windowing criteria*);
SELECT snippet(temp.TextResultsWindow.TextResultsWindow)
FROM temp.TextResultsWindow
WHERE temp.TextResultsWindow.fullText
MATCH 'mySearchExpression';
这确实有效,并且对于适度的窗口大小来说似乎相对较快,但是重新索引搜索命中的窗口只是为了突出显示似乎非常低效。如果特定窗口中的文本量碰巧非常大,我也可以很容易地看到窗口检索比原始 FTS 花费的时间更长,因为它必须花费大量时间为每个窗口重新索引才能使用该snippet
功能。因此,虽然它在学术上有效,但我认为它在实践中不会很好。
任何人都可以提出更好的方法吗?许多应用程序都具有带窗口和突出显示的全文搜索功能。我是否别无选择,只能对检索到的每个全文结果应用手动扫描和突出显示功能?
非常感谢。
更新:对于它的价值,SQLite 文档中有一个部分讨论了 FTE3/4 和snippet
,以及分页/窗口。他们建议使用 LIMIT 和 OFFSET 进行窗口化,因此他们描述的场景确实会导致全文搜索在每个窗口的整个索引上重新运行。我想如果 SQLite 开发人员没有更有效的方法来做到这一点,它可能不存在,但仍然会感谢人们可能有的任何其他想法。