Amgix Building Blocks
Amgix is a modular distributed hybrid search system. The definition may sound intimidating and confusing. A lot of strange terminology floating around: Amgix API, Amgix Encoder, Amgix One, Amgix Now. This can be understandably overwhelming. Sounds complex. We'll try to demystify all of this in this page and show you that it's really much easier than it may appear.
"Modular" in the definition is the key. Amgix was build as a set of components that can be deployed and combined in multiple configurations, depending on your needs: from a single container deployments to a distributed cluster configuration. Amgix is designed to be flexible and expandable to grow with your needs.
There are only 3 distinct Amgix components (container images):
- Amgix API: Lightweight frontend application implementing Amgix API in Python with FastAPI framework.
- Amgix Encoder: Backend worker application that does the heavy-lifting: indexing, embedding, searching, etc. Encoders can be specialized to do only indexing or only searching, to participate in model embeddings or not. But by default, they do it all.
- Amgix Now: Fast and lean implementation of Amgix API contract in Rust as a single binary. You can think of it as Rust implementation of Amgix API and Amgix Encoder combined.
Maybe a diagram will help:
---
config:
htmlLabels: false
---
flowchart TB
amgix["`**Amgix API (Contract)**`"]
one["`**Amgix One**
*
Single-image packaging of **Amgix API** and **Amgix Encoder**
`"]
now["`**Amgix Now**
*
Single-image packaging of Rust implementation of API Contract
`"]
api["`**Amgix API**
*
Python implementation of API Contract
`"]
encoder["`**Amgix Encoder**
*
Python/Rust implementation of backend worker
`"]
amgix --> one
amgix --> now
amgix --> api
api --> encoder
As you can see from the diagram, Amgix One is not a different application, it's just Amgix API and Amgix Encoder packaged to be deployed as a single container.
This modular architecture is designed to allow individual parts of the system to be scaled out independently, based on your needs. You can start simple with a single Amgix One or Amgix Now container. When your demand grows, instead of "just add more monoliths", Amgix allows you to add just the components you need. Because API is the same your application doesn't need to know or care how Amgix is deployed - your code stays the same.
Deployment Possibilities
Start Simple
You can start simple with a single Amgix One or Amgix Now container. They implement the same API contract. So the differences are only operational:
-
Amgix One
docker run -d \ -p 8234:8234 \ -v <path/on/host>:/data \ amgixio/amgix-one:1Full features of Amgix, including:
- Asynchronous document ingestion
- Synchronous document ingestion
- Metrics
- Dashboard
- Supported Backends: Qdrant, PostgreSQL, or MariaDB
-
Amgix Now
docker run -d \ -p 8235:8235 \ -v <path/on/host>:/data \ amgixio/amgix-now:0Full implementation of Amgix API (contract):
- Lowest latencies and maximum throughput
- Synchronous document ingestion only
- Metrics reported only as a part of Amgix cluster
- Does not have a dashboard
- Supported backends: Qdrant
But here is an interesting bit: because both support the same API and have the same storage format (providing you use Qdrant), you can start with either one and simply switch to the other by starting a different container image over the same mounted volume. Your application doesn't have to change.
Best of Both Worlds: Simple Cluster
Want to get the best of both worlds: raw search performance of Amgix Now, AND async pipeline, metrics and dashboard of Amgix One? No problem. You can read how we implemented a similar pattern in findgovdata.org on 2 vCPU cores with typeahead search performance.
---
config:
htmlLabels: false
---
flowchart TB
or[Load Balancer / Proxy] <-->|fast search| an["`**Amgix Now**`"]
or <-.->|search failover| ao["`**Amgix One**`"]
or -->|async docs ingestion| ao
ao -->|metrics / dashboard| ob[Observability]@{ shape: braces }
an <--> br([RabbitMQ])
ao <--> br
an <--> db[(Qdrant)]
ao <--> db
Amgix Cluster
Need more? We can replace Amgix One instance with independently scalable groups of Amgix API and Amgix Encoder instances. You may setup something like this:
flowchart TB
or[Load Balancer / Proxy] <-->|fast search| an["`**Amgix Now** nodes`"]@{ shape: procs }
or <-.->|search failover| api["`**Amgix API** nodes`"]@{ shape: procs }
or -->|async docs ingestion| api
api <--> enc["`**Amgix Encoder** nodes`"]@{ shape: procs }
api -->|metrics / dashboard| ob[Observability]@{ shape: braces }
an <--> br([RabbitMQ])
an <--> db[(Qdrant)]
enc <--> br
enc <--> db
Enterprise Amgix Cluster
Using Amgix Encoder roles we can take this even further:
flowchart TB
or[Load Balancer / Proxy] <-->|fast search| an["`**Amgix Now** nodes`"]@{ shape: procs }
or <-.->|search failover| api["`**Amgix API** nodes`"]@{ shape: procs }
or -->|async docs ingestion| api
api <-.->|search failover| query["`**Amgix Encoder**
query nodes`"]@{ shape: procs }
api <-->|docs ingestion| index["`**Amgix Encoder**
index nodes`"]@{ shape: procs }
api <-->|docs ingestion| gpu["`**Amgix Encoder**
GPU model embedding/indexing nodes`"]@{ shape: procs }
api -->|metrics / dashboard| ob[Observability]@{ shape: braces }
an <--> br([RabbitMQ Cluster])
an <--> db[(Qdrant Cluster)]
query <--> br
query <--> db
index <--> br
index <--> db
gpu <--> br
gpu <--> db
query <-.->|model embedding| gpu
index <-.->|model embedding| gpu
Each group of nodes can scale independently based on demand.
Conclusion
This is what we mean by "modular" and by "distributed". With just 3 components/applications we can go from a single container deployment to a distributed modular enterprise cluster setup.