Global Search & Weaviate Setup
Artemis has a search across courses, lectures, lecture units, exercises, exams, FAQs, communication channels and posts.
It stores a search index in Weaviate and is switched on with artemis.weaviate.enabled
(default: off). Iris uses the same index to find course content for its answers.
This page explains how the search works, how to run Weaviate, how to connect an embedding model, what load Artemis puts on that model, and what happens when the index must be rebuilt.
How global search works
Global search runs in one of two modes, selected with artemis.weaviate.vectorizer-module:
| Mode | Value | What it finds | What you need |
|---|---|---|---|
| Keyword search | none | Items that contain the words of the query | Weaviate |
| Hybrid search | text2vec-openai | Items that contain the words or mean the same thing as the query | Weaviate and an OpenAI-compatible embedding API |
In hybrid mode, Artemis computes all vectors itself. Weaviate never calls the embedding model. For every item, Artemis:
- builds the text of the item: a short header line (type, title, and for example the exercise type or the lecture title) and the body (problem statement, description, content or answer);
- splits the text into pieces of at most about 470 tokens. Each piece starts with the header line and overlaps the previous piece by about one sentence, so no sentence is lost at a border. Short items, such as most FAQs, are one piece;
- sends the pieces to the embedding API and gets one vector per piece;
- stores one row per item in Weaviate, with all vectors of its pieces.
A search query also becomes one vector. Weaviate compares it with every piece of an item and scores the item by its best matching piece, and combines that score with the keyword score. A long exercise is therefore found by a sentence in the middle of its problem statement, not only by its beginning. Iris receives the best matching piece with each result, so it judges a long item by the part that matched.
If the embedding API cannot be reached within 3 seconds or does not answer within 3 more seconds
(embedding.query-timeout), the search falls back to keyword search for that query. Users always get results; Artemis logs a warning at most once per minute.
Provision Weaviate
Use Weaviate 1.37 or newer (tested with 1.37.2 and 1.38.20). Artemis connects over REST and gRPC.
Docker Compose
The repository ships deployment/docker/weaviate.yml. It works for both modes. Run it from the repository root:
docker compose --env-file .env -f deployment/docker/weaviate.yml up -d
The image is pinned to Weaviate 1.38.20. REST is on port 8001, gRPC on port 50051. Data is stored in the
Docker volume artemis-weaviate.
Production: disable anonymous access
The Compose file reads its Weaviate configuration from deployment/docker/weaviate/default.env. Anonymous access is
enabled there, which is fine for development only.
Change these lines in deployment/docker/weaviate/default.env:
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=false
AUTHENTICATION_APIKEY_ENABLED=true
AUTHENTICATION_APIKEY_ALLOWED_KEYS=your-secure-key
AUTHENTICATION_APIKEY_USERS=admin@your-domain.com
AUTHORIZATION_ADMINLIST_ENABLED=true
AUTHORIZATION_ADMINLIST_USERS=admin@your-domain.com
Then set the same key in Artemis as artemis.weaviate.api-key. The
Authentication section of the developer guide explains each variable.
Ansible (production, TLS and backups)
The Artemis Ansible collection has a Weaviate role for TLS, API keys and scheduled backups: ls1intum/artemis-ansible-collection — roles/weaviate.
Kubernetes or Weaviate Cloud
Artemis ships no Helm chart. Use any Weaviate deployment (1.37 or newer) and set
artemis.weaviate.http-host, http-port, grpc-port, scheme and api-key. Weaviate Cloud uses port 443 for REST
and gRPC.
Connect an embedding model
Skip this section for keyword search.
Requirements for the embedding API
Artemis calls POST {open-ai-base-url}/v1/embeddings in the OpenAI format, with a bearer token. Every server that
offers this endpoint works, for example vLLM, Ollama, Logos or the OpenAI API. The model must:
- accept at least 512 tokens per input (Artemis sends at most about 470);
- accept up to 32 inputs in one request (
artemis.weaviate.embedding.max-inputs-per-request).
Artemis checks every response: one finite, non-zero vector per input, all of the same length. A response that fails the check counts as a failed request.
Settings
Property (artemis.weaviate.…) | Required | Default | Meaning |
|---|---|---|---|
vectorizer-module | yes | none | none for keyword search, text2vec-openai for hybrid search |
open-ai-base-url | hybrid | — | Base URL of the embedding API as Artemis reaches it, without /v1 |
open-ai-embedding-model | hybrid | — | Model name sent with every request. Changing it rebuilds the index |
gpu-api-key | hybrid | — | Bearer token for the embedding API. Use any non-empty value if the server needs none |
open-ai-query-instruction | no | empty | Text put in front of every search query before it is embedded. See below |
embedding.query-timeout | no | 3s | Time limit for connecting and for the answer when a search query is embedded; after it, the search uses keywords. A search waits at most about twice this time |
embedding.write-timeout | no | 60s | The same limit for embedding the pieces of an index write |
embedding.max-inputs-per-request | no | 32 | Pieces sent in one request (at most 256) |
embedding.background-max-rows-per-minute | no | 600 | Background index writes per minute (see Load) |
embedding.background-max-requests-per-minute | no | 30 | Background embedding requests per minute |
Artemis checks the required settings at startup and refuses to start if one is missing. The former value
text2vec-transformers is no longer accepted; use text2vec-openai with a local server instead (see
Local CPU embeddings).
Query instruction
Some embedding models expect a short task description in front of the query, but not in front of the indexed texts. Qwen3-Embedding is one of them; for it, set:
artemis:
weaviate:
open-ai-query-instruction: "Instruct: Given a student's search on a university learning platform, retrieve the course item (exercise, lecture, lecture unit, exam, FAQ, channel) it refers to\nQuery: "
Keep the double quotes: YAML then turns \n into a line break, which the model expects. The trailing space after
Query: belongs to the value. Leave the property empty for models that need no instruction, such as the OpenAI
text-embedding-3 models. Changing the instruction takes effect at once and needs no rebuild, because it only changes
how queries are embedded.
Example: GPU server or cloud API
artemis:
weaviate:
enabled: true
http-host: your-weaviate-host
http-port: 443
grpc-port: 443
scheme: https
api-key: your-weaviate-api-key
collection-prefix: Artemis_
vectorizer-module: text2vec-openai
open-ai-base-url: https://your-embedding-endpoint # OpenAI: https://api.openai.com
open-ai-embedding-model: Qwen/Qwen3-Embedding-8B # OpenAI: text-embedding-3-small
gpu-api-key: your-embedding-api-key
open-ai-query-instruction: "Instruct: Given a student's search on a university learning platform, retrieve the course item (exercise, lecture, lecture unit, exam, FAQ, channel) it refers to\nQuery: "
Local CPU embeddings
Use this when no GPU and no external API are available. Ollama serves a small embedding model on
the CPU through the same OpenAI-compatible endpoint. The repository ships deployment/docker/ollama-embeddings.yml:
docker compose -f deployment/docker/ollama-embeddings.yml up -d
The file starts Ollama on port 11434 and downloads the model qwen3-embedding:0.6b (about 640 MB) once into the
Docker volume artemis-ollama. Wait until the download has finished:
docker compose -f deployment/docker/ollama-embeddings.yml logs -f ollama-pull
Then configure Artemis:
artemis:
weaviate:
enabled: true
http-host: your-weaviate-host
http-port: 8001
grpc-port: 50051
scheme: http # https for a TLS endpoint
api-key: your-weaviate-api-key # if Weaviate requires a key
collection-prefix: Artemis_
vectorizer-module: text2vec-openai
open-ai-base-url: http://localhost:11434 # the host where Ollama runs, as Artemis reaches it
open-ai-embedding-model: qwen3-embedding:0.6b
gpu-api-key: ollama # Ollama ignores the key, but it must not be empty
open-ai-query-instruction: "Instruct: Given a student's search on a university learning platform, retrieve the course item (exercise, lecture, lecture unit, exam, FAQ, channel) it refers to\nQuery: "
To use another Ollama model, set OLLAMA_EMBEDDING_MODEL before docker compose up and use the same name in
open-ai-embedding-model. The Compose file keeps the model in memory (OLLAMA_KEEP_ALIVE=-1), so no search waits for
the model to load.
On a CPU, embedding is much slower than on a GPU, and the speed depends on the server. Measure one query on your
server with the check command in Verify the setup (use "model": "qwen3-embedding:0.6b") and
prefix it with time. If a query takes longer than about 2 seconds, raise embedding.query-timeout above the measured
time; otherwise every search falls back to keyword search. The first indexing of a large instance also takes longer
than the rebuild estimate below.
Keyword search only
artemis:
weaviate:
enabled: true
http-host: your-weaviate-host
http-port: 8001
grpc-port: 50051
scheme: http # https for a TLS endpoint
api-key: your-weaviate-api-key # if Weaviate requires a key
collection-prefix: Artemis_
vectorizer-module: none
No embedding API is needed, and no data leaves your servers. You can switch to hybrid search later; Artemis then rebuilds the index (see Rebuild of the index).
Load on the embedding API
Artemis protects the embedding API and keeps searches fast:
- Searches and edits by users go first. A search embeds one query with a short time limit. An edit (for example of an exercise) is written right away and embeds only the pieces whose text changed; a change of only the due date sends no embedding request at all.
- Background work is limited. Index repairs and the rebuild write at most
embedding.background-max-rows-per-minuteitems (default 600) and send at mostembedding.background-max-requests-per-minuterequests (default 30, each with up to 32 pieces) per minute. They send one request at a time, and between two requests Artemis writes the edits by users that arrived meanwhile, so an edit waits for at most one embedding request. Artemis never waits for the budget: when it is used up, background work pauses until the next minute, and edits by users are still written at once. - Requests are small. No input is longer than about 470 tokens.
Lower the two background values if your embedding server is shared and slow. Raise them only if the server has capacity to spare.
Rebuild of the index
The stored vectors only fit the model that computed them. Artemis therefore stores a signature next to the index: the layout version, the mode and, in hybrid mode, the model name. When Artemis starts and the signature does not match the configuration, it rebuilds the index automatically. This happens:
- on the first start after an upgrade to a version with a new index layout;
- after a change of
vectorizer-module; - after a change of
open-ai-embedding-model.
A change of open-ai-base-url, gpu-api-key or open-ai-query-instruction does not trigger a rebuild. If you
point open-ai-base-url to a server that runs a different model under the same name, change the model name
too, or the index mixes two models.
What happens during a rebuild
About 30 seconds after the start (artemis.weaviate.migration.initial-delay-seconds), the scheduling node:
- deletes the Artemis collections and creates them again, empty;
- clears its record of what is indexed, so the background repair finds every item as missing;
- starts the refill of posts and answer posts;
- stores the new signature.
Then the background repair indexes every item again from the database, within the limits from Load. Search keeps working during the rebuild, but its results are incomplete until the rebuild has finished. Edits by users during the rebuild are indexed at once.
If Artemis stops during a rebuild, it starts the rebuild again on the next start, because the signature is written
last. Artemis does not start if Weaviate cannot be reached when it starts. If Weaviate goes down after the start but
before the check, the check is repeated every 2 minutes (artemis.weaviate.migration.retry-delay-seconds), and nothing
is written to the index until it has succeeded; all changes stay queued in the database.
How long a rebuild takes
With the default limits, the background work indexes up to 600 items and up to 960 pieces per minute, whichever limit comes first. Most items are one or two pieces; long problem statements are more. As an example, an instance with 40,000 items needs about one to two hours. A slow embedding server can make it longer, because each request must finish before the next one starts.
Follow the progress in the log of the scheduling node:
The global search index was built for '…' but the configuration needs '…'. Rebuilding itmarks the start;[missing …] queued … entities the index had no record ofappears while items are queued;Global search refill of posts and answer posts is completemarks the end of the post refill.
The rebuild is finished when the missing pass no longer queues anything.
Run Weaviate alongside Pyris
One Weaviate instance can serve Artemis and Pyris (EduTelligence) at the same time. They use separate collections and separate embedding settings. For the Pyris side, see the Iris / EduTelligence admin documentation.
Namespace isolation
The prefix is put in front of every collection Artemis creates. Changing it points Artemis at new, empty collections. Artemis then indexes everything again through the background repair, like after a rebuild.
Embedding settings
The embedding settings of Artemis apply only to Artemis collections. Pyris computes its own vectors. Different models and vector lengths in Artemis and Pyris collections are no problem.
API key and gRPC
Artemis and Pyris may use the same Weaviate API key. For stricter isolation, Weaviate offers role-based access control. The gRPC port (default 50051) must be reachable from Artemis. Protect it like the REST port: with TLS or with firewall rules that admit only the application servers.
Operate
Verify the setup
Artemis has a Weaviate health indicator. With an admin token:
curl -s -H "Authorization: Bearer <admin-access-token>" \
https://your-artemis-host/management/health | jq '.components.weaviate'
A healthy result is "status": "UP". You can also check Weaviate directly:
curl -H "Authorization: Bearer your-weaviate-api-key" https://your-weaviate-host/v1/.well-known/ready
200 means ready, 401 means a wrong key. To check the embedding API from the Artemis host, send one input:
curl -s https://your-embedding-endpoint/v1/embeddings \
-H "Authorization: Bearer your-embedding-api-key" -H "Content-Type: application/json" \
-d '{"model": "Qwen/Qwen3-Embedding-8B", "input": ["test"]}' | jq '.data[0].embedding | length'
The result is the vector length of the model, for example 4096.
Backups
The Ansible role includes scheduled backups through Weaviate's backup module. For manual backups, see the Weaviate backup documentation. Artemis can always rebuild its index from the database, so a backup only saves the time of a rebuild.
Weaviate upgrades
Upgrade Weaviate one minor version at a time (for example 1.37 → 1.38), read the release notes before each step, and take a backup first. After the upgrade, check the health indicator. A Weaviate upgrade does not trigger a rebuild.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Startup fails with artemis.weaviate.open-ai-embedding-model (must be configured …) | Hybrid mode without a model name | Set open-ai-embedding-model |
Startup fails with artemis.weaviate.vectorizer-module ('text2vec-transformers' is no longer supported …) | The removed local sidecar mode is still configured | Use text2vec-openai with a local server |
Startup fails with open-ai-base-url or gpu-api-key | Hybrid mode with a missing value | Add the value |
Log: Global search uses keyword search because the query could not be embedded | The embedding API is down, slow, or rejects the request | Check the API with the curl command above; raise embedding.query-timeout only if the server is healthy but slow |
Log: Embedding request for … chunks failed | Background requests fail | Same check; the affected items are retried with growing delays and are indexed once the API works again |
Log: Global search index check attempt … failed | Weaviate went down after Artemis started | Check Weaviate; Artemis repeats the check until it succeeds |
| Artemis does not start, log names Weaviate | Weaviate is not reachable when Artemis starts | Start Weaviate first, or check http-host, the ports and the key |
401 Unauthorized from Weaviate | Wrong api-key | Compare it with AUTHENTICATION_APIKEY_ALLOWED_KEYS |
| gRPC errors | Port 50051 blocked, or a proxy without HTTP/2 | Open the port; let the proxy pass gRPC through |
| Search results stay incomplete for hours | The rebuild is still running, or Global Search Reconcile is off | See Rebuild of the index |