8000 perf(search): keep word search in SQLite, with OpenSearch as an option by adeelahmad · Pull Request #166 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

perf(search): keep word search in SQLite, with OpenSearch as an option - #166

Merged
adeelahmad merged 2 commits into
mainfrom
claude/project-thread-n7hg6d
Oct 5, 2026
Merged

adeelahmad merged 2 commits into
mainfrom
claude/project-thread-n7hg6d

Conversation

@adeelahmad
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: word search used SurrealDB's own full-text index (BM25 + highlights), which cost about six times the records' memory. On 10,000 transcript lines with production surrealkv storage, the SurrealDB server used 380 MB, against 47 MB without the index.

After: search.engine picks where the words are indexed.

  • sqlite, the default, uses a SQLite FTS5 file per database in <data_dir>/search/. On the same 10,000 lines the server used 64 MB, and the index file was 4 MB.
  • surrealdb keeps today's index.
  • opensearch uses a cluster at search.opensearch_url. There's an opensearch compose profile.

Search, the assistant's retrieval and IIIF content search return the same results. An existing install builds the new index on first start and frees SurrealDB's index.

How:

  • app/domain/textindex.py holds the engines.
  • A DEFINE EVENT on each text table records created, deleted or re-texted rows in text_change. The index catches up from there before each search, so writers change nothing.
  • SurrealDB still applies who may see a row: the index returns ids, and SurrealDB filters them with the caller's conditions.
  • An index built from another database (a restore, or a new database under the same name) is rebuilt; a token in text_change_state:index detects this.
  • If OpenSearch can't be reached, searches read the tables.
  • lens reindex (or Settings › Search › Reindex now) applies a change of engine or stemming.
  • Settings › Search gains Word search and the OpenSearch address, user, password and certificate check.

Motivation and Context

Adeel found the database was the weight, and approved this: "yes but also allow opensearch". Plan: /mnt/project-files/lens-lite/plan.md.

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

  • The title is a Conventional Commit.
  • ruff and ruff format are clean; tsc, lint and jest (698 passed) are clean.
  • Tests in tests/domain/test_search_index.py cover both engines across a reopen, edits and deletes, switching engines, a swapped database, filters, OpenSearch (with LENS_TEST_OPENSEARCH_URL), an unreachable OpenSearch, and settings validation.
  • Backend suite: 657 passed in memory and 658 passed on a SurrealDB 3.2.4 server, both with OpenSearch 2.19.1. The one failure is the LibreOffice conversion test, which fails in this environment.
  • Docs (docs/database.md, archive.example.yaml) and CHANGELOG updated.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QtzGWLtX99AFMsL4hYpoRe


Generated by Claude Code

claude added 2 commits October 5, 2026 05:32
SurrealDB's full-text index cost about six times the records' memory (10,000
transcript lines: 380 MB of server memory with it, 64 MB with a SQLite FTS5
file instead). search.engine "sqlite" is the default; "surrealdb" keeps
today's index. Events note changed rows in text_change and the index catches
up before each search.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtzGWLtX99AFMsL4hYpoRe
search.engine "opensearch" keeps the words in an OpenSearch (or
Elasticsearch-compatible) cluster at search.opensearch_url, kept in step by
the same text_change events as the SQLite index. When it can't be reached,
searches read the tables instead. A compose profile runs one next to Lens.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtzGWLtX99AFMsL4hYpoRe
@adeelahmad
adeelahmad merged commit 5235bb0 into main Oct 5, 2026
4 of 5 checks passed
@adeelahmad adeelahmad self-assigned this Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0