Skip to content

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:1
    

    Full 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:0
    

    Full implementation of Amgix API (contract):

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.