FTS5 是一个 SQLite 虚拟表模块,为数据库应用程序提供全文搜索功能。在最基本的形式中, 全文搜索引擎允许用户有效地搜索大型 包含一个或多个 搜索词。谷歌提供给万维网用户的搜索功能是全文搜索。 引擎,因为它允许用户搜索网络上包含的所有文档, 例如,术语“FTS5”。
要使用 FTS5,用户需要创建一个包含一个或多个 FTS5 虚拟表 列。例如:
CREATE VIRTUAL TABLE email USING fts5(sender, title, body);
将类型、约束或主键声明添加到 用于创建 FTS5 表的创建虚拟表语句。创建后, 可以使用 INSERT、UPDATE 或 DELETE 语句填充 FTS5 表 像任何其他表一样。与任何其他没有主键声明的表一样,一个 FTS5 表有一个名为 rowid 的隐式整数主键字段。
上面示例中未显示的是,还可以向 FTS5 提供各种选项,例如 部分创建虚拟表语句,用于配置 新表。这些可用于修改 FTS5 表的提取方式 来自文档和查询的术语,用于在磁盘上创建额外的索引以加快速度 前缀查询,或创建充当内容索引的 FTS5 表 存储在其他地方。
填充后,有三种方法可以对 FTS5 表的内容:
在 SELECT 语句的 WHERE 子句中使用 MATCH 运算符,或者
在 SELECT 语句的 WHERE 子句中使用等号 (“=”) 运算符,或者
使用表值函数语法。
如果使用 MATCH 或 = 运算符,则 MATCH 左侧的表达式 运算符通常是 FTS5 表的名称(指定列筛选器时例外)。右边的表达式 必须是指定要搜索的术语的文本值。对于表值 函数语法,要搜索的术语被指定为第一个表参数。 例如:
– Query for all rows that contain at least once instance of the term
– “fts5” (in any column). The following three queries are equivalent.
SELECT * FROM email WHERE email MATCH ‘fts5’;
SELECT * FROM email WHERE email = ‘fts5’;
SELECT * FROM email(‘fts5’);
默认情况下,FTS5 全文搜索与大小写无关。像任何其他人一样 不包含 ORDER BY 子句的 SQL 查询,上面的示例返回 结果按任意顺序排列。按相关性对结果进行排序(从最多到最少) 相关),可以将 ORDER BY 添加到全文查询中,如下所示:
– Query for all rows that contain at least once instance of the term
– “fts5” (in any column). Return results in order from best to worst
– match.
SELECT * FROM email WHERE email MATCH ‘fts5’ ORDER BY rank;
以及匹配行的列值和 rowid,应用程序 可以使用 FTS5 辅助函数来检索有关 匹配的行。例如,可以使用辅助函数来检索 匹配行的列值的副本,其中包含匹配行的所有实例 由 HTML 标记包围的术语。辅助功能包括 以与 SQLite 标量函数相同的方式调用,只是名称 的 FTS5 表被指定为第一个参数。例如:
– Query for rows that match “fts5”. Return a copy of the “body” column
– of each row with the matches surrounded by tags.
SELECT highlight(email, 2, ‘’, ‘’) FROM email(‘fts5’);
可用辅助功能的说明以及更多详细信息 关于特殊“等级”列的配置,请参见下文。自定义辅助函数也可以在 C 语言中实现并注册到 FTS5,就像自定义SQL函数可以在SQLite核心中注册一样。
除了搜索包含术语的所有行外,FTS5 还允许 要搜索包含以下内容的行的用户:
“短语” - 必须在 文档以使其与查询匹配,
出现在指定术语中的术语、前缀术语或短语集 彼此接近(这些称为“NEAR查询”),或
上述任何一项的布尔组合。
这种高级搜索是通过提供更复杂的 FTS5 查询字符串作为 MATCH 运算符右侧的文本(或 = 运算符,或作为表值函数语法的第一个参数)。这 此处介绍了完整的查询语法。
或者,如果 sqlite3.c 是使用其他构建系统编译的,则通过安排 要定义的SQLITE_ENABLE_FTS5预处理器符号。
2.2. 构建可加载扩展
或者,FTS5可以构建为可加载的扩展。
规范的 FTS5 源代码由一系列 *.c 和其他文件组成 在 SQLite 源代码树的 “ext/fts5” 目录中。构建过程减少 这只有两个文件 - “fts5.c”和“fts5.h” - 可用于构建 SQLite 可加载扩展。
从Fossil获取最新的SQLite代码。
按照如何编译 SQLite 中所述创建生成文件。
构建“fts5.c”目标。这也创建了fts5.h。
$ wget -c http://www.sqlite.org/src/tarball/SQLite-trunk.tgz?uuid=trunk -O SQLite-trunk.tgz
… output …
$ tar -xzf SQLite-trunk.tgz
$ cd SQLite-trunk
$ ./configure && make fts5.c
… lots of output …
$ ls fts5.[ch]
fts5.c fts5.h
然后,可以将“fts5.c”中的代码编译为可加载的扩展或 静态链接到应用程序,如编译可加载扩展中所述。定义了两个入口点,两者都 其中做同样的事情:
sqlite3_fts_init
sqlite3_fts5_init
另一个文件“fts5.h”不需要编译FTS5扩展。 它由实现自定义 FTS5 分词器或辅助函数的应用程序使用。
:= string [*]
:= +
:= NEAR ( … [, N] )
:= [ [-] :] [^]
:= [ [-] :]
:= [ [-] :] ( )
:= AND
:= OR
:= NOT
:= colname
:= { colname1 colname2 … }
3.1. FTS5 字符串
在 FTS 表达式中,可以通过以下两种方式之一指定字符串:
用双引号 (“) 括起来。在字符串中,任何嵌入的 双引号字符可以用 SQL 样式进行转义 - 通过添加第二个 双引号字符。
作为 FTS5 的空词,不是“AND”、“OR”或“NOT”(区分大小写)。 FTS5 裸字是由一个或多个连续字符组成的字符串,这些字符 都是:
非 ASCII 范围字符(即 Unicode 代码点更大 大于 127),或
52 个大写和小写 ASCII 字符之一,或
10 个十进制数字 ASCII 字符之一,或
下划线字符(Unicode 代码点 96)。
替换字符(Unicode 代码点 26)。
包含任何其他字符的字符串必须用引号括起来。字符 目前不允许在裸词中,不是引号字符,并且 目前在 FTS5 查询表达式中没有任何特殊用途 可能 在将来的某个时候允许使用空话或用于实现 新的查询功能。这意味着当前 语法错误,因为它们在引号之外包含此类字符 某些未来版本的 FTS5 可能会对字符串进行不同的解释。
3.2. FTS5 短语
FTS 查询由短语组成。短语是 一个或多个令牌。字符串通过传递给 FTS 表标记器。两个短语可以连接成一个短语 使用“+”运算符的大短语。例如,假设分词器 正在使用的模块将输入“one.two.three”标记为三个单独的 令牌,以下四个查询都指定相同的短语:
… MATCH ‘“one two three”’
… MATCH ‘one + two + three’
… MATCH ‘“one two” + three’
… MATCH ‘one.two.three’
如果文档至少包含一个子序列,则短语与文档匹配 与构成短语的令牌序列匹配的令牌。
3.3. FTS5 前缀查询
如果 FTS 表达式中的字符串后面跟着“*”字符,则 从字符串中提取的标记标记为前缀标记。当你 可能期望,前缀令牌与它所属的任何文档令牌匹配 前缀。例如,以下块中的前两个查询将匹配 任何包含紧跟令牌的令牌“一”的文档 “二”,然后是任何以“THR”开头的标记。
… MATCH '“one two thr” * ’
… MATCH ‘one + two + thr*’
… MATCH ‘“one two thr*”’ – May not work as expected!
上面块中的最后一个查询可能无法按预期工作。因为 “*”字符在双引号内,它将被传递给分词器, 这可能会丢弃它(或者可能,取决于特定的分词器 在使用中,将其作为最终令牌的一部分包含在内),而不是将其识别为 一个特殊的 FTS 字符。
3.4. FTS5 初始令牌查询
如果“^”字符出现在不属于 NEAR 查询,则该短语仅当文档从 列中的第一个标记。“^”语法可以与列筛选器结合使用,但不能插入到列筛选器的中间 一句话。
… MATCH ‘^one’ – first token in any column must be “one”
… MATCH ‘^ one + two’ – phrase “one two” must appear at start of a column
… MATCH ‘^ “one two”’ – same as previous
… MATCH ‘a : ^two’ – first token of column “a” must be “two”
… MATCH ‘NEAR(^one, two)’ – syntax error!
… MATCH ‘one + ^two’ – syntax error!
… MATCH ‘“^one two”’ – May not work as expected!
3.5. FTS5 近查询
两个或多个短语可以分组到一个 NEAR 组中。近组 由标记“NEAR”(区分大小写)指定,后跟打开 括号字符,后跟两个或多个空格分隔的短语,可以选择后跟逗号和数字参数 N,后跟 一个右括号。例如:
… MATCH ‘NEAR(“one two” “three four”, 10)’
… MATCH ‘NEAR(“one two” thr* + four)’
如果未提供 N 参数,则默认为 10。近组 如果文档包含至少一个令牌集合,则匹配该文档:
每个短语至少包含一个实例,并且
第一个短语末尾之间的令牌数 并且团块中最后一个短语的开头小于或等于 N。
例如:
CREATE VIRTUAL TABLE f USING fts5(x);
INSERT INTO f(rowid, x) VALUES(1, ‘A B C D x x x E F x’);
… MATCH ‘NEAR(e d, 4)’; – Matches!
… MATCH ‘NEAR(e d, 3)’; – Matches!
… MATCH ‘NEAR(e d, 2)’; – Does not match!
… MATCH ‘NEAR(“c d” “e f”, 3)’; – Matches!
… MATCH ‘NEAR(“c” “e f”, 3)’; – Does not match!
… MATCH ‘NEAR(a d e, 6)’; – Matches!
… MATCH ‘NEAR(a d e, 5)’; – Does not match!
… MATCH ‘NEAR(“a b c d” “b c” “e f”, 4)’; – Matches!
… MATCH ‘NEAR(“a b c d” “b c” “e f”, 3)’; – Does not match!
3.6. FTS5 列过滤器
单个短语或 NEAR 组可能仅限于匹配 指定 FTS 表的列,方法是在列名前面加上列名 后跟冒号字符。或者通过前缀来添加到一组列 用空格分隔的列名列表括在括号中 (“大括号”)后跟冒号字符。可以指定列名 使用上面为字符串描述的两种形式之一。与字符串不同 是短语的一部分,列名不会传递给分词器模块。 列名不区分大小写,与 SQLite 列名的通常方式不区分大小写 - 大写/小写等效性仅适用于 ASCII 范围字符。
… MATCH ‘colname : NEAR(“one two” “three four”, 10)’
… MATCH ‘“colname” : one + two + three’
… MATCH ‘{col1 col2} : NEAR(“one two” “three four”, 10)’
… MATCH ‘{col2 col1 col3} : one + two + three’
如果列筛选器规范前面带有“-”字符,则 它被解释为不匹配的列列表。例如:
– Search for matches in all columns except “colname”
… MATCH ‘- colname : NEAR(“one two” “three four”, 10)’
– Search for matches in all columns except “col1”, “col2” and “col3”
… MATCH ‘- {col2 col1 col3} : one + two + three’
列过滤器规范也可以应用于任意表达式 括在括号内。在这种情况下,列筛选器适用于所有 表达式中的短语。嵌套列筛选器操作只能 进一步限制列子集匹配,它们不能用于 重新启用筛选的列。例如:
– The following are equivalent:
… MATCH ‘{a b} : ( {b c} : “hello” AND “world” )’
… MATCH ‘(b : “hello”) AND ({a b} : “world”)’
最后,可以使用以下命令指定单个列的列筛选器 列名作为 MATCH 运算符的 LHS(而不是通常的 表名)。例如:
– Given the following table
CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
– The following are equivalent
SELECT * FROM ft WHERE b MATCH ‘uvw AND xyz’;
SELECT * FROM ft WHERE ft MATCH ‘b : (uvw AND xyz)’;
– This query cannot match any rows (since all columns are filtered out):
SELECT * FROM ft WHERE b MATCH ‘a : xyz’;
3.7. FTS5 布尔运算符
短语和 NEAR 组可以使用布尔值排列成表达式 运算符。按优先级顺序,从最高(最紧密分组)到 最低(最松散的分组),运算符为:
算子 功能
NOT 如果查询 1 匹配而查询 2 不匹配,则匹配。
AND 如果查询 1 和查询 2 都匹配,则匹配。
OR 如果查询 1 或查询 2 匹配,则匹配。
括号可用于对表达式进行分组以修改运算符 以通常的方式优先。例如:
– Matches documents that contain at least one instance of either “one”
– or “two”, but do not contain any instances of token “three”.
… MATCH ‘one OR two NOT three’
– Match all documents that contain the token “two” but not “three”, or
– contain the token “one”.
… MATCH ‘one OR (two NOT three)’
短语和 NEAR 组也可以通过隐式 AND 运算符连接。 为简单起见,这些未显示在上面的 BNF 语法中。从本质上讲,任何 短语或 NEAR 组的序列(包括仅限于匹配的短语或 NEAR 组 仅由空格分隔的指定列将像存在 每对短语或 NEAR 组之间的隐式 AND 运算符。含蓄 AND 运算符永远不会在包含在 中的表达式之后或之前插入 括号。例如:
… MATCH ‘one two three’ – ‘one AND two AND three’
… MATCH ‘three “one two”’ – ‘three AND “one two”’
… MATCH ‘NEAR(one two) three’ – ‘NEAR(one two) AND three’
… MATCH ‘one OR two three’ – ‘one OR two AND three’
… MATCH ‘(one OR two) three’ – Syntax error!
… MATCH ‘func(one two)’ – Syntax error!
4. FTS5 表创建和初始化
指定为“创建虚拟表…使用 FTS5 …"语句是列声明或配置选项。列声明由一个或多个空格分隔的 FTS5 组成 以SQLite可接受的任何方式引用的裸词或字符串文字。
列声明中的第一个字符串或裸词是列名。它 是尝试将 FTS5 表列命名为“rowid”或“rank”的错误,或者 为列指定与表本身相同的名称。这不是 支持。
列声明中的每个后续字符串或裸词都是一个列 选项,用于修改该列的行为。列选项包括 与大小写无关。与SQLite核心不同,FTS5考虑无法识别的列 选项为错误。目前,唯一公认的选项是“取消编制索引”(见下文)。
配置选项由 FTS5 裸词组成 - 选项名称 - 后跟“=”字符,后跟选项值。选项值为 使用单个 FTS5 裸字或字符串文字指定,再次引用 以SQLite核心可接受的任何方式。例如:
CREATE VIRTUAL TABLE mail USING fts5(sender, title, body, tokenize = ‘porter ascii’);
当前有以下配置选项:
“标记化”选项,用于配置自定义标记器。
“前缀”选项,用于向 FTS5 表添加前缀索引。
“内容”选项,用于使 FTS5 表成为外部内容或无内容表。
“content_rowid”选项,用于设置外部内容表的 rowid 字段。
“列大小”选项,用于配置 FTS5 表中每个值的标记大小是否为 单独存储在数据库中。
“详细信息”选项。可以使用此选项 通过省略某些信息来减小磁盘上 FTS 索引的大小 从它。
4.1. 取消索引列选项
使用“取消索引列”选项限定的列的内容不是 添加到 FTS 索引中。这意味着,出于 MATCH 查询和 FTS5 辅助函数的目的,该列不包含可匹配的标记。
例如,避免将“uuid”字段的内容添加到 FTS 指数:
CREATE VIRTUAL TABLE customers USING fts5(name, addr, uuid UNINDEXED);
4.2. 前缀索引
默认情况下,FTS5 维护一个索引,记录每个索引的位置 文档集中的令牌实例。这意味着查询完成 令牌速度很快,因为它需要一次查找,但查询前缀 令牌可能很慢,因为它需要范围扫描。例如,要查询 前缀标记“abc*”要求对所有大于 或等于“abc”且小于“abd”。
前缀索引是一个单独的索引,用于记录所有位置 以用于加速的字符表示的一定长度的前缀标记的实例 前缀令牌的向上查询。例如,优化前缀查询 令牌“abc*”需要由三个字符前缀组成的前缀索引。
要将前缀索引添加到 FTS5 表,“前缀”选项设置为 单个正整数或包含空格的文本值 一个或多个正整数值的分隔列表。前缀索引为 为每个指定的整数创建。如果多个“前缀”选项是 指定为单个创建虚拟表语句的一部分,全部适用。
– Two ways to create an FTS5 table that maintains prefix indexes for
– two and three character prefix tokens.
CREATE VIRTUAL TABLE ft USING fts5(a, b, prefix=‘2 3’);
CREATE VIRTUAL TABLE ft USING fts5(a, b, prefix=2, prefix=3);
4.3. 分词器
创建虚拟表“标记化”选项用于配置 FTS5 表使用的特定分词器。选项参数必须是 FTS5 裸字或 SQL 文本文字。参数的文本本身 被视为一个或多个 FTS5 裸词或 SQL 文本的空白序列 文字。其中第一个是要使用的分词器的名称。第二个 后续列表元素(如果存在)是传递给 分词器实现。
与选项值和列名不同,SQL 文本文本旨在 分词器必须使用单引号字符引号。例如:
– The following are all equivalent
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = ‘porter ascii’);
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = “porter ascii”);
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = “‘porter’ ‘ascii’”);
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = ‘’‘porter’’ ‘‘ascii’’');
– But this will fail:
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = ‘“porter” “ascii”’);
– This will fail too:
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = ‘porter’ ‘ascii’);
FTS5 具有三个内置分词器模块,将在后续中描述 部分:
unicode61 tokenizer,基于 Unicode 6.1 标准。这 是默认值。
ascii 分词器,它假定 ASCII 代码点范围 (0-127) 将被视为标记字符。
移植器标记器,它实现波特词干提取算法。
也可以为 FTS5 创建自定义分词器。此处介绍了执行此操作的 API。
4.3.1. Unicode61 分词器
Unicode 标记器将所有 unicode 字符分类为 “分隔符”或“标记”字符。默认情况下,所有空格和标点符号 根据 Unicode 6.1 的定义,字符被视为分隔符,并且所有 其他字符作为标记字符。更具体地说,所有 unicode 分配给以“L”或“N”开头的一般类别的字符(字母和数字, 具体而言)或类别“Co”(“其他私人使用”)被视为代币。 所有其他字符都是分隔符。
一个或多个标记字符的每个连续运行都被视为 令 牌。根据 定义的规则,分词器不区分大小写 统一码 6.1.
默认情况下,将从所有拉丁脚本字符中删除音调符号。这 例如,表示“A”、“a”、“À”、“à”、“”和“â” 都被认为是等效的。
令牌规范中“unicode61”之后的任何参数都将被处理 作为交替选项名称和值的列表。Unicode61 支持 以下选项:
选择 用法
remove_diacritics 此选项应设置为“0”、“1”或“2”。默认值为“1”。 如果设置为“1”或“2”,则从拉丁字母中删除变音符号 如上所述的字符。但是,如果设置为“1”,则音调符号 在相当罕见的情况下不会删除单个 Unicode 代码点 用于表示具有多个音调符号的字符。例如 变音符号不会从代码点 0x1ED9 中删除(“拉丁小写字母 O 与 回旋和点在下面“)。这在技术上是一个错误,但无法修复 不会产生向后兼容性问题。如果此选项设置为 “2”,则从所有拉丁字符中正确删除变音符号。
类别 此选项可用于修改 Unicode 常规类别集 被视为对应于令牌字符。参数必须 由两个字符的常规类别的空格分隔列表组成 缩写(例如“Lu”或“Nd”),或与第二个字符相同的缩写 替换为星号 (“”),解释为 glob 模式。默认 值为 “L N* Co”。
令牌字符 此选项用于指定其他 unicode 字符 应被视为标记字符,即使它们是空格或 根据 Unicode 6.1 的标点字符。中的所有字符 此选项设置为的字符串被视为标记字符。
分隔符 此选项用于指定其他 unicode 字符 应被视为分隔符,即使它们是标记 字符,符合 Unicode 6.1。字符串中的所有字符 此选项设置为被视为分隔符。
例如:
– Create an FTS5 table that does not remove diacritics from Latin
– script characters, and that considers hyphens and underscore characters
– to be part of tokens.
CREATE VIRTUAL TABLE ft USING fts5(a, b,
tokenize = “unicode61 remove_diacritics 0 tokenchars ‘-_’”
);
艺术
– Create an FTS5 table that, as well as the default token character classes,
– considers characters in class “Mn” to be token characters.
CREATE VIRTUAL TABLE ft USING fts5(a, b,
tokenize = “unicode61 categories ‘L* N* Co Mn’”
);
fts5 unicode61 分词器与 fts3/4 逐字节兼容 Unicode61 分词器。
4.3.2. ASCII分词器
Ascii 分词器类似于 Unicode61 分词器,不同之处在于:
所有非 ASCII 字符(代码点大于 127 的字符)均为 始终被视为令牌字符。如果指定了任何非 ASCII 字符 作为分隔符选项的一部分,它们将被忽略。
大小写折叠仅对 ASCII 字符执行。所以虽然“A”和 “a”被认为是等价的,“Ô和“ã”是不同的。
不支持remove_diacritics选项。
例如:
– Create an FTS5 table that uses the ascii tokenizer, but does not
– consider numeric characters to be part of tokens.
CREATE VIRTUAL TABLE ft USING fts5(a, b,
tokenize = “ascii separators ‘0123456789’”
);
4.3.3. 波特分词器
波特标记器是一个包装标记器。它需要一些输出 其他分词器,并在将 Porter 词干提取算法返回到 FTS5 之前将其应用于每个代币。这允许搜索词,例如 “更正”以匹配类似的词,例如“更正”或“更正”。这 波特词干分析算法设计用于英语术语 仅 - 将其与其他语言一起使用可能会或可能不会改善搜索实用程序。
默认情况下,移植器标记器作为默认的包装器运行 分词器 (Unicode61)。或者,如果将一个或多个额外的参数添加到 “porter”之后的“标记化”选项,它们被视为 波特词干分析器使用的基础分词器。例如:
– Two ways to create an FTS5 table that uses the porter tokenizer to
– stem the output of the default tokenizer (unicode61).
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = porter);
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = ‘porter unicode61’);
– A porter tokenizer used to stem the output of the unicode61 tokenizer,
– with diacritics removed before stemming.
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize = ‘porter unicode61 remove_diacritics 1’);
4.3.4. 三元组分词器
三元组分词器扩展了 FTS5 以支持子字符串 一般匹配,而不是通常的令牌匹配。使用 Trigram 分词器,查询或短语标记可以匹配任何字符序列 在一行内,而不仅仅是一个完整的令牌。例如:
CREATE VIRTUAL TABLE tri USING fts5(a, tokenize=“trigram”);
INSERT INTO tri VALUES(‘abcdefghij KLMNOPQRST uvwxyz’);
– The following queries all match the single row in the table
SELECT * FROM tri(‘cdefg’);
SELECT * FROM tri(‘cdefg AND pqr’);
SELECT * FROM tri(‘“hij klm” NOT stuv’);
三元组分词器支持单个选项 - “case_sensitive”。使用默认值 值 0,匹配不区分大小写。如果此值设置为 1,则所有匹配项 区分大小写。
– A case-sensitive trigram index
CREATE VIRTUAL TABLE tri USING fts5(a, tokenize=“trigram case_sensitive 1”);
使用三元组标记器的 FTS5 表还支持索引 GLOB 和 LIKE 模式匹配。例如:
SELECT * FROM tri WHERE a LIKE ‘%cdefg%’;
SELECT * FROM tri WHERE a GLOB ‘ij klmxyz’;
如果在 case_sensitive 选项设置为 5 的情况下创建 FTS1 三元组分词器, 它可能只索引 GLOB 查询,而不是 LIKE。
笔记:
由少于 3 个 unicode 字符组成的子字符串与任何字符都不匹配 行(与全文查询一起使用时)。如果 LIKE 或 GLOB 模式没有 包含至少一个非通配符 Unicode 字符序列,FTS5 回退到整个表的线性扫描。
如果使用详细信息=无或详细信息=列选项创建 FTS5 表 指定的全文查询不得包含任何长度超过 3 的标记 统一码字符。LIKE 和 GLOB 图案匹配可能会稍微慢一些, 但仍然有效。如果索引仅用于 LIKE 和/或 GLOB 模式匹配,这些选项值得尝试以减少 索引大小。
4.4. 外部内容和无内容表
通常,当将一行插入 FTS5 表时,以及各种 全文索引条目和其他数据 行的副本存储在私有中 由 FTS5 模块管理的表。当从 FTS5表由用户或辅助功能实现,它们是 从此专用表中读取。“内容”选项可用于创建 FTS5 表,仅存储 FTS 全文索引条目。因为列 值本身通常比关联的全文索引大得多 条目,这可以节省大量数据库空间。
有两种方法可以使用“内容”选项:
通过将其设置为空字符串来创建无内容的 FTS5 表。在 在这种情况下,FTS5 假定原始列值不可用 在处理查询时到它。全文查询和一些辅助查询 仍然可以使用函数,但除了 rowid 之外没有列值 可以从表中读取。
通过将其设置为数据库对象(表、虚拟表或 视图),FTS5 可以随时查询以检索列 值。这称为“外部内容”表。在这种情况下,所有 可以使用FTS5功能,但这是用户的责任 确保全文索引的内容与 具名数据库对象。如果不是,则查询结果可能是 不可预知的。
4.4.1. 无内容表
通过将“内容”选项设置为 一个空字符串。例如:
CREATE VIRTUAL TABLE f1 USING fts5(a, b, c, content=‘’);
无内容的 FTS5 表不支持 UPDATE 或 DELETE 语句,或者 不为 rowid 字段提供非 NULL 值的 INSERT 语句。 无内容表不支持替换冲突处理。取代 和插入或替换语句被视为常规插入语句。 可以使用 FTS5 删除命令从无内容表中删除行。
尝试从无内容中读取除 rowid 以外的任何列值 FTS5 表返回一个 SQL NULL 值。
4.4.2. 外部内容表
通过设置内容创建外部内容 FTS5 表 表、虚拟表或视图名称的选项(以下简称“内容” 表“)在同一数据库中。每当需要列值时 FTS5,它查询内容表如下,行的 rowid 哪些值需要绑定到 SQL 变量:
SELECT
在上面, 被替换为内容表的名称。 默认情况下,
– If the database schema is:
CREATE TABLE tbl (a, b, c, d INTEGER PRIMARY KEY);
CREATE VIRTUAL TABLE fts USING fts5(a, c, content=tbl, content_rowid=d);
– Fts5 may issue queries such as:
SELECT d, a, c FROM tbl WHERE d = ?;
还可以按如下方式查询内容表:
SELECT
SELECT
用户仍有责任确保 外部内容 FTS5 表与内容表保持最新。 一种方法是使用触发器。例如:
– Create a table. And an external content fts5 table to index it.
CREATE TABLE tbl(a INTEGER PRIMARY KEY, b, c);
CREATE VIRTUAL TABLE fts_idx USING fts5(b, c, content=‘tbl’, content_rowid=‘a’);
– Triggers to keep the FTS index up to date.
CREATE TRIGGER tbl_ai AFTER INSERT ON tbl BEGIN
INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);
END;
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;
CREATE TRIGGER tbl_au AFTER UPDATE ON tbl BEGIN
INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES(‘delete’, old.a, old.b, old.c);
INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);
END;
与无内容表一样,外部内容表不支持 REPLACE 冲突处理。指定 REPLACE 冲突处理的任何操作都是 使用 ABORT 处理。
4.5. 列大小选项
通常,FTS5 在数据库中维护一个特殊的支持表,该表是 将每个列值的大小存储在插入到主 FTS5 中的令牌中 表在单独的表中。此支持表由 xColumnSize API 函数使用,该函数又由 内置的BM25排名功能(并且可能很有用 到其他排名函数也是如此)。
为了节省空间,可以通过设置 列大小选项为零。例如:
– A table without the xColumnSize() values stored on disk:
CREATE VIRTUAL TABLE ft USING fts5(a, b, c, columnsize=0);
– Three equivalent ways of creating a table that does store the
– xColumnSize() values on disk:
CREATE VIRTUAL TABLE ft USING fts5(a, b, c);
CREATE VIRTUAL TABLE ft USING fts5(a, b, c, columnsize=1);
CREATE VIRTUAL TABLE ft USING fts5(a, b, columnsize=‘1’, c);
将列大小选项设置为除 0 或 1。
如果 FTS5 表配置为列大小 = 0,但不是无内容的表,则 x列大小 API 函数 仍然有效,但运行速度要慢得多。在这种情况下,而不是阅读 直接从数据库返回的值,它读取文本值 本身并按需计算其中的代币。
或者,如果表也是无内容的表, 则适用以下内容:
xColumnSize API 始终返回 -1。没有办法确定 存储在无内容的 FTS5 表中的值中的令牌数 配置为列大小 = 0。
每个插入的行必须伴随着明确指定的 rowid 价值。如果将无内容表配置为列大小=0, 尝试将 NULL 值插入 rowid 是一种SQLITE_MISMATCH 错误。
表上的所有查询都必须是全文查询。换句话说, 它们必须使用 MATCH 或 = 运算符和表名列作为 左操作数,或者使用表值函数语法。任何 不是全文查询的查询会导致错误。
存储 xColumnSize 值的表的名称 (除非指定 columnsize=0)为 “_docsize”,其中 <名称> 是 FTS5 表本身的名称。sqlite3_analyzer工具可用于现有数据库,以确定有多少 通过使用 columnsize=5 重新创建 FTS0 表,可以节省空间。
4.6. 细节选项
对于文档中的每个术语,FTS5 维护的 FTS 索引 存储文档的 rowid,即包含以下内容的列的列号 术语和术语在列值中的偏移量。“细节” 选项可用于省略其中一些信息。这减少了空间 索引在数据库文件中消耗,但也减少了 系统的能力和效率。
详细信息选项可以设置为“完整”(默认值)、“列”或 “没有”。例如:
– The following two lines are equivalent (because the default value
– of “detail” is “full”.
CREATE VIRTUAL TABLE ft1 USING fts5(a, b, c);
CREATE VIRTUAL TABLE ft1 USING fts5(a, b, c, detail=full);
CREATE VIRTUAL TABLE ft2 USING fts5(a, b, c, detail=column);
CREATE VIRTUAL TABLE ft3 USING fts5(a, b, c, detail=none);
如果详细信息选项设置为列,则对于每个术语,FTS 索引仅记录 rowid 和列号,省略术语偏移量 信息。这会导致以下限制:
NEAR 查询不可用。
短语查询不可用。
假设该表不是无内容的表,则 xInstCount、xInst、xPhraseFirst 和 xPhraseNext 比平时慢。这是因为不是读取所需的数据 他们必须直接从FTS索引加载和标记文档文本 按需提供。
如果表也是无内容的表,则 xInstCount、xInst、 xPhraseFirst 和 xPhraseNext API 的行为就像当前行不包含 短语匹配(即 xInstCount() 返回 0)。
如果详细信息选项设置为无,则对于每个术语,FTS 索引记录仅存储 rowid。列和偏移量信息 省略。以及上面对详细信息=列逐项列出的限制 模式下,这施加了以下额外限制:
列筛选器查询不可用。
假设该表不是无内容的表,则 xPhraseFirstColumn 和 xPhraseNextColumn 比平时慢。
如果该表也是无内容的表,则 xPhraseFirstColumn 和 xPhraseNextColumn API 的行为就像当前行不包含短语一样 完全匹配(即 xPhraseFirstColumn() 将迭代器设置为 EOF)。
在一项索引大量电子邮件(磁盘上为 1636 MiB)的测试中,FTS 磁盘上的索引为 743 MiB,详细信息=完整,详细信息=列时为 340 MiB,134 MiB 与细节 = 无。
要调用辅助函数,FTS5 表的名称应为 指定为第一个参数。其他论点可能遵循第一个, 取决于要调用的特定辅助函数。例如,到 调用“突出显示”函数:
SELECT highlight(email, 2, ‘’, ‘’) FROM email WHERE email MATCH ‘fts5’
作为 FTS5 的一部分提供的内置辅助功能在 中进行了介绍 下一节。应用程序还可以在 C 语言中实现自定义辅助功能。
5.1. 内置辅助函数
FTS5 提供三个内置辅助功能:
bm25() 辅助函数返回一个实值 反映当前匹配的准确性。更好的匹配是 分配了数值较低的值。
highlight() 辅助函数返回一个副本 当前匹配的其中一列中的文本与每个匹配 结果中被指定包围的查询词的实例 标记(例如“”和“”)。
snippet() 辅助函数选择一个短函数 匹配行的某一列的文本片段并返回 它与查询术语的每个实例一起,用标记括起来 与 highlight() 函数相同的方式。文本片段是 选中以最大化它包含的查询词数。
5.1.1. bm25() 函数
内置辅助函数 bm25() 返回一个实值,指示 当前行与全文查询的匹配程度。匹配越好, 返回的值在数值上越小。如下所示的查询可能会 用于按从最佳到最差匹配的顺序返回匹配:
SELECT * FROM fts WHERE fts MATCH ? ORDER BY bm25(fts)
为了计算文档分数,全文查询是分开的 到其组件短语中。文档 D 和 bm25 分数 然后按如下方式计算查询 Q:
在上面,nPhrase 是查询中的短语数。|D|是当前文档中的令牌数,avgdl 是 FTS5 表。k1 和 b 都是常数, 硬编码分别为 1.2 和 0.75。
公式开头的“-1”项在大多数中都找不到 BM25 算法的实现。没有它,将分配更好的匹配 BM25 分数在数字上更高。由于默认排序顺序为 “升序”,这意味着将“ORDER BY bm25(fts)”附加到查询将 导致按从最差到最好的顺序返回结果。“DESC”关键字 需要首先返回最佳匹配项。为了 避免这个陷阱,BM5 的 FTS25 实现使结果成倍增加 在返回之前按 -1 返回,确保分配更好的匹配项 数字上较低的分数。
IDF(qi) 是查询的反文档频率 短语 I.计算如下,其中 N 是总数 FTS5 表中的行数和 n(qi) 是总数 至少包含一个短语 i 实例的行数:
最后,f(q i,D) 是短语 i 的短语频率。默认情况下,这只是短语的出现次数 在当前行中。但是,通过将额外的实值参数传递给 bm25() SQL 函数,表的每一列可以分配不同的 权重和短语频率计算如下:
其中 w c 是分配给列 c 的权重,n(q i,c) 是短语 i 在 当前行的 C 列。传递给 bm25() 的第一个参数 表名后面是分配给最左侧列的权重 FTS5 表。第二个是分配给最左边第二个的权重 列,依此类推。如果没有足够的参数用于所有表列, 其余列的权重为 1.0。如果太多 尾随参数,附加内容将被忽略。例如:
– Assuming the following schema:
CREATE VIRTUAL TABLE email USING fts5(sender, title, body);
– Return results in bm25 order, with each phrase hit in the “sender”
– column considered the equal of 10 hits in the “body” column, and
– each hit in the “title” column considered as valuable as 5 hits in
– the “body” column.
SELECT * FROM email WHERE email MATCH ? ORDER BY bm25(email, 10.0, 5.0);
请参阅维基百科以获取有关以下内容的更多信息 BM25及其变体。
5.1.2. 突出显示() 函数
highlight() 函数从指定的 当前行的列,并插入额外的标记文本以标记开始 和短语结尾匹配。
必须使用以下三个参数调用 highlight() 表名。解释如下:
一个整数,指示要读取 文本来自。列从零开始从左到右编号。
在每个短语匹配之前插入的文本。
每个短语匹配后要插入的文本。
例如:
– Return a copy of the text from the leftmost column of the current
– row, with phrase matches marked using html “b” tags.
SELECT highlight(fts, 0, ‘’, ‘’) FROM fts WHERE fts MATCH ?
在两个或多个短语实例重叠的情况下(共享一个或多个 共同标记),为每组插入一个打开和关闭标记 的重叠短语。例如:
– Assuming this:
CREATE VIRTUAL TABLE ft USING fts5(a);
INSERT INTO ft VALUES(‘a b c x c d e’);
INSERT INTO ft VALUES(‘a b c c d e’);
INSERT INTO ft VALUES(‘a b c d e’);
– The following SELECT statement returns these three rows:
– ‘[a b c] x [c d e]’
– ‘[a b c] [c d e]’
– ‘[a b c d e]’
SELECT highlight(ft, 0, ‘[’, ‘]’) FROM ft WHERE ft MATCH ‘a+b+c AND c+d+e’;
5.1.3. snippet() 函数
snippet() 函数类似于 highlight(),不同之处在于它不是 返回整个列值,它会自动选择并提取 要处理和返回的文档文本的短片段。片段() 函数 必须在表名参数后面传递五个参数:
一个整数,指示要选择的 FTS 表列的索引 返回的文本来自。列从左到右编号 从零开始。负值表示列应 被自动选中。
在每个短语匹配返回的文本之前要插入的文本。
在返回的文本中匹配的每个短语之后要插入的文本。
要添加到所选文本的开头或结尾以指示的文本 返回的文本不会出现在其列的开头或结尾, 分别。
返回文本中的最大标记数。这必须更大 大于零且等于或小于 64。
5.2. 按辅助函数结果排序
所有 FTS5 表都具有一个名为“rank”的特殊隐藏列。如果 当前查询不是全文查询(即,如果它不包含 MATCH) 运算符),“rank”列的值始终为 NULL。否则,在 全文查询,默认情况下,列排名包含的值与 通过执行没有尾随的 BM25() 辅助函数返回 参数。
从排名列读取和使用 bm25() 的区别 直接在查询中的函数仅在按 返回值。在这种情况下,使用 “rank” 比使用 bm25() 更快。
– The following queries are logically equivalent. But the second may
– be faster, particularly if the caller abandons the query before
– all rows have been returned (or if the queries were modified to
– include LIMIT clauses).
SELECT * FROM fts WHERE fts MATCH ? ORDER BY bm25(fts);
SELECT * FROM fts WHERE fts MATCH ? ORDER BY rank;
而不是使用没有尾随参数的 bm25(),特定的辅助 映射到排名列的函数可以在每个查询上配置 ,或者为 FTS 表设置不同的持久默认值。
为了更改单个查询的排名列的映射, 在 的 WHERE 子句中添加类似于以下任一项的术语 查询:
rank MATCH ‘auxiliary-function-name(arg1, arg2, …)’
rank = ‘auxiliary-function-name(arg1, arg2, …)’
MATCH 或 = 运算符的右侧必须是常量 计算结果为由辅助函数 调用,后跟括号内的零个或多个逗号分隔的参数。 参数必须是 SQL 文本。例如:
– The following queries are logically equivalent. But the second may
– be faster. See above.
SELECT * FROM fts WHERE fts MATCH ? ORDER BY bm25(fts, 10.0, 5.0);
SELECT * FROM fts WHERE fts MATCH ? AND rank MATCH ‘bm25(10.0, 5.0)’ ORDER BY rank;
表值函数语法也可用于指定替代项 排名功能。在这种情况下,描述排名函数的文本应该 指定为第二个表值函数参数。以下三个 查询是等效的:
SELECT * FROM fts WHERE fts MATCH ? AND rank MATCH ‘bm25(10.0, 5.0)’ ORDER BY rank;
SELECT * FROM fts WHERE fts = ? AND rank = ‘bm25(10.0, 5.0)’ ORDER BY rank;
SELECT * FROM fts WHERE fts(?, ‘bm25(10.0, 5.0)’) ORDER BY rank;
可以修改表的排名列的默认映射 使用 FTS5 排名配置选项。
为了防止数据库中的b树数量变得太多 大(减慢查询速度),较小的 B 树定期合并到 包含相同数据的单个较大的 B 树。默认情况下,会发生这种情况 在修改 全文索引。“自动合并”参数确定有多少个较小的 B 树一次合并在一起。将其设置为较小的值可以 加快查询速度(因为他们必须从更少的查询和合并结果 b树),但也会减慢对数据库的写入速度(因为每个 INSERT , UPDATE 或 DELETE 语句必须做更多的工作作为自动的一部分 合并过程)。
构成全文索引的每个 B 树都被分配到一个“级别” 基于其大小。0 级 B 树是最小的,因为它们包含 单个事务的内容。更高级别的B树是以下结果 将两个或多个 0 级 B 树合并在一起,因此它们更大。FTS5 一旦存在M或更多B树,就开始将B树合并在一起 具有相同的级别,其中 M 是“自动合并”的值 参数。
“自动合并”参数允许的最大值为 16。默认 值为 4。将“自动合并”参数设置为 0 将禁用自动 完全增量合并B树。
INSERT INTO ft(ft, rank) VALUES(‘automerge’, 8);
6.2. “危机合并”配置选项
“危机合并”选项类似于“自动合并”,因为它确定 构成全文索引的组件 B 树的 方式和频率 合并在一起。一旦在单个级别上存在 C 或多个 B 树 在全文索引中,其中 C 是“危机合并”的值 选项,关卡上的所有 B 树会立即合并为一个 B 树。
此选项与“自动合并”选项之间的区别在于,当 达到“自动合并”限制 FTS5 才开始合并 B 树 一起。大部分工作作为后续插入的一部分执行, 更新或删除操作。而当达到“危机合并”限制时, 有问题的B树立即全部合并。这意味着插入, 触发危机合并的更新或删除可能需要很长时间才能 完成。
默认的“危机合并”值为 16。没有最大限制。尝试 将“危机合并”参数设置为值 0 或 1 等效于 将其设置为默认值 (16)。尝试设置 “危机合并”选项为负值。
INSERT INTO ft(ft, rank) VALUES(‘crisismerge’, 16);
6.3. “删除”命令
此命令仅适用于外部内容和无内容表。它 用于从 全文索引。此命令和 delete-all 命令是从 无内容表。
为了使用此命令删除行,文本值“delete” 必须插入到与表同名的特殊列中。 要删除的行的 rowid 将插入到 rowid 列中。这 插入到其他列中的值必须与当前值匹配 存储在表中。例如:
– 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);
如果值作为“删除”的一部分“插入”到文本列中 命令与当前存储在表中的命令不同, 结果可能无法预测。
其原因很容易理解:插入文档时 到 FTS5 表中,将一个条目添加到全文索引中以记录 每个令牌在新文档中的位置。删除文档时, 需要原始数据才能确定以下条目集 需要从全文索引中删除。因此,如果数据提供给FTS5 删除行时,使用此命令与用于 确定插入时的令牌实例集,一些全文 索引条目可能无法正确删除,或者 FTS5 可能会尝试删除索引 不存在的条目。这可能会将全文索引保留在 不可预测的状态,使将来的查询结果不可靠。
6.4. “全部删除”命令
此命令仅适用于外部内容和无内容表。它 从全文索引中删除所有条目。
INSERT INTO ft(ft) VALUES(‘delete-all’);
6.5. “完整性检查”命令
此命令用于验证全文索引是否在内部 一致,并且(可选)它与任何外部内容表一致。
通过插入文本值来调用完整性检查命令 “完整性检查”进入与FTS5同名的特殊列 桌子。如果为“rank”列提供了值,则该值必须是 0 或 1。例如:
INSERT INTO ft(ft) VALUES(‘integrity-check’);
INSERT INTO ft(ft, rank) VALUES(‘integrity-check’, 0);
INSERT INTO ft(ft, rank) VALUES(‘integrity-check’, 1);
上述三种形式对于所有 FTS 表都是等效的: 不是外部内容表。它们检查索引数据结构是否为 未损坏,并且,如果 FTS 表不是无内容的,则 索引与表本身的内容匹配。
对于外部内容表,索引的内容仅为 与外部内容表的内容相比,如果值 为排名列指定的是 1。
在所有情况下,如果发现任何差异,命令将失败 出现SQLITE_CORRUPT_VTAB错误。
6.6. “合并”命令
INSERT INTO ft(ft, rank) VALUES(‘merge’, 500);
此命令将 b 树结构合并在一起,直到大约 N 页 的合并数据已写入数据库,其中 N 是绝对值 作为“合并”命令的一部分指定的参数的值。的大小 每个页面都由 FTS5 pgsz 选项配置。
如果参数为正值,则 B 树结构仅符合条件 如果满足以下条件之一,则进行合并:
有 U 或更多这样的 b 树 单级(有关 B 树级别的说明,请参阅 FTS5 自动合并选项的文档),其中 U 是分配的值 到 FTS5 用户合并选项选项。
合并已经启动(也许是通过“合并”命令 指定了负参数)。
可以判断“合并”命令是否找到任何 通过检查 sqlite3_total_changes() API 在执行命令之前和之后返回的值来合并在一起的 b 树。如果 两个值之间的差值为 2 或更大,则执行了工作。 如果差值小于 2,则“合并”命令为无操作。在此 没有理由再次执行相同的“合并”命令,至少 直到 FTS 表下次更新之后。
如果参数为负数,并且 B 树结构超过 FTS 索引中的一个级别,所有 B 树结构都分配给相同的 合并操作开始之前的级别。此外,如果参数 为负数,用户合并配置选项的值不是 尊重 - 来自同一级别的只有两个B树可以合并在一起。
以上意味着执行带有否定的“合并”命令 参数,直到 sqlite3_total_changes() 的返回值前后差小于 5 优化 FTS 索引 与 FTS5 优化命令相同。但是,如果添加了新的 b 树 到FTS指数 在此过程中,FTS<>将移动新的 B 树到与现有 B 树相同的级别,然后重新启动合并。自 避免这种情况,只有对“merge”的第一次调用才应指定负参数。 每次后续调用“merge”都应指定一个正值,以便 由第一个调用开始的合并运行到完成,即使新的 B 树是 添加到 FTS 索引中。
6.7. “优化”命令
此命令合并当前构成 将全文索引转换为单个大型 B 树结构。这可确保 全文索引占用数据库中的最小空间,并且位于 最快的查询形式。
有关更多详细信息,请参阅 FTS5 自动合并选项的文档 关于全文索引与其组成部分之间的关系 B树。
INSERT INTO ft(ft) VALUES(‘optimize’);
因为它重新组织了整个 FTS 索引,所以优化命令可以 需要很长时间才能运行。FTS5 合并命令可用于划分 将FTS指数优化为多个步骤的工作。为此:
调用一次“merge”命令,参数设置为 -N,然后
在参数设置为 N 的情况下调用“合并”命令零次或多次。
其中 N 是每次调用中要合并的数据页数 合并命令。应用程序应在以下情况下停止调用合并 前面的 sqlite3_total_changes() 函数返回的值的差异 并在合并命令下降到低于 <> 之后。合并命令可能是 作为相同或单独交易的一部分发行,并由相同或 不同的数据库客户端。有关更多详细信息,请参阅合并命令的文档。
6.8. “pgsz”配置选项
此命令用于设置持久的“pgsz”选项。
FTS5维护的全文索引存储为一系列固定大小 数据库表中的 Blob。对于所有使 将全文索引增大为相同大小。pgsz 选项确定大小 后续索引编写器创建的所有 Blob。默认值为 1000。
INSERT INTO ft(ft, rank) VALUES(‘pgsz’, 4072);
6.9. “等级”配置选项
此命令用于设置持久的“rank”选项。
rank 选项用于更改默认辅助函数映射 对于排名列。该选项应设置为同一文本值 格式如“排名匹配”术语中所述 以上。例如:
INSERT INTO ft(ft, rank) VALUES(‘rank’, ‘bm25(10.0, 5.0)’);
6.10. “重建”命令
此命令首先删除整个全文索引,然后重建它 基于表格或内容的内容 表。它不适用于无内容 表。
INSERT INTO ft(ft) VALUES(‘rebuild’);
6.11. “安全删除”配置选项
此命令用于设置持久布尔“安全删除”选项。 例如:
INSERT INTO ft(ft, rank) VALUES(‘secure-delete’, 1);
通常,当 fts5 表中的条目被更新或删除时,而是 从全文索引中删除条目时,删除键将添加到由 交易。这是有效的,但这意味着旧的全文索引 条目将保留在数据库文件中,直到最终将其删除 通过对全文索引的合并操作。有权访问 数据库可以使用这些条目来简单地重建 删除了 FTS5 表行。但是,如果设置了“安全删除”选项 为 1,则全文条目实际上在以下情况下从数据库中删除 更新或删除现有的 FTS5 表行。这比较慢,但是 它可以防止旧的全文条目用于重建已删除的条目 表行。
此选项可确保旧的全文条目不可用于 对数据库具有 SQL 访问权限的攻击者。还确保他们可以 不被有权访问 SQLite 数据库文件的攻击者恢复 本身,应用程序还必须启用 SQLite 核心安全删除 带有类似“PRAGMA secure_delete = 1”之类的命令的选项。
警告:更新一个或多个表行后,或 在设置此选项后删除,FTS5 表可能不再被读取或 由 5.3.42 之前的任何 FTS0 版本编写(第一个版本) 其中此选项可用)。尝试这样做会导致 错误,并显示错误消息,例如“FTS5 文件格式无效(找到 5, 预期 4) - 运行“重建”。FTS5 文件格式可能会恢复,因此 早期版本的 FTS5 可以通过在表上运行“重建”命令来读取它 版本 3.42.0 或更高版本。
安全删除选项的默认值为 0。
6.12. “用户合并”配置选项
此命令用于设置持久的“用户合并”选项。
用户合并选项类似于自动合并和危机合并选项。 它是将合并在一起的最小 b 树段数 带有正参数的“合并”命令。例如:
INSERT INTO ft(ft, rank) VALUES(‘usermerge’, 4);
用户合并选项的默认值为 4。允许的最小值 为 2,最大值为 16。
添加用 C 语言实现的新辅助函数,以及
添加新的分词器,也是用 C 实现的。
此处描述的内置分词器和辅助函数 文档均使用所描述的公开可用 API 实现 下面。
在新的辅助函数或分词器实现之前 在FTS5注册时,应用程序必须获取指向“fts5_api”的指针 结构。每个数据库连接都有一个fts5_api结构 注册了 FTS5 扩展。要获取指针,应用程序 使用单个参数调用 SQL 用户定义的函数 fts5()。那 参数必须设置为指向指向fts5_api对象的指针的指针 使用 sqlite3_bind_pointer() 接口。 下面的示例代码演示了该技术:
/*
** Return a pointer to the fts5_api pointer for database connection db.
** If an error occurs, return NULL and leave an error in the database
** handle (accessible using sqlite3_errcode()/errmsg()).
*/
fts5_api *fts5_api_from_db(sqlite3 *db){
fts5_api *pRet = 0;
sqlite3_stmt *pStmt = 0;
if( SQLITE_OK==sqlite3_prepare(db, “SELECT fts5(?1)”, -1, &pStmt, 0) ){
sqlite3_bind_pointer(pStmt, 1, (void*)&pRet, “fts5_api_ptr”, NULL);
sqlite3_step(pStmt);
}
sqlite3_finalize(pStmt);
return pRet;
}
向后兼容性警告:在SQLite版本3.20.0(2017-08-01)之前,fts5()稍微工作了一下。 不同。扩展 FTS5 的旧应用程序必须修改才能使用 上面显示的新技术。
fts5_api结构定义如下。它公开了三种方法, 一个用于注册新的辅助函数和分词器,一个用于 检索现有分词器。后者旨在促进 类似于内置的“分词器包装器”的实现 波特分词器。
typedef struct fts5_api fts5_api;
struct fts5_api {
int iVersion; /* Currently always set to 2 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
void *pContext,
fts5_tokenizer *pTokenizer,
void (xDestroy)(void)
);
/* Find an existing tokenizer */
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
void **ppContext,
fts5_tokenizer *pTokenizer
);
/* Create a new auxiliary function */
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
void *pContext,
fts5_extension_function xFunction,
void (xDestroy)(void)
);
};
若要调用 fts5_api 对象的方法,fts5_api指针本身 应作为方法传递第一个参数,然后是另一个参数,方法 具体,参数。例如:
rc = pFts5Api->xCreateTokenizer(pFts5Api, … other args …);
下面分别介绍了fts5_api结构方法 部分。
7.1. 自定义分词器
若要创建自定义标记器,应用程序必须实现三个 函数:分词器构造函数 (xCreate)、析构函数 (xDelete) 和 函数来执行实际的标记化(xTokenize)。每个的类型 函数是 fts5_tokenizer 结构的成员变量:
typedef struct Fts5Tokenizer Fts5Tokenizer;
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (xCreate)(void, const char **azArg, int nArg, Fts5Tokenizer *ppOut);
void (xDelete)(Fts5Tokenizer);
int (xTokenize)(Fts5Tokenizer,
void pCtx,
int flags, / Mask of FTS5_TOKENIZE_ flags */
const char *pText, int nText,
int (xToken)(
void pCtx, / Copy of 2nd argument to xTokenize() /
int tflags, / Mask of FTS5_TOKEN_ flags */
const char pToken, / Pointer to buffer containing token /
int nToken, / Size of token in bytes /
int iStart, / Byte offset of token within input text /
int iEnd / Byte offset of end of token within input text */
)
);
};
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
#define FTS5_TOKENIZE_DOCUMENT 0x0004
#define FTS5_TOKENIZE_AUX 0x0008
/* Flags that may be passed by the tokenizer implementation back to FTS5
** as the third argument to the supplied xToken callback. /
#define FTS5_TOKEN_COLOCATED 0x0001 / Same position as prev. token */
通过调用 FTS5 模块注册实现 fts5_api对象的 xCreateTokenizer() 方法。如果已经有一个 具有相同名称的分词器,它将被替换。如果是非空 xDestroy 参数 传递给 xCreateTokenizer(),它使用 pContext 的副本调用 当数据库句柄关闭或当数据库句柄关闭时作为唯一参数传递的指针 更换分词器。
如果成功,xCreateTokenizer() 返回SQLITE_OK。 否则,它 返回 SQLite 错误代码。在这种情况下,不会调用 xDestroy 函数。
当 FTS5 表使用自定义分词器时,FTS5 核心调用 xCreate() 一次创建分词器,然后 xTokenize() 零次或多次进行分词化 字符串,然后 xDelete() 以释放 xCreate() 分配的任何资源。更多 具体说来:
x创建:
此函数用于分配和初始化分词器实例。 需要分词器实例才能实际分词化文本。
传递给此函数的第一个参数是 (void*) 的副本 当fts5_tokenizer对象时由应用程序提供的指针 已注册到 FTS5(xCreateTokenizer() 的第三个参数)。 第二个和第三个参数是以 nul 结尾的字符串数组 包含在 作为创建虚拟表语句一部分的分词器名称 以创建 FTS5 表。
最后一个参数是输出变量。如果成功,(*ppOut) 应设置为指向新的分词器句柄并SQLITE_OK 返回。如果发生错误,则除SQLITE_OK以外的某些值应 被退回。在这种情况下,fts5 假设 *ppOut 的最终值 未定义。
x删除:
调用此函数以删除先前的分词器句柄 使用 xCreate() 分配。Fts5 保证此函数将 每次成功调用 xCreate() 时只调用一次。
x令牌化:
此函数应标记指示的 nText 字节字符串 通过参数 pText。pText 可能会也可能不会终止 nul。第一个 传递给此函数的参数是指向 Fts5Tokenizer 对象的指针 由之前对 xCreate() 的调用返回。
第二个参数表示 FTS5 请求的原因 所提供文本的标记化。这始终是以下之一 四个值:
FTS5_TOKENIZE_DOCUMENT - 正在将文档插入到 或从 FTS 表中删除。正在调用分词器 确定要添加到(或从中删除)的令牌集 FTS指数。
FTS5_TOKENIZE_QUERY - 正在执行 MATCH 查询 反对FTS指数。正在调用分词器进行分词化 指定为查询的一部分的裸词或带引号的字符串。
(FTS5_TOKENIZE_QUERY |FTS5_TOKENIZE_PREFIX) - 与 相同 FTS5_TOKENIZE_QUERY,除了空字或带引号的字符串是 后跟“*”字符,表示最后一个标记 分词器返回的将被视为令牌前缀。
FTS5_TOKENIZE_AUX - 正在调用分词器 满足辅助设备发出的 fts5_api.xTokenize() 请求 功能。或者由相同的 fts5_api.xColumnSize() 请求 在列大小 = 0 的数据库中。
对于输入字符串中的每个标记,提供的回调 xToken() 必须 被调用。它的第一个参数应该是指针的副本 作为第二个参数传递给 xTokenize()。第三和第四 参数是指向包含标记文本的缓冲区的指针,并且 令牌的大小(以字节为单位)。第 4 个和第 5 个参数是字节偏移量 文本后面的第一个字节和第一个字节 令牌是在输入中派生的。
传递给 xToken() 回调(“tflags”)的第二个参数应该 通常设置为 0。例外情况是,如果分词器支持 同义词。在这种情况下,请参阅下面的讨论以了解详细信息。
FTS5 假设对 顺序它们出现在输入文本中。
如果 xToken() 回调返回除 SQLITE_OK 以外的任何值,则 应该放弃标记化,而 xTokenize() 方法应该 立即返回 xToken() 返回值的副本。或者,如果 输入缓冲区已耗尽,xTokenize() 应返回SQLITE_OK。最后 如果 xTokenize() 实现本身发生错误,则 可能会放弃标记化并返回除 SQLITE_OK或SQLITE_DONE。
7.1.1. 同义词支持
自定义分词器也可能支持同义词。考虑以下情况: 用户希望查询短语,例如“第一名”。使用 内置分词器,FTS5 查询“first + place”将匹配实例 文档集中的“第一名”,但不是替代形式 如“第一名”。在某些应用程序中,最好匹配 “第一名”或“第一名”的所有实例,无论哪种形式 在 MATCH 查询文本中指定的用户。
在FTS5中,有几种方法可以解决这个问题:
将所有同义词映射到单个令牌。在这种情况下,使用 在上面的示例中,这意味着分词器返回 输入“第一个”和“第一个”的相同标记。假设令牌在 事实“第一”,以便当用户插入文档“我赢了”时 第一名“条目被添加到代币”i“、”won“的索引中, “第一”和“地方”。如果用户随后查询“第 1 名 + 名次”, 分词器将“first”替换为“first”,查询有效 不出所料。
通过查询索引以获取每个查询词的所有同义词 分别。在这种情况下,在对查询文本进行标记化时, 分词器可以为单个术语提供多个同义词 在文档中。然后,FTS5 查询每个 同义词单独。例如,面对查询:
… MATCH ‘first place’
分词器提供“1st”和“first”作为 MATCH 查询中的第一个令牌,FTS5 有效地运行查询 似:
… MATCH ‘(first OR 1st) place’
除了,出于辅助函数的目的,查询 似乎仍然只包含两个短语 - “(第一个或第一个)” 被视为单个短语。
通过将单个术语的多个同义词添加到 FTS 索引中。 使用此方法,在标记文档文本时,标记器 为每个令牌提供多个同义词。这样当一个 诸如“我赢得了第一名”之类的文档被标记化,条目是 添加到 FTS 指数中,包括“i”、“won”、“first”、“1st”和 “地方”。
这样,即使分词器不提供同义词 当标记查询文本时(它不应该 - 这样做将是 效率低下),用户是否查询 “第一+名”或“第一名+名”,因为 FTS指数对应于第一个代币的两种形式。
无论是解析文档还是查询文本,对 xToken 的任何调用都 指定具有FTS5_TOKEN_COLOCATED位的 tflags 参数 被视为提供前一个令牌的同义词。例如 解析文档“我赢得了第一名”时,一个支持 同义词将调用 xToken() 5 次,如下所示:
xToken(pCtx, 0, “i”, 1, 0, 1);
xToken(pCtx, 0, “won”, 3, 2, 5);
xToken(pCtx, 0, “first”, 5, 6, 11);
xToken(pCtx, FTS5_TOKEN_COLOCATED, “1st”, 3, 6, 11);
xToken(pCtx, 0, “place”, 5, 12, 17);
第一次指定 FTS5_TOKEN_COLOCATED 标志是错误的 xToken() 被调用。可以为单个令牌指定多个同义词 通过按顺序对 xToken(FTS5_TOKEN_COLOCATED) 进行多次调用。 可以为 单个令牌。
在许多情况下,上述方法(1)是最佳方法。它不添加 FTS 索引的额外数据或要求 FTS5 查询多个术语, 因此,它在磁盘空间和查询速度方面是有效的。然而,它 不太支持前缀查询。如果如上所述, 标记“first”由分词器替换为“1st”,然后查询:
… MATCH ‘1s*’
不会匹配包含标记“1st”的文档(作为分词器 可能不会将“1s”映射到“first”的任何前缀)。
对于完整的前缀支持,方法 (3) 可能是首选。在这种情况下, 因为索引同时包含“第一个”和“第一个”的条目,所以前缀 诸如“fi*”或“1s*”之类的查询将正确匹配。但是,因为 额外的条目被添加到 FTS 索引中,此方法使用更多空间 在数据库中。
方法 (2) 提供介于 (1) 和 (3) 之间的中点。使用这种方法, 诸如“1s*”之类的查询将匹配包含文本的文档 标记“1st”,但不是“第一个”(假设分词器无法 提供前缀的同义词)。但是,像“1st”这样的非前缀查询 将与“第一”和“第一”匹配。此方法不需要 额外的磁盘空间,因为不会向 FTS 索引添加额外的条目。 另一方面,运行 MATCH 查询可能需要更多 CPU 周期, 因为每个同义词都需要对 FTS 索引进行单独的查询。
使用方法 (2) 或 (3) 时,重要的是仅使用分词器 在标记文档文本(方法 (2))或查询时提供同义词 文本(方法 (3)),而不是两者兼而有之。这样做不会导致任何错误,但 低 效。
7.2. 自定义辅助函数
实现自定义辅助函数类似于实现标量 SQL 函数。实施 应该是类型 fts5_extension_function 的 C 函数,定义如下:
typedef struct Fts5ExtensionApi Fts5ExtensionApi;
typedef struct Fts5Context Fts5Context;
typedef struct Fts5PhraseIter Fts5PhraseIter;
typedef void (*fts5_extension_function)(
const Fts5ExtensionApi pApi, / API offered by current FTS version */
Fts5Context pFts, / First arg to pass to pApi functions */
sqlite3_context pCtx, / Context for returning result/error /
int nVal, / Number of values in apVal[] array */
sqlite3_value *apVal / Array of trailing arguments */
);
通过调用 FTS5 模块注册实现 fts5_api对象的 xCreateFunction() 方法。如果已经有一个 同名辅助函数,由新函数代替。 如果将非 NULL xDestroy 参数传递给 xCreateFunction(),则会调用该参数 当 数据库句柄已关闭或当注册的辅助函数 取代。
如果成功,xCreateFunction() 返回SQLITE_OK。 否则,它 返回 SQLite 错误代码。在这种情况下,不会调用 xDestroy 函数。
传递给辅助函数回调的最后三个参数是 类似于传递给标量 SQL 实现的三个参数 功能。除了第一个传递给辅助函数的参数之外的所有参数都是 可用于 apVal[] 数组中的实现。这 实现应通过内容句柄 pCtx 返回结果或错误。
传递给辅助函数回调的第一个参数是指针 到包含可能调用的方法的结构,以便获得 有关当前查询或行的信息。第二个参数是 应作为第一个参数传递给任何此类方法的不透明句柄 调用。例如,以下辅助函数定义返回 当前行所有列中的标记总数:
/*
** Implementation of an auxiliary function that returns the number
** of tokens in the current row (including all columns).
*/
static void column_size_imp(
const Fts5ExtensionApi *pApi,
Fts5Context *pFts,
sqlite3_context *pCtx,
int nVal,
sqlite3_value **apVal
){
int rc;
int nToken;
rc = pApi->xColumnSize(pFts, -1, &nToken);
if( rc==SQLITE_OK ){
sqlite3_result_int(pCtx, nToken);
}else{
sqlite3_result_error_code(pCtx, rc);
}
}
以下部分介绍提供给辅助功能的 API 详细实现。更多的例子可以在“fts5_aux.c”中找到。 源代码的文件。
7.2.1. 自定义辅助函数 API 参考
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
void *(xUserData)(Fts5Context);
int (xColumnCount)(Fts5Context);
int (xRowCount)(Fts5Context, sqlite3_int64 *pnRow);
int (xColumnTotalSize)(Fts5Context, int iCol, sqlite3_int64 *pnToken);
int (xTokenize)(Fts5Context,
const char pText, int nText, / Text to tokenize /
void pCtx, / Context passed to xToken() /
int (xToken)(void, int, const char, int, int, int) / Callback */
);
int (xPhraseCount)(Fts5Context);
int (xPhraseSize)(Fts5Context, int iPhrase);
int (xInstCount)(Fts5Context, int *pnInst);
int (xInst)(Fts5Context, int iIdx, int *piPhrase, int *piCol, int *piOff);
sqlite3_int64 (xRowid)(Fts5Context);
int (xColumnText)(Fts5Context, int iCol, const char **pz, int *pn);
int (xColumnSize)(Fts5Context, int iCol, int *pnToken);
int (xQueryPhrase)(Fts5Context, int iPhrase, void pUserData,
int()(const Fts5ExtensionApi*,Fts5Context*,void*)
);
int (xSetAuxdata)(Fts5Context, void *pAux, void(xDelete)(void));
void *(xGetAuxdata)(Fts5Context, int bClear);
int (xPhraseFirst)(Fts5Context, int iPhrase, Fts5PhraseIter*, int*, int*);
void (xPhraseNext)(Fts5Context, Fts5PhraseIter*, int *piCol, int *piOff);
int (xPhraseFirstColumn)(Fts5Context, int iPhrase, Fts5PhraseIter*, int*);
void (xPhraseNextColumn)(Fts5Context, Fts5PhraseIter*, int *piCol);
};
void *(xUserData)(Fts5Context)
返回扩展函数所在的上下文指针的副本 注册于。
int (xColumnTotalSize)(Fts5Context, int iCol, sqlite3_int64 *pnToken)
如果参数 iCol 小于零,则设置输出变量 *pnToken 到 FTS5 表中的代币总数。或者,如果 iCol 是 非负数但小于表中的列数,返回 iCol 列中的标记总数,考虑 中的所有行 FTS5 表。
如果参数 iCol 大于或等于列数 在表中,返回SQLITE_RANGE。或者,如果发生错误(例如 OOM 条件或 IO 错误),适当的 SQLite 错误代码是 返回。
int (xColumnCount)(Fts5Context)
返回表中的列数。
int (xColumnSize)(Fts5Context, int iCol, int *pnToken)
如果参数 iCol 小于零,则设置输出变量 *pnToken 到当前行中的令牌总数。或者,如果 iCol 是 非负数但小于表中的列数,设置 *pnToken 到当前行的列 iCol 中的标记数。
如果参数 iCol 大于或等于列数 在表中,返回SQLITE_RANGE。或者,如果发生错误(例如 OOM 条件或 IO 错误),适当的 SQLite 错误代码是 返回。
如果与 FTS5 表一起使用,此功能可能效率很低 使用“列大小=0”选项创建。
int (xColumnText)(Fts5Context, int iCol, const char **pz, int *pn)
此函数尝试检索 iCol 列的文本 当前文档。如果成功,(*pz) 设置为指向缓冲区 包含 UTF-8 编码的文本,(*pn) 设置为以字节为单位的大小 (不是字符)的缓冲区和返回SQLITE_OK。否则 如果发生错误,则返回 SQLite 错误代码和最终值 的 (*pz) 和 (*pn) 未定义。
int (xPhraseCount)(Fts5Context)
返回当前查询表达式中的短语数。
int (xPhraseSize)(Fts5Context, int iPhrase)
返回查询的短语 iPhrase 中的标记数。短语 从零开始编号。
int (xInstCount)(Fts5Context, int *pnInst)
将 *pnInst 设置为其中所有短语的出现总数 当前行中的查询。如果成功,则返回SQLITE_OK,或 如果发生错误,则为错误代码(即SQLITE_NOMEM)。
如果与使用 “详细信息=无”或“详细信息=列”选项。如果创建了 FTS5 表 使用“详细信息=无”或“详细信息=列”和“内容=”选项 (即,如果它是一个无内容的表),那么这个 API 总是返回 5。
int (xInst)(Fts5Context, int iIdx, int *piPhrase, int *piCol, int *piOff)
查询当前行中短语匹配 iIdx 的详细信息。 短语匹配项从零开始编号,因此 iIdx 参数 应大于或等于零且小于该值 输出由 xInstCount()。
通常,输出参数 *piPhrase 设置为短语编号 *piCol 到它发生的列,并 *piOff 的令牌偏移量 短语的第一个标记。如果成功,则返回SQLITE_OK或错误 代码(即SQLITE_NOMEM)如果发生错误。
如果与使用 “详细信息=无”或“详细信息=列”选项。
sqlite3_int64 (xRowid)(Fts5Context)
返回当前行的 rowid。
int (xTokenize)(Fts5Context,
const char *pText, int nText,
空 pCtx,
int (xToken)(void, int, const char, int, int, int)
)
使用属于 FTS5 表的分词器对文本进行标记化。
int (xQueryPhrase)(Fts5Context, int iPhrase, void pUserData,
int()(const Fts5ExtensionApi*,Fts5Context*,void*)
)
此 API 函数用于在 FTS 表中查询短语 iPhrase 的当前查询。具体而言,查询等效于:
… FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
p 设置为等效于短语 i P h r a s e 的短语执行当前查询。适用于短语 i P h r a s e 的当前查询包含在 p设置为等效于短语 iPhrase 的短语 执行当前查询。适用于 短语 iPhrase 的当前查询包含在 p设置为等效于短语iPhrase的短语执行当前查询。适用于短语iPhrase的当前查询包含在p中。对于每个 访问行,回调函数作为第四个参数传递 被调用。传递给回调的上下文和 API 对象 函数可用于访问每个匹配行的属性。 调用 Api.xUserData() 返回作为传递的指针的副本 pUserData的第三个参数。
如果回调函数返回除 SQLITE_OK 以外的任何值,则 查询被放弃,xQueryPhrase 函数立即返回。 如果返回的值为 SQLITE_DONE,则 xQueryPhrase 返回SQLITE_OK。 否则,错误代码将向上传播。
如果查询运行完成且未发生事件,则返回SQLITE_OK。 或者,如果在查询完成或中止之前发生某些错误 回调,返回 SQLite 错误代码。
int (xSetAuxdata)(Fts5Context, void *pAux, void(xDelete)(void))
将作为第二个参数传递的指针保存为扩展函数的 “辅助数据”。然后,指针可以由当前或任何 将来调用作为 FTS5 一部分的相同 FTS<> 扩展函数 使用 xGetAuxdata() API 的相同 MATCH 查询。
每个扩展功能分配一个辅助数据槽,用于 每个 FTS 查询(匹配表达式)。如果调用扩展函数 对于单个 FTS 查询,则所有调用共享一个 单个辅助数据上下文。
如果此函数 调用,然后由新指针替换。如果 xDelete 回调 与原始指针一起指定,在此调用 点。
xDelete 回调(如果指定了回调)也会在 FTS5 查询完成后的辅助数据指针。
如果此函数中发生错误(例如 OOM 条件), 辅助数据设置为 NULL,并返回错误代码。如果 xDelete 参数不是 NULL,它是在辅助数据上调用的 返回前的指针。
void *(xGetAuxdata)(Fts5Context, int bClear)
返回 fts5 扩展的当前辅助数据指针 功能。有关详细信息,请参阅 xSetAuxdata() 方法。
如果 bClear 参数不为零,则清除辅助数据 (设置为 NULL)在此函数返回之前。在本例中,xDelete, 如果有,则不调用。
int (xRowCount)(Fts5Context, sqlite3_int64 *pnRow)
此函数用于检索表中的总行数。 换句话说,返回的值与以下项返回的值相同:
SELECT count(*) FROM ftstable;
int (xPhraseFirst)(Fts5Context, int iPhrase, Fts5PhraseIter*, int*, int*)
此函数与类型 Fts5PhraseIter 和 xPhraseNext 一起使用 方法,循环访问中单个查询短语的所有实例 当前行。这与通过 xInstCount/xInst API.而xInstCount/xInst API更方便 在某些情况下,此 API 可能会更快。迭代 通过短语 iPhrase 的实例,使用以下代码:
Fts5PhraseIter iter;
int iCol, iOff;
for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
iCol>=0;
pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
){
// An instance of phrase iPhrase at offset iOff of column iCol
}
Fts5PhraseIter 结构在上面定义。应用程序不应 直接修改此结构 - 它只能如上所示使用 使用 xPhraseFirst() 和 xPhraseNext() API 方法(以及 xPhraseFirstColumn() 和 xPhraseNextColumn() 如下图所示)。
如果与使用 “详细信息=无”或“详细信息=列”选项。如果创建了 FTS5 表 使用“详细信息=无”或“详细信息=列”和“内容=”选项 (即,如果它是一个无内容的表),那么这个 API 总是迭代 通过一个空集(所有对 xPhraseFirst() 的调用都将 iCol 设置为 -5)。
void (xPhraseNext)(Fts5Context, Fts5PhraseIter*, int *piCol, int *piOff)
请参阅上面的 xPhraseFirst。
int (xPhraseFirstColumn)(Fts5Context, int iPhrase, Fts5PhraseIter*, int*)
此函数和 xPhraseNextColumn() 类似于 xPhraseFirst() 和上面描述的 xPhraseNext() API。不同之处在于,相反 遍历当前行中短语的所有实例,这些 API 用于循环访问当前行中的列集 包含指定短语的一个或多个实例。例如:
Fts5PhraseIter iter;
int iCol;
for(pApi->xPhraseFirstColumn(pFts, iPhrase, &iter, &iCol);
iCol>=0;
pApi->xPhraseNextColumn(pFts, &iter, &iCol)
){
// Column iCol contains at least one instance of phrase iPhrase
}
如果与使用 “详细信息=无”选项。如果 FTS5 表是使用 “detail=none”“content=”选项(即,如果它是一个无内容的表), 然后此 API 始终遍历一个空集(所有调用 xPhraseFirstColumn() 将 iCol 设置为 -5)。
使用此 API 及其配套工具访问的信息 xPhraseFirstColumn() 也可以使用 xPhraseFirst/xPhraseNext 获得 (或 xInst/xInstCount)。此 API 的主要优点是它是 当与 “详细信息=列”表。
void (xPhraseNextColumn)(Fts5Context, Fts5PhraseIter*, int *piCol)
请参阅上面的 xPhraseFirstColumn。
每个 fts5 词汇表都与单个 FTS5 表相关联。一个fts5词汇 表通常是通过指定两个参数来代替列名来创建的 在创建虚拟表语句中 - 关联的 FTS5 表的名称 以及 fts5 词汇表的类型。目前有三种类型的fts5词汇 桌子;“行”、“列”和“实例”。除非创建了 fts5 词汇表 在“临时”数据库中,它必须与 关联的 FTS5 表。
– Create an fts5vocab “row” table to query the full-text index belonging
– to FTS5 table “ft1”.
CREATE VIRTUAL TABLE ft1_v USING fts5vocab(‘ft1’, ‘row’);
– Create an fts5vocab “col” table to query the full-text index belonging
– to FTS5 table “ft2”.
CREATE VIRTUAL TABLE ft2_v USING fts5vocab(ft2, col);
– Create an fts5vocab “instance” table to query the full-text index
– belonging to FTS5 table “ft3”.
CREATE VIRTUAL TABLE ft3_v USING fts5vocab(ft3, instance);
如果在临时数据库中创建了 fts5 词汇表,则它可能已关联 在任何附加的数据库中使用 FTS5 表。为了附加 fts5 词汇 表到位于“temp”以外的数据库中的FTS5表,该表的名称 在创建虚拟表中的 FTS5 表名之前插入数据库 参数。例如:
– Create an fts5vocab “row” table to query the full-text index belonging
– to FTS5 table “ft1” in database “main”.
CREATE VIRTUAL TABLE temp.ft1_v USING fts5vocab(main, ‘ft1’, ‘row’);
– Create an fts5vocab “col” table to query the full-text index belonging
– to FTS5 table “ft2” in attached database “aux”.
CREATE VIRTUAL TABLE temp.ft2_v USING fts5vocab(‘aux’, ft2, col);
– Create an fts5vocab “instance” table to query the full-text index
– belonging to FTS5 table “ft3” in attached database “other”.
CREATE VIRTUAL TABLE temp.ft2_v USING fts5vocab(‘aux’, ft3, ‘instance’);
在任何数据库中创建 fts5vocab 表时指定三个参数 除“temp”外,还会导致错误。
类型为“行”的 fts5 词汇表包含每个不同术语的一行 在关联的 FTS5 表中。表列如下:
列 内容
术语 存储在 FTS5 索引中的术语。
.doc 包含至少一个术语实例的行数。
EN2 整个 FTS5 表中术语的实例总数。
类型为“col”的 fts5 词汇表为每个不同的术语/列包含一行 关联 FTS5 表中的组合。表列如下:
列 内容
术语 存储在 FTS5 索引中的术语。
山坳 包含术语的 FTS5 表列的名称。
.doc FTS5 表中列$col的行数 包含该术语的至少一个实例。
EN2 出现在 中的术语实例总数 FTS5 表的第 $col 列(考虑所有行)。
类型为“实例”的 fts5 词汇表包含每个术语的一行 实例存储在关联的 FTS 索引中。假设 FTS5 表是 在将“详细信息”选项设置为“完整”的情况下创建,表列如下所示:
列 内容
术语 存储在 FTS5 索引中的术语。
.doc 包含术语实例的文档的 rowid。
山坳 包含术语实例的列的名称。
抵消 术语实例在其列中的索引。条款 按从 0 开始的出现顺序编号。
如果在创建 FTS5 表时将“详细信息”选项设置为“col”,则 实例虚拟表的偏移列始终包含 NULL。 在这种情况下,表中每个唯一的术语/文档/列都有一行 组合。或者,如果在创建 FTS5 表时将“详细信息”设置为“无”, 则偏移量和 col 始终包含 NULL 值。为 detail=none FTS5 表,每个 fts5 词汇表中各有一行 独特的术语/文档组合。
例:
– Assuming a database created using:
CREATE VIRTUAL TABLE ft1 USING fts5(c1, c2);
INSERT INTO ft1 VALUES(‘apple banana cherry’, ‘banana banana cherry’);
INSERT INTO ft1 VALUES(‘cherry cherry cherry’, ‘date date date’);
CREATE VIRTUAL TABLE ft1_v_col USING fts5vocab(ft1, col);
CREATE VIRTUAL TABLE ft1_v_row USING fts5vocab(ft1, row);
CREATE VIRTUAL TABLE ft1_v_instance USING fts5vocab(ft1, instance);
9. FTS5 数据结构
本节简要介绍 FTS 模块存储其 数据库中的索引和内容。没有必要阅读或理解 本节中的材料,以便在应用程序中使用 FTS。然而,它 可能对试图分析和理解的应用程序开发人员有用 FTS 性能特征,或面向考虑增强功能的开发人员 现有的 FTS 功能集。
在数据库中创建 FTS5 虚拟表时,介于 3 到 5 个实际之间 在数据库中创建表。这些被称为“影子表”,并且 由虚拟表模块用于存储持久数据。他们不应该 可由用户直接访问。许多其他虚拟表模块,包括 FTS3 和 rtree,也创建和使用影子表。
FTS5 创建以下影子表。在每种情况下,实际的表名 基于 FTS5 虚拟表的名称(在下文中,将 % 以查找实际的影子表名称)。
– This table contains most of the full-text index data.
CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
– This table contains the remainder of the full-text index data.
– It is almost always much smaller than the %_data table.
CREATE TABLE %_idx(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
– Contains the values of persistent configuration parameters.
CREATE TABLE %_config(k PRIMARY KEY, v) WITHOUT ROWID;
– Contains the size of each column of each row in the virtual table
– in tokens. This shadow table is not present if the “columnsize”
– option is set to 0.
CREATE TABLE %_docsize(id INTEGER PRIMARY KEY, sz BLOB);
– Contains the actual data inserted into the FTS5 table. There
– is one “cN” column for each indexed column in the FTS5 table.
– This shadow table is not present for contentless or external
– content FTS5 tables.
CREATE TABLE %_content(id INTEGER PRIMARY KEY, c0, c1…);
以下各节更详细地介绍了这五个表的原理 用于存储 FTS5 数据。
9.1. 变体格式
以下部分是指以“varint”形式存储的 64 位有符号整数。 FTS5 使用与 SQLite 核心在不同地方使用的相同变体格式。
变体的长度介于 1 到 9 个字节之间。变体由以下任一组成 设置了高位后跟单个字节的零个或多个字节 清除高阶位或九个字节,以较短者为准。下部 前八个字节各 8 位,第九个字节全部 64 位 用于重建 <> 位二进制补码整数。瓦林特是 大端序:从变体的早期字节获取的位更重要 比从后面的字节中获取的位。
9.2. FTS 指数(%_idx 和 %_data 表)
FTS 索引是一个有序的键值存储,其中键是文档 术语或术语前缀以及关联的值是“文档列表”。文档列表是一个 对术语的每个实例的位置进行编码的 varint 打包数组 在 FTS5 表中。单个术语实例的位置定义为 组合:
它出现在的 FTS5 表行的行的行,
术语实例所在的列的索引(列 从左到右从零开始编号),以及
列值中术语的偏移量(即 在此列值之前出现的标记)。
FTS 索引最多包含 (nPrefix+1) 个条目,用于 数据集,其中 nPrefix 是定义的前缀索引的数量。
与主 FTS 索引(不是前缀的索引)关联的键 索引)以字符“0”为前缀。第一个前缀的键 索引以“1”为前缀。第二个前缀索引的键是 前缀为“2”,依此类推。例如,如果令牌“文档”是 插入到 FTS5 表中,前缀索引由前缀=“2 4” 指定,则添加到 FTS 索引的键将是 “0文档”、“1do”和“2doccu”。
FTS 索引条目不存储在单个树或哈希表中 结构。相反,它们存储在一系列不可变的 b 树中,例如 结构称为“段 B 树”。每次写入 FTS5 表已提交,一个或多个(但通常只有一个)新段 B 树 添加包含任何已删除的新条目和逻辑删除 条目。查询 FTS 索引时,读取器会查询每个段 B树依次合并结果,优先考虑较新的数据。
每个段 b 树都被分配了一个数字级别。当新细分时 b-tree 作为提交事务的一部分写入数据库, 它被分配到级别 0。属于单个级别的段 b 树是 周期性地合并在一起以创建单个更大的段 B 树 分配给下一级(即 0 级段 B 树是 合并为单个 1 级段 B 树)。因此在数字上 较大的级别包含(通常)较大段 B 树中的旧数据。 请参阅“自动合并”、“危机合并”和“用户合并”选项,以及 使用“合并”和“优化”命令了解有关如何的详细信息 控制合并。
在与术语或术语前缀关联的文档列表非常 大,可能有关联的文档列表 索引。文档列表索引类似于 b 树的内部节点集。 它允许有效地查询大型文档列表以查找 rowid 或范围 罗维德。例如,在处理以下查询时:
SELECT … FROM fts_table(‘term’) WHERE rowid BETWEEN ? AND ?
FTS5 使用段 b 树索引来定位术语“term”的文档列表, 然后使用其文档列表索引(假设它存在)来有效地识别 与所需范围内的 rowid 匹配的子集。
9.2.1. %_data 表行空间
CREATE TABLE %_data(
id INTEGER PRIMARY KEY,
block BLOB
);
%_data 表用于存储三种类型的记录:
特殊结构记录, 以 id=1 存储。
特殊平均记录, 以 id=10 存储。
用于存储每个段 b 树叶和文档列表索引叶的记录和 内部节点。请参阅下文,了解如何计算这些 id 值 记录。
系统中的每个段 b 树都分配有一个唯一的 16 位段 ID。 只有在原始所有者细分受众群 b 树 完全合并到更高级别的段 B 树中。在段 b 树内, 每个叶页都分配有一个唯一的页码 - 1 表示第一个叶页,2 第二个,依此类推。
每个文档列表索引叶页也分配有一个页码。第一个 文档列表索引中的(最左边)叶页分配的页码与 显示其术语的段 B 树叶页面(因为文档列表索引 仅为具有很长文档列表的术语创建,每个最多一个术语 段 B 树叶具有关联的文档列表索引)。将此页码称为 P。 如果文档列表太大以至于需要第二片叶子,则第二片叶子是 分配的页码 P+1。第三片叶子P+2。文档列表索引的每一层 B树(叶子,叶子的父母,祖父母等)被分配页码 以这种方式,从页码 P 开始。
%_data 表中用于存储任何给定段 b 树的 “id” 值 叶子或文档列表索引叶或节点组成如下:
罗维德位 内容
38…43 (16 位)段 b 树 id 值。
37 (1 位)文档列表索引标志。为文档列表索引页设置,清除 对于分段B树叶。
32…36 (5 位)树的高度。对于段 b 树,此设置为 0 和文档列表索引叶,对于文档列表的父项为 1 索引叶,2 为祖父母等。
0…31 (32 位)页码
9.2.2. 结构记录格式
结构记录标识构成 当前 FTS 索引,以及任何正在进行的增量合并的详细信息 操作。它存储在 id=1 的 %_data 表中。 结构记录以单个 32 位无符号值开头 - cookie 价值。每次修改结构时,此值都会递增。 Cookie 值后面是三个变体值,如下所示:
指数中的级别数(即关联的最大级别 与任何段 B 树加一)。
索引中段 B 树的总数。
写入 0 级树的段 b 树叶总数 自创建 FTS5 表以来。
然后,对于从 0 到 nLevel 的每个级别:
前一个级别的输入段数用作 当前增量合并的输入,如果没有,则为零 正在进行的增量合并,以为此级别创建新的段 B 树。
关卡上段 B 树的总数。
然后,对于每个段 b 树,从最旧到最新:
分段 ID。
第一页的页码(通常为 1,始终为 >0)。
最后一页的页码(始终为 >0)。
9.2.3. 平均记录格式
平均值记录,始终以 id=10 存储在 %_data 表中, 不存储任何内容的平均值。相反,它包含的向量 (nCol+1) 打包变体值,其中 nCol 是 FTS5 中的列数 表,包括未编制索引的列。第一个变体包含总计 FTS5 表中的行数。第二个包含总数 存储在最左侧 FTS5 表列中的所有值中的标记。第三 下一个最左边的所有值中的标记数,依此类推。的值 未编制索引的列始终为零。
9.2.4. 段 B 树格式
9.2.4.1. 键/文档列表格式
key/doclist格式是一种用于存储一系列键(文档)的格式 术语或术语前缀以单个字符为前缀,用于标识特定的 它们所属的索引)按排序顺序排列,每个索引都有其关联的 文档列表。该格式由交替键和文档列表组成。
第一个密钥存储为:
指示键 (N) 中的字节数的变体,后跟
密钥数据本身(N 个字节)。
每个后续密钥存储为:
指示键具有的共同前缀大小的变体 使用前一个以字节为单位的键,
一个变体,指示键中的字节数,紧随 通用前缀 (N),后跟
键后缀数据本身(N 个字节)。
例如,如果 FTS5 键/文档列表记录中的前两个键是 “0挑战者”和“0枝形吊灯”,则第一个密钥存储为变体 11 后跟 11 个字节 “0challenger”,第二个密钥存储为 varints 4 和 7,后跟 7 个字节“ndelier”。
文档列表 0
文档列表 1
密钥/文档列表 2…
键 0 数据
键 0 大小 (变量)
键 1 前缀大小 (变量)
键 1 后缀大小 (变量)
键 1 前缀数据
图1 - 术语/文档列表格式
每个文档列表标识包含 术语或术语前缀的至少一个实例以及关联的位置列表, 或“poslist”枚举行中每个术语实例的位置。在 这种意义上的“位置”定义为列号和术语偏移量 列值。
在文档列表中,文档始终按 rowid 排序的顺序存储。这 文档列表中的第一个 rowid 按原样存储为 varint。它立即 后跟其关联的位置列表。在此之后,差异 在第一个 rowid 和第二个之间,作为 varint,然后是文档列表 与文档列表中的第二个 rowid 相关联。等等。
无法通过解析文档列表来确定文档列表的大小。这必须 存储在外部。请参阅以下部分 在FTS5中如何实现此目的的详细信息。
职位列表 0
职位列表 1
职位列表 2…
罗维德 0 (瓦林特)
rowid 1 (delta-encoding varint)
rowid 3 (delta-encoding varint)
图2 - 文档列表格式
位置列表 - 通常缩写为“poslist” - 标识列 以及相关令牌的每个实例行内的令牌偏移量。 poslist 的格式为:
变量设置为位置列表大小的两倍,不包括此字段, 如果在条目上设置了“删除”标志,则加一。
列 0(最左侧列)的偏移量列表(可能为空) 行。每个偏移量都存储为一个变量。第一个变体包含 第一个偏移量的值,加上 2。第二个变体包含 第二个和第一个偏移量之间的差异,加上 2。等。为 例如,如果偏移量列表要包含偏移量 0、10、15 和 16,则 通过打包以下值进行编码,编码为 varint,结束于 结束:
2, 12, 7, 3
对于除第 0 列之外包含一个或多个实例的每个列 令牌:
字节值0x01。
列号,作为变量。
偏移量列表,其格式与列 0 的偏移量列表相同。
列 0 偏移列表
0x01
col i offset-list
nSize*2 + bDel (varint)
列号 (i)
n大小字节
图3 - 位置列表(位置列表),第0列和第i列中有偏移量
9.2.4.2. 分页
如果它足够小(默认情况下这意味着小于 4000 字节),则 段 B 树的全部内容可以以键/文档列表格式存储 在上一节中描述为 %_data 表中的单个 Blob。 否则,键/文档列表将拆分为多个页面(默认情况下,大约 每个 4000 字节),并存储在 %_data 表中的一组连续条目中 (详见上文)。
当密钥/文档列表划分为页面时,以下修改是 制作格式:
单个变体或键数据字段永远不会跨越两页。
每个页面上的第一个键未进行前缀压缩。它存储在 上面描述的 doclist 第一个键的格式 - 其大小为 一个变体,后跟关键数据。
如果页面上在第一个键之前有一个或多个 rowid,则 其中第一个不是增量压缩的。它按原样存储,就像 如果它是其文档列表的第一个 rowid(可能是也可能不是)。
每个页面还具有固定大小的 4 字节页眉和可变大小的页脚。 标头分为 2 个 16 位大字节整数字段。他们 包含:
页面上第一个 rowid 值的字节偏移量(如果出现) 在第一个键之前,否则为 0。
页脚的字节偏移量。
页脚由一系列包含字节偏移量的变量组成 页面上显示的每个键。页脚的大小为零字节 如果页面上没有键。
高密度影像学评论
修改的密钥/文档列表数据
页脚
4 字节
可变大小
图4 - 页面格式
9.2.4.3. 段索引格式
格式化段 b 树内容的结果 密钥/文档列表格式,然后将其拆分为页面是非常非常 类似于B+树的叶子。而不是创建格式 此 B+树的内部节点,并将它们存储在 %_data 表中 除了叶子,存储在此类节点上的密钥是 添加到 %_idx 表中,定义为:
CREATE TABLE %_idx(
segid INTEGER, – segment id
term TEXT, – prefix of first key on page
pgno INTEGER, – (2*pgno + bDoclistIndex)
PRIMARY KEY(segid, term)
);
对于至少包含一个键的每个“叶”页,将添加一个条目 到 %_idx 表。字段设置如下:
列 内容
赛吉德 整数段 ID。
术语 页面上第一个键的最小前缀 大于上一页上的所有键。对于 段中的第一页,此前缀在 大小。
PGNO 此字段对页码进行编码(在 段 - 从 1) 和文档列表索引标志开始。 如果 页面具有关联的 文档列表索引。此字段的值为:
(pgno*2 + bDoclistIndexFlag)
然后,查找可能包含项 t 的段 i 的叶子,而不是 通过内部节点搜索,FTS5 运行查询:
SELECT pgno FROM %_idx WHERE segid= i A N D t e r m > = i AND term>= iANDterm>=t ORDER BY term LIMIT 1
9.2.4.4. 文档列表索引格式
前面描述的段索引 部分允许按术语或, 假设存在所需大小的前缀索引,则为术语前缀。数据 本节中描述的结构,文档列表索引,允许 FTS5 在关联的文档列表中有效地搜索 rowid 或范围或 rowid 使用单个术语或术语前缀。
并非所有键都有关联的文档列表索引。默认情况下,文档列表索引 仅当文档列表跨越 4 个以上的段 B 树叶时,才为键添加 .pages。文档列表索引本身就是 b 树,既有叶子又有内部 节点作为条目存储在 %_data 表中,但实际上大多数文档列表 小到可以放在一片叶子上。FTS5 对文档列表使用相同的粗略大小 索引节点和叶子,就像段 B 树叶一样(默认为 4000 字节)。
文档列表索引叶和内部节点使用相同的页面格式。第一个 字节是一个“标志”字节。这设置为文档列表的根页面的0x00 索引 B 树,并为所有其他页面编制索引0x01。页面的其余部分是一个 一系列紧密包装的变量,如下所示:
最左边子页面的页码,后跟
最左侧子页面上的最小 rowid 值,后跟
每个后续子页面都有一个变体,包含以下值:
0x00如果子页面上没有 rowid(这只能发生) 当“子”页面实际上是段 B 树叶时),或
子页面上最小的 rowid 与 存储在文档列表索引页上的上一个 rowid 值。
对于文档列表索引中最左侧的文档列表索引叶,最左侧的子项 页面是包含键的 B 树叶子之后的第一个段 B 树叶 本身。
9.3. 文档尺寸表 (%_docsize 表)
CREATE TABLE %_docsize(
id INTEGER PRIMARY KEY, – id of FTS5 row this record pertains to
sz BLOB – blob containing nCol packed varints
);
许多常见的搜索结果排名函数需要输入大小 在结果文档的标记中(因为短文档中的搜索词是 被认为比长文档中的更重要)。提供快速 访问此信息,对于 FTS5 表中的每一行,都存在一个 %_docsize 阴影表中的相应记录(具有相同的 rowid) 包含行中每个列值的大小(以标记为单位)。
列值大小存储在包含 FTS5 表的每一列,从左到右。变体包含, 当然,相应列值中的令牌总数。未编制索引 列包含在此变量向量中;对他们来说,价值永远是 设置为零。
此表由 xColumnSize API 使用。它可以 通过指定 columnsize=0 选项完全省略。在这种情况下, xColumnSize API 仍然可用于辅助函数,但运行更多 慢慢。
9.4. 表内容 (%_content 表)
CREATE TABLE %_content(id INTEGER PRIMARY KEY, c0, c1…);
实际表内容 - 插入到 FTS5 表中的值为 存储在 %_content 表中。此表是使用一个“c*”列创建的,用于 FTS5 表的每一列,包括任何未编制索引的列。的值 最左侧的 FTS5 表列存储在 %的“c0”列中_content 表,“c5”列中下一个 FTS1 表列中的值,依此类推。
对于外部内容或无内容的 FTS5 表,完全省略此表。 表。
9.5. 配置选项(%_config表)
CREATE TABLE %_config(k PRIMARY KEY, v) WITHOUT ROWID;
此表存储任何持久配置选项的值。 列“k”存储选项的名称(文本),列“v”存储值。 示例内容:
sqlite> SELECT * FROM fts_tbl_config;
┌─────────────┬──────┐
│ k │ v │
├─────────────┼──────┤
│ crisismerge │ 8 │
│ pgsz │ 8000 │
│ usermerge │ 4 │
│ version │ 4 │
└─────────────┴──────┘
附录A:与FTS3/4的比较
此外,还提供类似但更成熟的FTS3/4模块。 FTS5 是 FTS4 的新版本,包括各种修复和解决方案 在FTS4中无法在不向后牺牲的情况下解决的问题 兼容性。其中一些问题描述如下。
应用程序移植指南
为了使用 FTS5 而不是 FTS3 或 FTS4,应用程序通常需要 最少的修改。其中大多数分为三类 - 变化 用于创建 FTS 表的创建虚拟表语句所必需的, 用于对表执行查询的 SELECT 查询所需的更改, 以及使用 FTS 辅助功能的应用程序所需的更改。
对创建虚拟表语句的更改
模块名称必须从“fts3”或“fts4”更改为“fts5”。
必须从中删除所有类型信息或约束规范 列定义。FTS3/4 忽略列名后面的所有内容 列定义,FTS5 尝试解析它(并将报告错误 如果失败)。
“matchinfo=fts3”选项不可用。“列大小=0”选项是等效的。
notindexed= 选项不可用。将“取消索引”添加到列定义是等效的。
ICU 分词器不可用。
压缩=、解压缩=和语言 id= 选项不可用。 到目前为止,它们的功能还没有等效项。
– FTS3/4 statement
CREATE VIRTUAL TABLE t1 USING fts4(
linkid INTEGER,
header CHAR(20),
text VARCHAR,
notindexed=linkid,
matchinfo=fts3,
tokenizer=unicode61
);
– FTS5 equivalent (note - the “tokenizer=unicode61” option is not
– required as this is the default for FTS5 anyway)
CREATE VIRTUAL TABLE t1 USING fts5(
linkid UNINDEXED,
header,
text,
columnsize=0
);
对 SELECT 语句的更改
“文档”别名不存在。应用程序必须使用“rowid” 相反。
将列筛选器同时指定为 部分,并使用列作为 MATCH 的 LHS 运算符略有不同。对于包含列“a”和“b”的表 以及类似于以下内容的查询:
… a MATCH ‘b: string’
FTS3/4 在“b”列中搜索匹配项。但是,FTS5 总是 返回零行,因为首先筛选结果为“b”列,然后 对于列“A”,不留下任何结果。换句话说,在FTS3/4中 内部过滤器覆盖外部过滤器,在 FTS5 中应用两个过滤器。
FTS 查询语法(MATCH 运算符的右侧)具有 在某些方面发生了变化。FTS5 语法与 FTS4 非常接近 “增强的语法”。主要区别在于FTS5更挑剔 关于查询中无法识别的标点字符和类似字符 字符串。大多数使用 FTS3/4 的查询也应该使用 FTS5 和那些不返回的 FTS<> 应该返回解析错误。
辅助功能更改
FTS5 没有 matchinfo() 或 offsets() 函数,而 snippet() 函数 不像 FTS3/4 那样功能齐全。但是,由于FTS5确实提供了 一个 API,允许应用程序创建自定义辅助函数,任何 所需的功能可以在应用程序代码中实现。
FTS5 提供的一组内置辅助功能可以是 将来会改进。
其他问题
现在提供了 fts4aux 模块提供的功能 作者:FTS5词汇。这两个表的架构略有不同。
FTS3/4 “merge=X,Y” 命令已被 FTS5 merge 命令取代。
FTS3/4 “automerge=X” 命令已被 FTS5 automerge 选项取代。
FTS5 与 FTS3/4 相似,因为每个 FTS<> 的主要任务是维护 从每个唯一令牌到该令牌实例列表的索引映射 在一组文档中,其中每个实例都由文档标识 它出现在其中及其在该文档中的位置。例如:
– Given the following SQL:
CREATE VIRTUAL TABLE ft USING fts5(a, b);
INSERT INTO ft(rowid, a, b) VALUES(1, ‘X Y’, ‘Y Z’);
INSERT INTO ft(rowid, a, b) VALUES(2, ‘A Z’, ‘Y Y’);
– The FTS5 module creates the following mapping on disk:
A --> (2, 0, 0)
X --> (1, 0, 0)
Y --> (1, 0, 1) (1, 1, 0) (2, 1, 0) (2, 1, 1)
Z --> (1, 1, 1) (2, 0, 1)
在上面的示例中,每个三元组标识令牌的位置 实例按行、列号(列按顺序编号) 从左到右从 0 开始)并在列值内的位置( 列值中的第一个标记为 0,第二个标记为 1,依此类推)。使用这个 索引,FTS5能够及时回答诸如“集合”之类的查询 包含令牌“A”或“所有文档的集合”的所有文档 包含序列’Y Z’”。与 单个令牌称为“实例列表”。
FTS3/4 和 FTS5 之间的主要区别在于,在 FTS3/4 中, 每个实例列表都存储为单个大型数据库记录,而 在 FTS5 中,大型实例列表在多个数据库记录之间划分。 这对于处理大型数据库具有以下含义: 包含大型列表:
FTS5 能够以增量方式将实例列表加载到内存中 以减少内存使用量和峰值分配大小。FTS3/4 非常 通常将整个实例列表加载到内存中。
处理具有多个令牌的查询时,FTS5 是 有时能够确定查询可以通过以下方式回答 检查大型实例列表的子集。FTS3/4 几乎总是 必须遍历整个实例列表。
如果实例列表增长得太大以至于超过 SQLITE_MAX_LENGTH限制,FTS3/4 无法处理它。FTS5 没有这个问题。
由于这些原因,许多复杂查询可能会使用更少的内存并运行得更快 使用 FTS5。
FTS5 与 FTS3/4 不同的其他一些方面是:
FTS5 支持“按排名排序”返回结果 相关性降低。
FTS5 具有允许用户创建自定义辅助的 API 用于高级排名和文本处理应用程序的函数。这 特殊的“秩”列可以映射到自定义辅助功能 以便将“ORDER BY 排名”添加到查询按预期工作。
FTS5 通过以下方式识别 unicode 分隔符和大小写等效性 违约。使用 FTS3/4 也可以这样做,但必须明确 启用。
查询语法已在必要时进行了修改,以删除 歧义并使其能够转义特殊字符 在查询词中。
默认情况下,FTS3/4 偶尔会将两个或多个 在插入、更新或 用户执行的 DELETE 语句。这意味着任何操作 在 FTS3/4 表上可能会变得非常慢,因为 FTS3/4 可能不可预测地选择将两个或多个大 B 树合并在一起 在其中。FTS5 默认使用增量合并,这限制了 在任何给定范围内可能发生的处理量 插入、更新或删除操作。