# Meilisearch and Typesense docs search: code and real outputs Run date: 2026-11-10. Docker 24.0.6 (Docker Desktop, arm64, about 7.9 GB VM shared with other containers). Scripts are plain Python (`requests==2.32.3`, Python 3.11.2 in a venv outside the repo, see `pip-freeze.txt`) and talk to the engines on 127.0.0.1. Screenshots come from Puppeteer installed outside the repo. Pins (see `pins.txt`): `getmeili/meilisearch:v1.56.2` (RepoDigest `sha256:9600db22be3fcbf3d506176d3a73dd70a65c5719d9aa1d2837355b75afb8f4fb`) and `typesense/typesense:30.2` (RepoDigest `sha256:610f2d34b1f93d00762869da2c67736775e5798d19a2c8b91b014b8a0cc1e110`), both native arm64, both the latest GitHub release on the run day. All results belong to these versions. ## Input data `chunks.jsonl` is not included (3.4 MB with embeddings): 304 chunks from 52 pages of webcrawlerapi.com/docs, fields `id,url,heading,text,embedding`, `nomic-embed-text` 768 dims, sha256 `7c62db9258ba7b33bc75bf3e0593b0a7ffc73d0b0fb11da68db0eb27ebe4e145`. It is the shared file from the Elasticsearch and MongoDB posts, produced by `build_chunks.py` (not re-run for this post). `questions.json` and `qvecs.json` (7 query vectors, query prefix `search_query: `) are unchanged copies from the Elasticsearch post. ## Keys Both engines ran with random keys generated per run. This folder has only placeholders: `YOUR_MASTER_KEY` (Meilisearch), `YOUR_API_KEY` (Typesense), `YOUR_SEARCH_KEY` (browser pages). The scripts read `MEILI_MASTER_KEY` and `TS_API_KEY` from the environment. Search-only keys are created by the scripts and never printed. Containers have no TLS and bind to 127.0.0.1: a local demo, not a server setup. ## Files - `compose.meili.yml`, `compose.ts.yml` (project names `kb21-meili`, `kb21-ts`, 2 GB limits), `run.sh` (order of the run). - `common.py`, `meili_setup.py`, `meili_query.py` (keyword, vector, hybrid, ratio sweep), `meili_embedder.py` (`ollama` source), `meili_extra.py` (typos, filters, search-only key, delete and reinsert), `ts_setup.py`, `ts_query.py` (keyword, vector, hybrid, alpha sweep), `ts_embedder.py` (`ts/all-MiniLM-L12-v2`), `ts_extra.py` (typos, filters, search-only and scoped key, delete and reinsert), `meili_keyword_diag.py` and `ts_keyword_diag.py` (round 1 diagnostic of the keyword-mode misses: `found`/hit counts, `matchingStrategy` all and frequency, `drop_tokens_threshold` 50; side checks, not in the table), `knn_exact.py` and `overlap.py` (engine vector-only top 5 against exact cosine kNN), `typos.json`. - `search.meili.html`, `search.typesense.html` (instant-search pages, `YOUR_SEARCH_KEY` placeholder, pinned CDN versions), `shot.mjs`, `term_shot.mjs`, `make_terminals.py` (excerpts and terminal renders). - `*.out`: real output of every script. `t1..t5-*.out` are the excerpts rendered in the screenshots. `memory_stats_*.out` is `docker stats --no-stream` about every 7 s. `oom_*.out` is OOMKilled and restart count after the run. `meili_data_size.out` is `du` of `/meili_data`. ## Notes - Meilisearch blocks internal IPs for embedder URLs. `MEILI_EXPERIMENTAL_ALLOWED_IP_NETWORKS` in `compose.meili.yml` allows the Docker Desktop address of `host.docker.internal` (192.168.65.254, check yours with `getent hosts host.docker.internal` in the container). - `ts_embedder.py` downloads the `ts/all-MiniLM-L12-v2` model from the internet on first use. - Both engines run keyword mode at their defaults. Typesense `drop_tokens_threshold` defaults to 1; `ts_query.out` has one side check with 50 and `ts_keyword_diag.out` has the per-question counts (not in the post's table). - The Meilisearch mini dashboard screenshot used a scratch global key with `search`, `indexes.get`, `version` and `stats.get`; it was created by hand, is not in a script and was never written to this folder. Stop: `docker compose -f compose.meili.yml down -v` and `docker compose -f compose.ts.yml down -v`. Remove cached images if you do not want them: `docker rmi getmeili/meilisearch:v1.56.2 typesense/typesense:30.2`.