Skip to main content

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:

ModeValueWhat it findsWhat you need
Keyword searchnoneItems that contain the words of the queryWeaviate
Hybrid searchtext2vec-openaiItems that contain the words or mean the same thing as the queryWeaviate and an OpenAI-compatible embedding API

In hybrid mode, Artemis computes all vectors itself. Weaviate never calls the embedding model. For every item, Artemis:

  1. 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);
  2. 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;
  3. sends the pieces to the embedding API and gets one vector per piece;
  4. 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.…)RequiredDefaultMeaning
vectorizer-moduleyesnonenone for keyword search, text2vec-openai for hybrid search
open-ai-base-urlhybrid—Base URL of the embedding API as Artemis reaches it, without /v1
open-ai-embedding-modelhybrid—Model name sent with every request. Changing it rebuilds the index
gpu-api-keyhybrid—Bearer token for the embedding API. Use any non-empty value if the server needs none
open-ai-query-instructionnoemptyText put in front of every search query before it is embedded. See below
embedding.query-timeoutno3sTime 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-timeoutno60sThe same limit for embedding the pieces of an index write
embedding.max-inputs-per-requestno32Pieces sent in one request (at most 256)
embedding.background-max-rows-per-minuteno600Background index writes per minute (see Load)
embedding.background-max-requests-per-minuteno30Background 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-minute items (default 600) and send at most embedding.background-max-requests-per-minute requests (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:

  1. deletes the Artemis collections and creates them again, empty;
  2. clears its record of what is indexed, so the background repair finds every item as missing;
  3. starts the refill of posts and answer posts;
  4. 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 it marks the start;
  • [missing …] queued … entities the index had no record of appears while items are queued;
  • Global search refill of posts and answer posts is complete marks 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​

SymptomCauseFix
Startup fails with artemis.weaviate.open-ai-embedding-model (must be configured …)Hybrid mode without a model nameSet open-ai-embedding-model
Startup fails with artemis.weaviate.vectorizer-module ('text2vec-transformers' is no longer supported …)The removed local sidecar mode is still configuredUse text2vec-openai with a local server
Startup fails with open-ai-base-url or gpu-api-keyHybrid mode with a missing valueAdd the value
Log: Global search uses keyword search because the query could not be embeddedThe embedding API is down, slow, or rejects the requestCheck the API with the curl command above; raise embedding.query-timeout only if the server is healthy but slow
Log: Embedding request for … chunks failedBackground requests failSame check; the affected items are retried with growing delays and are indexed once the API works again
Log: Global search index check attempt … failedWeaviate went down after Artemis startedCheck Weaviate; Artemis repeats the check until it succeeds
Artemis does not start, log names WeaviateWeaviate is not reachable when Artemis startsStart Weaviate first, or check http-host, the ports and the key
401 Unauthorized from WeaviateWrong api-keyCompare it with AUTHENTICATION_APIKEY_ALLOWED_KEYS
gRPC errorsPort 50051 blocked, or a proxy without HTTP/2Open the port; let the proxy pass gRPC through
Search results stay incomplete for hoursThe rebuild is still running, or Global Search Reconcile is offSee Rebuild of the index
Search documentation