Basics of SQLite Full-Text Search (FTS)

Normal SQL search:

SELECT *
FROM posts
WHERE content LIKE '%sqlite%';

Full-text search is designed specifically for searching large amounts of text.

SQLite provides this through FTS5.


Create an FTS5 Table

CREATE VIRTUAL TABLE posts_fts
USING fts5(title, content);

Insert data:

INSERT INTO posts_fts(title, content)
VALUES
  ('SQLite Basics', 'SQLite is a small embedded database.'),
  ('FTS5', 'SQLite provides full-text search.'),
  ('JavaScript', 'JavaScript can work with SQLite.');

Use MATCH:

SELECT *
FROM posts_fts
WHERE posts_fts MATCH 'SQLite';

Multiple words:

SELECT *
FROM posts_fts
WHERE posts_fts MATCH 'SQLite database';

This searches for documents containing the terms.


Search a Specific Column

SELECT *
FROM posts_fts
WHERE title MATCH 'SQLite';

Or:

SELECT *
FROM posts_fts
WHERE content MATCH 'database';

Use *:

SELECT *
FROM posts_fts
WHERE posts_fts MATCH 'java*';

Matches words such as:

java
javascript
javafx

Exact Phrases

Use quotes:

SELECT *
FROM posts_fts
WHERE posts_fts MATCH '"full text search"';

Searches for the phrase:

full text search

AND

SELECT *
FROM posts_fts
WHERE posts_fts MATCH 'sqlite AND database';

Both terms must match.

OR

SELECT *
FROM posts_fts
WHERE posts_fts MATCH 'sqlite OR postgres';

Either term can match.

NOT

SELECT *
FROM posts_fts
WHERE posts_fts MATCH 'sqlite NOT mysql';

Matches sqlite but excludes mysql.


Ranking Results

FTS5 provides bm25() for relevance ranking.

SELECT
  title,
  content,
  bm25(posts_fts) AS score
FROM posts_fts
WHERE posts_fts MATCH 'sqlite'
ORDER BY score;

Lower bm25() scores are more relevant.


Highlight Matches

Useful for search results:

SELECT
  highlight(posts_fts, 1, '<b>', '</b>') AS result
FROM posts_fts
WHERE posts_fts MATCH 'sqlite';

1 means the second column (content).


FTS With a Normal Table

Usually you have a real table:

CREATE TABLE posts (
  id INTEGER PRIMARY KEY,
  title TEXT,
  content TEXT
);

And an FTS table:

CREATE VIRTUAL TABLE posts_fts
USING fts5(
  title,
  content,
  content='posts',
  content_rowid='id'
);

Now FTS indexes the content from posts.


Keep the Index Updated

If you use an external-content FTS table, changes to the original table must be reflected in the FTS index.

For example:

INSERT INTO posts(title, content)
VALUES ('SQLite', 'SQLite is awesome.');

Then update FTS:

INSERT INTO posts_fts(rowid, title, content)
VALUES (last_insert_rowid(), 'SQLite', 'SQLite is awesome.');

For automatic synchronization, SQLite triggers can be used.


FTS5 vs LIKE

LIKE

WHERE content LIKE '%sqlite%'

Good for:

FTS5

WHERE posts_fts MATCH 'sqlite'

Good for:


Simple Search Example

CREATE VIRTUAL TABLE docs
USING fts5(title, body);

INSERT INTO docs(title, body)
VALUES
  ('SQLite', 'SQLite is an embedded database.'),
  ('PostgreSQL', 'PostgreSQL is a powerful database.'),
  ('JavaScript', 'JavaScript is commonly used for web development.');

SELECT
  title,
  body,
  bm25(docs) AS score
FROM docs
WHERE docs MATCH 'database'
ORDER BY score;

Remember

LIKE       → simple text matching
FTS5       → real full-text search
MATCH      → perform an FTS search
bm25()     → rank results
highlight() → highlight matches
*          → prefix search
"..."      → phrase search
AND/OR/NOT → combine terms

FTS5 is SQLite’s built-in search engine for text.