SQLite FTS3 和 FTS4 插件
总览
FTS3和FTS4是SQLite虚表模块,允许用户在一堆文档中实现全文搜索。用户输入一个短语(term),或者一些列term,然后这个系统找到一些列文档,最佳地匹配了哪些terms。这篇文章介绍了FTS3和FTS4的部署和使用
FTS1和FTS2是过时的全文搜索模块。有一些已知的问题。FTS3的部分恭喜到了SQLite的项目中。现在作为SQLite的一部分被开发和维护。
1、FTS3和FTS4的介绍
FTS3和FTS4扩展模块允许用户创建特殊的表,内置了全文索引(FTS表)全文索引允许用户有效地查询数据库的所有行,找到包含一个或更多的单词(tokens),就算表包含很多文档。
比如,如果517430个文档中,每个文档都同时插入了FTS表和普通的SQLite表,使用以下的SQL脚本
CREATE VIRTUAL TABLE enrondata1 USING fts3(content TEXT); /* FTS3 table */
CREATE TABLE enrondata2(content TEXT); /* Ordinary table */
然后下面任意一个query可以执行,来查找数据库中包含单词”linux“文档的数量。使用一个桌面PC硬件的配置,在FTS3的查询在大约0.03s返回,而查询普通表则需要22.5s
SELECT count(*) FROM enrondata1 WHERE content MATCH 'linux'; /* 0.03 seconds */
SELECT count(*) FROM enrondata2 WHERE content LIKE '%linux%'; /* 22.5 seconds */
当然,上面这两个query并不是完全相等的。比如,LIKE query匹配的行,可能是linuxphobe或者EnterpricseLinux
,而在FTS3的MATCH query选择准确的”linux“。这俩都是大小写敏感的。FTS3表的存储消耗大约2000MB,普通标大概是1453MB。使用相同的硬件配置调用上面的query,FTS3表使用31分钟建立,普通表则是25MB。
1.1、FTS3和FTS4的不同
FTS3和FTS4几乎是相同的。大部分代码一样,接口一样。不同点在于:
- FTS4包含query性能优化,可能显著地改进哪些包含常用term的全文query的性能(大比例的表的行都存在的)
- FTS4支持另外的选项,可能在matchinfo()函数使用
- 因为在硬盘保存了额外信息(在两个新的shadow 表) 为了支持性能优化和附加的matchinfo()选项,FTS4表可能比FTS3消耗更多磁盘空间,通常差距是少1-2%,但当FTS表很小的时候可能要高10%。
- FTS4提供了钩子(压缩和反压缩选项)允许数据以压缩的形式保存,减少磁盘使用和IO
FTS4是FTS3的增强版。
应该在你的应用用哪个?FTS4有时候比FTS3显著地快。
新一点的应用,推荐使用FTS4;然而如果兼容性比较重要,FTS3也不错。
1.2、 创建和销毁FTS表
像其他虚表类型,使用CREATE VIRTUAL TABLE声明来创建。
-- Create an FTS table named "data" with one column - "content":
CREATE VIRTUAL TABLE data USING fts3();-- Create an FTS table named "pages" with three columns:
CREATE VIRTUAL TABLE pages USING fts4(title, keywords, body);-- Create an FTS table named "mail" with two columns. Datatypes
-- and column constraints are specified along with each column. These
-- are completely ignored by FTS and SQLite.
CREATE VIRTUAL TABLE mail USING fts3(subject VARCHAR(256) NOT NULL,body TEXT CHECK(length(body)<10240)
);
删除也类似
-- Create, then immediately drop, an FTS4 table.
CREATE VIRTUAL TABLE data USING fts4();
DROP TABLE data;
1.3、填充FTS表
填充FTS表是使用INSERT、UPDATE和DELETE声明。
-- Create an FTS table
CREATE VIRTUAL TABLE pages USING fts4(title, body);-- Insert a row with a specific docid value.
INSERT INTO pages(docid, title, body) VALUES(53, 'Home Page', 'SQLite is a software...');-- Insert a row and allow FTS to assign a docid value using the same algorithm as
-- SQLite uses for ordinary tables. In this case the new docid will be 54,
-- one greater than the largest docid currently present in the table.
INSERT INTO pages(title, body) VALUES('Download', 'All SQLite source code...');-- Change the title of the row just inserted.
UPDATE pages SET title = 'Download SQLite' WHERE rowid = 54;-- Delete the entire table contents.
DELETE FROM pages;-- The following is an error. It is not possible to assign non-NULL values to both
-- the rowid and docid columns of an FTS table.
INSERT INTO pages(rowid, docid, title, body) VALUES(1, 2, 'A title', 'A document body');
为了支持全文query,FTS维护了倒排索引。
1.4、简单的FTS查询
这两种查询很高效:
- 使用rowid查询
- 全文query。 MATCH ? FTS表就可以使用内置全文索引
如果上面两种查询都不是,那就只能线性扫描了。那可就太慢了。
-- The examples in this block assume the following FTS table:
CREATE VIRTUAL TABLE mail USING fts3(subject, body);SELECT * FROM mail WHERE rowid = 15; -- Fast. Rowid lookup.
SELECT * FROM mail WHERE body MATCH 'sqlite'; -- Fast. Full-text query.
SELECT * FROM mail WHERE mail MATCH 'search'; -- Fast. Full-text query.
SELECT * FROM mail WHERE rowid BETWEEN 15 AND 20; -- Fast. Rowid lookup.
SELECT * FROM mail WHERE subject = 'database'; -- Slow. Linear scan.
SELECT * FROM mail WHERE subject MATCH 'database'; -- Fast. Full-text query.
其实还支持更复杂的查询,包括phrase search,term-prefix search。
-- Example schema
CREATE VIRTUAL TABLE mail USING fts3(subject, body);-- Example table population
INSERT INTO mail(docid, subject, body) VALUES(1, 'software feedback', 'found it too slow');
INSERT INTO mail(docid, subject, body) VALUES(2, 'software feedback', 'no feedback');
INSERT INTO mail(docid, subject, body) VALUES(3, 'slow lunch order', 'was a software problem');-- Example queries
SELECT * FROM mail WHERE subject MATCH 'software'; -- Selects rows 1 and 2
SELECT * FROM mail WHERE body MATCH 'feedback'; -- Selects row 2
SELECT * FROM mail WHERE mail MATCH 'software'; -- Selects rows 1, 2 and 3
SELECT * FROM mail WHERE mail MATCH 'slow'; -- Selects rows 1 and 3
1.5、总结
从用户的角度看,FTS表跟普通表很像,也就是那些增删改查而已。主要不同如下:
1、就像所有的虚表类型,不可能创建索引或者trigger。也不可能使用ALTER TABLE命令来添加列。(尽管可以重命名表名)
2、数据类型完全被忽略。所有都会转换成TEXT来存储
3、允许别名‘docid’
4、FTS MATCH操作符支持全文搜索
5、FTS辅助功能,snippet() offsets() matchinfo()
6、每个FTS有隐藏列。名字跟表名一样。只是用来做MATCH。
2、编译和enable FTS3和FTS4
尽管源码中包含FTS3和FTS4,默认没有enable。要enable的话,编译的时候定义宏SQLITE_ENABLE_FTS3。新的应用应该也定义SQLITE_ENABLE_FTS3_PARENTHESIS宏,来enable enhanced_query_syntax。通常通过添加下面的两个开关。
-DSQLITE_ENABLE_FTS3
-DSQLITE_ENABLE_FTS3_PARENTHESIS
enable FTS3,FTS4也就顺带着好了。
3、全文索引query
FTS表支持三个基础的query类型
- Token 或者 token前缀 query。使用*来实现term prefix查询
-- Virtual table declaration
CREATE VIRTUAL TABLE docs USING fts3(title, body);-- Query for all documents containing the term "linux":
SELECT * FROM docs WHERE docs MATCH 'linux';-- Query for all documents containing a term with the prefix "lin". This will match
-- all documents that contain "linux", but also those that contain terms "linear",
--"linker", "linguistic" and so on.
SELECT * FROM docs WHERE docs MATCH 'lin*';
可以指定是哪一列:
-- Query the database for documents for which the term "linux" appears in
-- the document title, and the term "problems" appears in either the title
-- or body of the document.
SELECT * FROM docs WHERE docs MATCH 'title:linux problems';-- Query the database for documents for which the term "linux" appears in
-- the document title, and the term "driver" appears in the body of the document
-- ("driver" may also appear in the title, but this alone will not satisfy the
-- query criteria).
SELECT * FROM docs WHERE body MATCH 'title:linux driver';
term必须是第一个term:
-- All documents for which "linux" is the first token of at least one
-- column.
SELECT * FROM docs WHERE docs MATCH '^linux';-- All documents for which the first token in column "title" begins with "lin".
SELECT * FROM docs WHERE body MATCH 'title: ^lin*';
- Phrase queries。召回文档包含一系列的term或者term prefixes,按照指定的顺序,没有中间接入的token。
-- Query for all documents that contain the phrase "linux applications".
SELECT * FROM docs WHERE docs MATCH '"linux applications"';-- Query for all documents that contain a phrase that matches "lin* app*". As well as
-- "linux applications", this will match common phrases such as "linoleum appliances"
-- or "link apprentice".
SELECT * FROM docs WHERE docs MATCH '"lin* app*"';
- NEAR queries. 返回文档,term之前不能超过一定数量的介入term
-- Virtual table declaration.
CREATE VIRTUAL TABLE docs USING fts4();-- Virtual table data.
INSERT INTO docs VALUES('SQLite is an ACID compliant embedded relational database management system');-- Search for a document that contains the terms "sqlite" and "database" with
-- not more than 10 intervening terms. This matches the only document in
-- table docs (since there are only six terms between "SQLite" and "database"
-- in the document).
SELECT * FROM docs WHERE docs MATCH 'sqlite NEAR database';-- Search for a document that contains the terms "sqlite" and "database" with
-- not more than 6 intervening terms. This also matches the only document in
-- table docs. Note that the order in which the terms appear in the document
-- does not have to be the same as the order in which they appear in the query.
SELECT * FROM docs WHERE docs MATCH 'database NEAR/6 sqlite';-- Search for a document that contains the terms "sqlite" and "database" with
-- not more than 5 intervening terms. This query matches no documents.
SELECT * FROM docs WHERE docs MATCH 'database NEAR/5 sqlite';-- Search for a document that contains the phrase "ACID compliant" and the term
-- "database" with not more than 2 terms separating the two. This matches the
-- document stored in table docs.
SELECT * FROM docs WHERE docs MATCH 'database NEAR/2 "ACID compliant"';-- Search for a document that contains the phrase "ACID compliant" and the term
-- "sqlite" with not more than 2 terms separating the two. This also matches
-- the only document stored in table docs.
SELECT * FROM docs WHERE docs MATCH '"ACID compliant" NEAR/2 sqlite';
NOTE: 想想搜索的原理,这个NEAR是咋做的??以这个为例: SELECT * FROM docs WHERE docs MATCH ‘database NEAR/6 sqlite’;
倒排索引可以很轻松地先找出同时包含database 和 sqlite的doc,然后再看每个文档中这些term的位置,过滤掉不符合的就行。
还可以有多个NEAR,直接看例子吧:
-- The following query selects documents that contains an instance of the term
-- "sqlite" separated by two or fewer terms from an instance of the term "acid",
-- which is in turn separated by two or fewer terms from an instance of the term
-- "relational".
SELECT * FROM docs WHERE docs MATCH 'sqlite NEAR/2 acid NEAR/2 relational';-- This query matches no documents. There is an instance of the term "sqlite" with
-- sufficient proximity to an instance of "acid" but it is not sufficiently close
-- to an instance of the term "relational".
SELECT * FROM docs WHERE docs MATCH 'acid NEAR/2 sqlite NEAR/2 relational';
还有一些操作
- AND操作决定文档列表取交集
- OR操作决定文档列表取并集
- NOT操作 计算相对补集(relative complement)
后面还有好多例子,如果真的用到再看吧~
SQLite FTS3 和 FTS4 插件相关推荐
- SQLite FTS3/FTS4与一些使用心得
此文已由作者王攀授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 简介 对于今天的移动.桌面客户端应用而言,离线全文检索的需求已经十分强烈,我们日常使用的邮件客户端.云音乐.云 ...
- android sqlite fts4,SQLite FTS3/FTS4与一些使用心得
此文已由作者王攀授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 简介 对于今天的移动.桌面客户端应用而言,离线全文检索的需求已经十分强烈,我们日常使用的邮件客户端.云音乐.云 ...
- android sqlite 分词,sqlite fts3自定义分词器 zz
return sqlite3_finalize(pStmt); } 要想实现自定义的分词器,最关键的时是得到指向sqlite3_tokenizer_module结构的一个指针,sqlite3_toke ...
- iOS/Android SQLite 全文检索——FTS (Full Text Search)
文章目录 前言 一.基本概念 二.为什么使用SQLite全文检索 三.版本选择 四.分词器 五.使用步骤 六.```MATCH```部分语法 七.Demo 参考 前言 我们的APP部分功能为了满足用户 ...
- SQLite第三课 源码编译错误以及解决
1)fts2 has a designflaw and has been deprecated 2)fts1 has a designflaw and has been deprecated 解决方案 ...
- SQLite FTS5使用小技巧
SQLite FTS5使用小技巧 在SQLite中,全文索引功能以扩展模块存在.使用全文索引,可以快速对大段文字进行搜索.SQLite提供FTS3.FTS4.FTS5三个模块.其中,FTS5是最新版的 ...
- SQLite中使用全文搜索FTS
SQLite中使用全文搜索FTS SQLite支持全文搜索.通过全文搜索功能,可以方便用户快速进行查找.在iOS中,GRDB.FMDB等SQLite框架均支持FTS技术,如FTS3.FTS4等.各个框 ...
- Sqlite优化记录:使用全文索引加快检索速度-转
Sqlite是一个很优秀的数据库,不仅体积小,多平台支持,而且数据库具有单个文件,方便在不同平台上快速部署等很多优势. 关于Sqlite的性能,总是最具有争议的地方.不过之前也在网上看到过有人把sql ...
- SQLite虚表介绍
虚表 虚表是一种自定义的扩展,允许用户通过代码定制表的数据结构和数据内容:对于数据库引擎,它和普通表一样,允许进行大多数的sql操作. 虚表和普通表的主要不同在于,其表中的数据的来源:对于普通表,来源 ...
最新文章
- Oracle 正则表达式
- 火星坐标、百度坐标、WGS-84坐标相互转换及墨卡托投影坐标转经纬度JavaScript版...
- python的数值类型和运算符_Python中的基本数据类型和运算符,python
- 买台式电脑还是笔记本好?
- 移动端开发 main.js入口文件
- 数据倾斜是什么以及造成的原因?
- [luogu3198] 玩具装箱
- select学习小demo--实现网页换肤
- 22.客户端识别与 cookie 机制
- 基于python的三维射线追踪库-ttcrpy详解(1)
- 升级到Tomcat9之后js中文乱码解决办法
- windows7系统重装的步骤,电脑重装win7
- 供应脂质体形成材料DSPE-PEG-Thiol,DSPE-PEG-SH
- 《京东话费充值系统架构演进实践》读后感
- Mixly制作的MP3播放和七彩灯、台灯控制例子
- 【职场心路】一个老DBA的自白
- Thread.currentThread().interrupt()和Thread.interrupted()和Thread.currentThread().isInterrupted()
- 算法课堂笔记01-语句频度计算
- Dockers-搭建本地私有仓库
- 如何做一个基于微信高校食堂就餐预约小程序序系统毕业设计毕设作品