Skip to content

feat(search): searchkit, the search without its UI for desktop, Android 10+ and iOS - #698

Draft
kdroidFilter wants to merge 4 commits into
masterfrom
feat/searchkit
Draft

kdroidFilter wants to merge 4 commits into
masterfrom
feat/searchkit

Conversation

@kdroidFilter

@kdroidFilter kdroidFilter commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

The whole search logic becomes Kotlin Multiplatform, so the Android and iOS apps only have their screens to write (follows #606). This PR depends on kdroidFilter/SeforimLibrary#134 (the submodule points at its branch) and, through it, on NucleusFramework/NucleusJvmAccess#1: until an NJA release ships it, build with -Pnja.local=<NJA checkout>.

  • searchkit: a new KMP module (JVM, Android 10+, iOS) that the desktop app uses as is.
    • The engines: lexical search, plus the hybrid search with the semantic model in official builds.
    • The lookup: books, authors, tables of contents.
    • The search use cases and the view models SearchResultViewModel / SearchHomeViewModel, moved from SeforimApp unchanged.
    • Platform glue: SearchServices and openLuceneIndex (the façade's constructor, common to all platforms).
      • Lucene runs on a real JVM through Nucleus JVM Access (SeforimLibrary's search-facade): the desktop's own JVM, HotSpot in the app's process on Android 10+ (nothing to configure: the JVM comes with the search library), Zero linked into the app on iOS (assembleIosJavaRuntime* assembles what an app links and bundles).
      • The SQLite driver differs per platform as well.
    • Ports: the view models reach the desktop shell only through the four interfaces of SearchHost.kt: SearchTabs, SearchSessionStore, SearchSettings, SearchHistory.
    • Semantic search: the addon (addons/semantic) moves with it, on seforim-semantic 0.6.0, which is now KMP. The JVM jar carries the model; mobile apps download it.
  • navigation: Android and iOS targets.
  • SeforimApp: the desktop implementations of the ports (DesktopSearchTabs, DesktopSearchSessionStore, AppSettings, HistoryStore) and the Metro wiring. The app's behaviour is unchanged.
  • searchkit-check: an Android app with no UI that runs the search on a device or an emulator.
  • searchkit/README.md (usage from a mobile app) and CLAUDE.md are updated.

Verification

  • Parity (SearchKitDump on real data: lookup, hybrid search, snippets, highlights by meaning, smart find):
    • JVM and iOS simulator: byte-identical.
    • Android 11 emulator (searchkit-check, through NJA, 1.9 s once the runtime is extracted): identical except for one query's hit total, which Lucene counts as a lower bound.
  • iOS memory: the process footprint is ~160 MB with the default 128 MB Java heap.
  • Checks:
    • ktlintCheck passes for searchkit and navigation.
    • :searchkit:jvmTest passes.
    • The Android and iOS device compilations pass.
  • Not fixed here:
    • The 31 :SeforimApp:jvmTest failures (WidgetDragUiTest, *ScreenshotTest) also fail on an untouched master.
    • The ktlint import-order error in E2eQuoteLinksScenario.kt is in a file this PR doesn't touch.

Not in this PR

  • The mobile screens, and rendering snippets and lines (:htmlparser, which needs Ksoup on iOS).
  • The reader's find-in-page (BookFindMatches), which belongs with :htmlparser.

…id 15+ and iOS

The engines (lexical, hybrid with the semantic search), the lookup, the search use cases and the view models
move to searchkit, a Kotlin Multiplatform module the desktop app uses as is; a mobile app only adds its screens.

- searchkit: SearchServices, openLuceneIndex per platform (in process on the JVM and Android 15+, in the
  embedded OpenJDK on iOS), the database driver per platform, SearchResultViewModel and SearchHomeViewModel
  reaching the shell only through SearchHost's ports (SearchTabs, SearchSessionStore, SearchSettings,
  SearchHistory); the semantic addon on seforim-semantic 0.6.0 (Kotlin Multiplatform).
- navigation: Android and iOS targets.
- SeforimApp: the desktop adapters of the ports (DesktopSearchTabs, DesktopSearchSessionStore, AppSettings,
  HistoryStore) and the graph wiring.
- SeforimLibrary: the multiplatform search (kdroidFilter/SeforimLibrary#134).

Parity on real data (SearchKitDump): the JVM, the iOS simulator and an Android 15 emulator give the same
lookup, hybrid search, snippets, highlights and smart find.

Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
As SeforimLibrary now runs Lucene on a real JVM only (ART can't keep up with Lucene's Java versions), Android
reaches it through the bridge, in a Java process of the app's own.

- searchkit: AndroidJavaRuntime (configure(context), a 128 MB heap: ~140 MB for the process), openLuceneIndex
  always through it, assembleAndroidJavaRuntime (the launcher, the JDK, the search's jars), minSdk 29.
- searchkit-check back: the app that runs the search on a device (a library's test APK can't hold the launcher).
- SeforimLibrary at e4c1cad (kdroidFilter/SeforimLibrary#134).

Verified on Android 15 and Android 11 emulators: SearchKitDump as on the desktop, in 2.3 to 4.5 s.

Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
@kdroidFilter kdroidFilter changed the title feat(search): searchkit, the search without its UI for desktop, Android 15+ and iOS feat(search): searchkit, the search without its UI for desktop, Android 10+ and iOS Oct 16, 2026
assembleAndroidJavaRuntime puts both launchers among the native libraries and a java.home per ABI (jdk/<abi>:
some of its classes depend on the architecture); AndroidJavaRuntime picks the one of the launcher Android
installed. SeforimLibrary at its jdk-mobile-27b35.2 commit.

Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
SeforimLibrary's search now runs Lucene through NJA (kdroidFilter/SeforimLibrary#134), with the JVM in the
app's process on every platform:

- searchkit: openLuceneIndex is the façade's constructor, common to all platforms; AndroidJavaRuntime,
  IosJavaRuntime and assembleAndroidJavaRuntime go (Android gets the JVM with search's library, nothing to
  configure); iOS binaries link the staged runtime and carry NJA's bundle, assembleIosJavaRuntime* assembles
  both for an app.
- searchkit-check: no runtime to deliver anymore.
- SeforimLibrary at 81d9725.

The same SearchKitDump as before: the desktop byte for byte, iOS identical to it, Android 11 but for one hit
total (Lucene's lower bound), in 1.9 s once the runtime is extracted.

Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>

This branch has not been deployed

No deployments
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.

1 participant