Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:MauQNotes is a semantic search application designed to function as a personal search engine for notes. It converts text notes into numerical vector representations (embeddings) and stores them in a vector database (Qdrant). This allows users to query their notes based on semantic meaning rather than just keyword matching. The architecture is composed of a main application driver, a search service that orchestrates the core logic, an embedding generation module that can interface with different AI models, and a client for communicating with the Qdrant vector database.
The system supports two primary operations: ingesting notes into the database and querying the database to find the most relevant notes for a given search term. The application is configured via environment variables, allowing flexibility in choosing the embedding model and connecting to the Qdrant instance.
Sources: cmd/app/main.go:10-29, internal/search/service.go:1-77
Core Components
The application is built around several key Go packages that handle distinct responsibilities.
This diagram shows the high-level interaction between the main components of the MauQNotes application.
Sources: cmd/app/main.go:7, internal/search/service.go:8-9
Search Service
Path: internal/search/service.go
The search package is the central coordinator. It initializes application settings, handles the note ingestion process, and executes search queries.
Init(): Reads theEMBEDDING_MODELenvironment variable and determines the correct vector dimension size for the Qdrant collection.IngestNotes(notes []string): Takes a slice of strings, generates an embedding for each using an embedding provider (e.g., Ollama), createsqdrant.Pointobjects, and upserts them into the Qdrant collection.Query(topK int, q string): Takes a search query string, generates an embedding for it, and uses the Qdrant client to perform a similarity search. It also includes a naive reranking logic that slightly boosts the score of results containing the query keyword.
Sources: internal/search/service.go:12-77
Qdrant Client
Path: internal/qdrant/client.go
The qdrant package provides a client for interacting with a Qdrant vector database instance via its REST API. It abstracts the HTTP requests for creating collections, upserting data points, and performing searches.
Clientstruct: Holds the configuration for the Qdrant connection, includingBaseUrl,APIKey, andCollectionname, which are loaded from environment variables.CreateCollectionIfNotExists(...): Sends aPUTrequest to create a new collection with a specified vector size and distance metric. It gracefully handles cases where the collection already exists (HTTP 409).Upsert(points []Point): Batches and sendsPointdata to the/pointsendpoint to be indexed.Search(queryVec []float32, limit int): Sends aPOSTrequest to the/points/searchendpoint with a query vector to find thelimitmost similar points.
The client defines several data structures to map to the Qdrant API's JSON request and response bodies.
| Structure | File | Purpose |
|---|---|---|
Point | internal/qdrant/client.go:23-27 | Represents a single data point with an ID, a vector, and a JSON payload. |
createCollectionRequest | internal/qdrant/client.go:15-20 | Defines the body for a collection creation request. |
upsertRequest | internal/qdrant/client.go:29-31 | Defines the body for an upsert request, containing a slice of Points. |
searchRequest | internal/qdrant/client.go:34-40 | Defines the body for a search request, including the query vector and limit. |
Sources: internal/qdrant/client.go:53-207
Embedding Generation
Paths: internal/embeddings/ollama.go, internal/embeddings/openai.go
The embeddings package is responsible for converting text into vector embeddings. It provides functions to call external embedding model providers. The application primarily uses Ollama but also contains a client for OpenAI.
FromOllama(text string): Sends a POST request to a local Ollama instance (http://localhost:11434/api/embeddingsby default) to generate an embedding for the given text. The model used is determined by theEMBEDDING_MODELenvironment variable.FromOpenAI(text string): An alternative function that sends a request to the OpenAI API (https://api.openai.com/v1/embeddings) to generate an embedding. This requires anOPENAI_API_KEY.
Both functions convert the []float64 response from the APIs into []float32 as required by the Qdrant client.
Sources: internal/embeddings/ollama.go:23-80, internal/embeddings/openai.go:22-73, internal/search/service.go:44, internal/search/service.go:61
Data Flow
The application has two main data flows: Ingestion and Querying.
Ingestion Flow
The ingestion process takes raw text notes, converts them into vector points, and stores them in Qdrant.
This diagram illustrates the sequence of operations during the note ingestion process.
Sources: cmd/app/main.go:17-19, internal/search/service.go:38-58
Query Flow
The query process takes a user's text query, converts it into a vector, and searches Qdrant for the most semantically similar notes.
This diagram illustrates the sequence of operations when performing a semantic search.
Sources: cmd/app/main.go:22-24, internal/search/service.go:60-77
Configuration
The application is configured using a .env file, which is loaded at runtime.
| Environment Variable | Description | Default Value | Source File(s) |
|---|---|---|---|
EMBEDDING_MODEL | Specifies the name of the embedding model to use. | nomic-embed-text | internal/search/service.go:14-16 |
QDRANT_URL | The base URL of the Qdrant instance. | (none) | internal/qdrant/client.go:56 |
QDRANT_API_KEY | The API key for authenticating with Qdrant. | (none) | internal/qdrant/client.go:57 |
QDRANT_COLLECTION | The name of the collection to use in Qdrant. | (none) | internal/qdrant/client.go:58 |
OLLAMA_URL | The URL of the Ollama API service. | http://localhost:11434 | internal/embeddings/ollama.go:26-29 |
OPENAI_API_KEY | The API key for the OpenAI embeddings API. | (none) | internal/embeddings/openai.go:23 |
Sources: internal/search/service.go:13, internal/qdrant/client.go:54, internal/embeddings/ollama.go:24, internal/embeddings/openai.go:22
Supported Embedding Models
The choice of EMBEDDING_MODEL affects the dimension of the vectors stored in Qdrant. The system has built-in logic to handle different dimensions for specific models.
| Model Name | Vector Dimension | Notes | Source File(s) |
|---|---|---|---|
nomic-embed-text | 768 | Recommended default | internal/search/service.go:21-22 |
all-minilm | 384 | Smaller, faster model | internal/search/service.go:23-24 |
mxbai-embed-large | 512 | Larger, more accurate | internal/search/service.go:25-26 |
Note: The setup-ollama.md file lists mxbai-embed-large as having 1024 dimensions, while search/service.go hardcodes it to 512. The code's logic will use 512.
Sources: internal/search/service.go:19-29, setup-ollama.md:21-23