FTS 虚拟表(Full-Text Search Virtual Table) 是 SQLite数据库中一种特殊表类型,专门用于支持全文搜索功能。理解 FTS虚拟表的概念对于充分利用 SQLite和 Android Room的全文搜索功能至关重要。
以下是关于 FTS 虚拟表的关键点:
- 虚拟表的概念
虚拟表不是实际存储数据的物理表,而是一个接口,背后由特定的模块实现。
FTS 虚拟表看起来像普通的 SQLite 表,但其内部实现了特殊的索引和搜索算法- 全文搜索功能
FTS 虚拟表专门优化用于文本搜索,可以快速在大量文本数据中查找关键词。
它支持复杂的查询,如短语搜索、前缀匹配、布尔操作等。- 索引机制:
FTS 虚拟表使用倒排索引(Inverted Index)来加速搜索。
这种索引结构允许快速定位包含特定词语的文档,大大提高了搜索效率。
那么如何创建FTS 表呢?
在 SQLite 中,使用特殊的语法即可创建FTS 表:
sql
CREATE TABLE table_name_fts USING fts4(table_cloumn1, table_cloumn2)
如果是在 Android Room 数据库中,直接可以使用 @Fts3
或者@Fts4
注解即可:
kotlin
@Fts4
@Entity(tableName = "users_fts")
data class UserFts(
@PrimaryKey @ColumnInfo(name = "rowid") val id: Int,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "email") val email: String
)
那么如何进行搜索呢?可以想象它和like
关键字一样:
sql
SELECT * FROM users_fts WHERE users_fts MATCH 'search term'
这里,需要重点讨论一下,MATCH
和 LIKE
的不同点:
sql1:
sql
SELECT * FROM users WHERE name MATCH :searchQuery
和
sql2:
sql
ELECT * FROM users WHERE name LIKE '%' || :searchQuery || '%'
对于 sql1:
- 这是全文搜索(Full-Text Search, FTS)查询。
- 使用 MATCH 操作符,它是专门为全文搜索设计的。
- 通常需要特殊的表设置,如在 SQLite 中使用 FTS3, FTS4 或 FTS5 虚拟表。
- 性能通常更好,特别是在大型数据集上。
- 支持更复杂的搜索查询,如词语搜索、近似匹配等。
- 可以根据相关性排序结果。
- 不支持通配符匹配。
对于 sql2:
- 这是一个标准的 SQL LIKE 查询。
- 使用 LIKE 操作符进行模式匹配。
- 可以在任何标准 SQL 表上使用,不需要特殊设置。
- 对于大型数据集,性能可能较差,特别是当使用前缀通配符 ('%xxx') 时。
- 支持简单的通配符匹配。
- 不提供内置的相关性排序。
- 更灵活,可以轻松进行部分匹配。
主要区别:
-
性能:
MATCH 通常比 LIKE 更快,特别是在大型数据集上。LIKE 使用前缀通配符时无法使用索引,可能导致全表扫描。
-
功能
MATCH 提供更强大的全文搜索功能,如词语搜索、相关性排序等。LIKE 则提供简单的模式匹配。
-
设置要求
MATCH 需要特殊的表设置(FTS表),而 LIKE 可以在任何普通表上使用。
-
灵活性
LIKE 在模式匹配方面更灵活,可以轻松进行部分匹配。MATCH 主要用于全词匹配或词语搜索
-
结果排序
MATCH 可以基于相关性排序结果,LIKE 则不提供这种内置功能
-
语法
MATCH 使用特定的搜索语法,而 LIKE 使用简单的通配符
使用建议:
- 如果你需要高性能的全文搜索,特别是在大型数据集上,使用 MATCH。
- 如果你需要简单的模式匹配,或者在小型数据集上工作,LIKE 可能就足够了。
- 如果你不想或不能设置 FTS 表,那么就只能使用 LIKE。
在 Android Room 中如用 FTS:
kotlin
@Fts4
@Entity(tableName = "users_fts")
data class UserFts(
@PrimaryKey @ColumnInfo(name = "rowid") val id: Int,
@ColumnInfo(name = "name") val name: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM users_fts WHERE name MATCH :query")
fun searchUsers(query: String): List<UserFts>
}
可以观察到,Android Room 数据库中存在 @Fts4
和 @Fts3
注解,那么它们之间又有什么不同呢?
FTS3 和 FTS4 都是 SQLite 中的全文搜索扩展,但它们有一些重要的区别。了解这些差异可以帮助你选择最适合你的应用需求的版本。以下是 FTS3 和 FTS4 的主要区别:
-
性能:
FTS4 通常比 FTS3 更快,特别是在插入和更新操作上。
FTS4 在大型数据集上的查询性能也略优于 FTS3。
-
存储效率:
FTS4 通常比 FTS3 更节省存储空间。
FTS4 引入了压缩选项,可以进一步减少存储需求。
-
词干提取(Stemming):
FTS4 支持内置的词干提取,而 FTS3 不支持。
词干提取可以提高搜索的灵活性,例如搜索 "run" 也能匹配 "running"。
-
列名称:
FTS3 使用默认的列名(content),而 FTS4 允许自定义列名。
这使得 FTS4 在处理多列数据时更加灵活。
-
排序:
FTS4 支持基于文档 ID 的结果排序,这在 FTS3 中是不可用的。
术语近似度(Term Proximity):
FTS4 提供了更好的术语近似度支持,允许更精确的短语搜索。
-
Unicode 支持:
FTS4 对 Unicode 的支持比 FTS3 更好,特别是在处理非 ASCII 字符时。
-
可选的前缀索引:
FTS4 允许创建可选的前缀索引,这可以加速某些类型的查询,但会增加存储空间的使用。
-
向后兼容性:
FTS4 向后兼容 FTS3,这意味着为 FTS3 编写的代码通常可以在 FTS4 上运行。
-
稳定性:
FTS3 作为较早的版本,可能在某些旧版本的 SQLite 中更稳定。
FTS4 在较新的 SQLite 版本中已经非常稳定。
使用建议:
- 对于大多数现代 Android 应用,FTS4 是更好的选择,因为它提供了更好的性能和更多的功能。
- 如果你的应用需要处理大量文本数据,或者需要高级搜索功能(如词干提取或更好的 Unicode 支持),FTS4 是明确的选择。
- 只有在你需要支持非常旧的 Android 版本,或者有特定的兼容性要求时,才应该考虑使用 FTS3。
- 如果你正在升级现有的使用 FTS3 的应用,迁移到 FTS4 通常是一个好主意,因为它提供了性能改进和额外的功能。
- 需要注意的是,Android 还支持 FTS5,它比 FTS4 更新,提供了更多的功能和性能改进。在新项目中,你可能想考虑直接使用 FTS5。