Hanzo

Hanzo Search

AI-powered search engine built in Rust with sub-50ms response times, hybrid semantic/full-text search, faceted filtering, geo search, chat completions, and multi-language support.

Hanzo Search

Hanzo Search is a high-performance, AI-powered search engine built in Rust. It delivers sub-50ms query responses with typo tolerance, hybrid semantic and full-text search, faceted filtering, geo search, and built-in chat completions powered by LLMs.

Endpoint: search.hanzo.ai Gateway: api.hanzo.ai/v1/search/* Default Port: 7700 Source: github.com/hanzoai/search

Features

  • Hybrid Search -- Combine semantic vector search with full-text keyword search using configurable semantic ratios for maximum relevance
  • Search-as-you-type -- Sub-50ms query responses with prefix matching for instant, interactive search
  • Typo Tolerance -- Return relevant results even when queries contain typos and misspellings
  • Faceted Filtering -- Build rich, filterable search interfaces with custom facets and facet search
  • Geo Search -- Filter and sort documents by geographic coordinates and radius
  • Multi-Language -- Optimized tokenization for Chinese, Japanese, Hebrew, Thai, and Latin-alphabet languages
  • Custom Ranking Rules -- Define attribute-level ranking with words, typo, proximity, attribute, sort, and exactness rules
  • Synonyms and Stop Words -- Configure synonym mappings and stop word lists per index
  • Chat Completions -- OpenAI-compatible chat endpoint that searches your indexes and generates answers via LLMs
  • Multi-Index Search -- Federated search across multiple indexes in a single request
  • Multi-Tenancy -- Fine-grained API key permissions and tenant token isolation for SaaS applications
  • Embedder Support -- Built-in integrations with OpenAI, Ollama, Hugging Face, and custom REST embedders
  • Prometheus Metrics -- Expose search and indexing metrics at /metrics
  • S3 Snapshots -- Stream database snapshots directly to S3-compatible storage

Architecture

+------------------------------------------------------------------+
|                        HANZO SEARCH                               |
+------------------------------------------------------------------+
|                                                                    |
|  +------------------------------+  +----------------------------+ |
|  |        HTTP API (actix)      |  |     Chat Completions       | |
|  |  +--------+ +--------+      |  |  +--------+ +----------+   | |
|  |  | Search | | Index  |      |  |  | OpenAI | | Streaming|   | |
|  |  | Routes | | Routes |      |  |  | Compat | |   SSE    |   | |
|  |  +--------+ +--------+      |  |  +--------+ +----------+   | |
|  +------------------------------+  +----------------------------+ |
|                                                                    |
|  +------------------------------+  +----------------------------+ |
|  |     Index Scheduler          |  |      Vector Engine          | |
|  |  +--------+ +--------+      |  |  +--------+ +----------+   | |
|  |  | Tasks  | | Batches|      |  |  | HNSW   | | Embedders|   | |
|  |  +--------+ +--------+      |  |  +--------+ +----------+   | |
|  +------------------------------+  +----------------------------+ |
|                                                                    |
|  +------------------------------+  +----------------------------+ |
|  |     milli (Core Engine)      |  |      Auth & Tenancy        | |
|  |  +--------+ +--------+      |  |  +--------+ +----------+   | |
|  |  | BM25   | | Filters|      |  |  | API    | | Tenant   |   | |
|  |  | Ranking| | & Facets|     |  |  | Keys   | | Tokens   |   | |
|  |  +--------+ +--------+      |  |  +--------+ +----------+   | |
|  +------------------------------+  +----------------------------+ |
|                                                                    |
|  +--------------------------------------------------------------+ |
|  |                  LMDB Storage (heed)                          | |
|  +--------------------------------------------------------------+ |
+------------------------------------------------------------------+

Core crates:

  • hanzo-search -- HTTP server, routes, authentication, search queue
  • milli -- Core search engine: indexing, ranking, filtering, vector search, hybrid search
  • index-scheduler -- Asynchronous task scheduling and batch processing
  • hanzo-search-auth -- API key management and tenant token validation
  • filter-parser -- Filter expression parser for faceted search
  • hanzo-search-types -- Shared types, settings, and error codes

Quick Start

Docker

docker run -d \
  --name hanzo-search \
  -p 7700:7700 \
  -v hanzo_search_data:/meili_data \
  hanzoai/search:latest \
  hanzo-search --master-key="YOUR_MASTER_KEY"

From Source

git clone https://github.com/hanzoai/search.git && cd search
cargo build --release
./target/release/hanzo-search --master-key="YOUR_MASTER_KEY"

curl

# Add documents
curl -X POST 'http://localhost:7700/indexes/products/documents' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '[
    { "id": 1, "title": "Hanzo Agent SDK", "category": "AI", "price": 0 },
    { "id": 2, "title": "Hanzo MCP Server", "category": "Infrastructure", "price": 49 },
    { "id": 3, "title": "Hanzo LLM Gateway", "category": "AI", "price": 99 }
  ]'

# Search
curl 'http://localhost:7700/indexes/products/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{ "q": "agent" }'

Python

import requests

BASE = "http://localhost:7700"
HEADERS = {
    "Authorization": "Bearer YOUR_MASTER_KEY",
    "Content-Type": "application/json",
}

# Index documents
requests.post(f"{BASE}/indexes/products/documents", headers=HEADERS, json=[
    {"id": 1, "title": "Hanzo Agent SDK", "category": "AI"},
    {"id": 2, "title": "Hanzo MCP Server", "category": "Infrastructure"},
])

# Search
resp = requests.post(f"{BASE}/indexes/products/search", headers=HEADERS, json={
    "q": "agent",
    "limit": 10,
    "attributesToHighlight": ["title"],
})
print(resp.json()["hits"])

JavaScript / TypeScript

import { HanzoSearch } from '@hanzo/search'

const client = new HanzoSearch({
  host: 'http://localhost:7700',
  apiKey: 'YOUR_MASTER_KEY',
})

// Index documents
const index = client.index('products')
await index.addDocuments([
  { id: 1, title: 'Hanzo Agent SDK', category: 'AI' },
  { id: 2, title: 'Hanzo MCP Server', category: 'Infrastructure' },
])

// Search
const results = await index.search('agent', {
  limit: 10,
  attributesToHighlight: ['title'],
})
console.log(results.hits)

Indexing

Create an Index

Indexes are created automatically when you add documents, or explicitly:

curl -X POST 'http://localhost:7700/indexes' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  -H 'Content-Type: application/json' \
  --data-binary '{ "uid": "products", "primaryKey": "id" }'

Add Documents

Documents are JSON objects. Hanzo Search accepts arrays, NDJSON, and CSV formats. The maximum payload size defaults to 100 MB.

# JSON array
curl -X POST 'http://localhost:7700/indexes/products/documents' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary @products.json

# NDJSON
curl -X POST 'http://localhost:7700/indexes/products/documents' \
  -H 'Content-Type: application/x-ndjson' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary @products.ndjson

Update Documents

Use PUT to replace documents or PATCH (via update endpoint) to partially update:

curl -X PUT 'http://localhost:7700/indexes/products/documents' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  -H 'Content-Type: application/json' \
  --data-binary '[{ "id": 1, "price": 29.99 }]'

Searching

curl -X POST 'http://localhost:7700/indexes/products/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "q": "agent sdk",
    "limit": 20,
    "offset": 0,
    "attributesToRetrieve": ["id", "title", "category"],
    "attributesToHighlight": ["title"],
    "attributesToCrop": ["description"],
    "cropLength": 50,
    "showMatchesPosition": true,
    "showRankingScore": true
  }'

Combine keyword and semantic search by configuring an embedder and using hybrid:

curl -X POST 'http://localhost:7700/indexes/products/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "q": "tools for building AI agents",
    "hybrid": {
      "semanticRatio": 0.5,
      "embedder": "default"
    }
  }'

A semanticRatio of 0.0 uses pure keyword search, 1.0 uses pure vector search, and 0.5 blends both equally.

Search across multiple indexes in a single request:

curl -X POST 'http://localhost:7700/multi-search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "queries": [
      { "indexUid": "products", "q": "agent" },
      { "indexUid": "docs", "q": "agent", "limit": 5 }
    ]
  }'

Search within facet values for building autocomplete on filters:

curl -X POST 'http://localhost:7700/indexes/products/facet-search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "facetName": "category",
    "facetQuery": "infra"
  }'

Filtering

Declare filterable attributes in settings, then use filter expressions in search:

# Configure filterable attributes
curl -X PATCH 'http://localhost:7700/indexes/products/settings' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "filterableAttributes": ["category", "price", "tags", "_geo"]
  }'

# Filter by exact match
curl -X POST 'http://localhost:7700/indexes/products/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "q": "sdk",
    "filter": "category = AI AND price < 100"
  }'

# Complex filters with OR and nested expressions
curl -X POST 'http://localhost:7700/indexes/products/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "q": "sdk",
    "filter": "(category = AI OR category = Infrastructure) AND price >= 0"
  }'

Filter and sort by geographic location:

# Filter within radius (meters)
curl -X POST 'http://localhost:7700/indexes/stores/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "filter": "_geoRadius(37.7749, -122.4194, 5000)",
    "sort": ["_geoPoint(37.7749, -122.4194):asc"]
  }'

# Bounding box filter
curl -X POST 'http://localhost:7700/indexes/stores/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "filter": "_geoBoundingBox([37.8, -122.5], [37.7, -122.3])"
  }'

Documents must include a _geo field with lat and lng properties.

Faceted Filtering

Return facet value counts alongside search results:

curl -X POST 'http://localhost:7700/indexes/products/search' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "q": "",
    "facets": ["category", "tags"],
    "filter": "price < 100"
  }'

AI Features

Chat Completions

Hanzo Search includes an OpenAI-compatible chat completions endpoint. The LLM automatically searches your indexes to answer questions, with streaming SSE responses:

curl -X POST 'http://localhost:7700/chats/default/chat/completions' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  -H 'Content-Type: application/json' \
  --data-binary '{
    "model": "gpt-4o",
    "messages": [
      { "role": "user", "content": "What AI tools do you have?" }
    ],
    "stream": true
  }'

The chat system:

  • Automatically calls _searchInIndex to find relevant documents
  • Reports search progress via _searchProgress tool calls
  • Returns source citations via _searchSources
  • Supports conversation context via _appendConversationMessage

Embedder Configuration

Configure embedders per index for semantic and hybrid search:

# OpenAI embedder
curl -X PATCH 'http://localhost:7700/indexes/products/settings' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "embedders": {
      "default": {
        "source": "openAi",
        "apiKey": "sk-...",
        "model": "text-embedding-3-small",
        "documentTemplate": "A product titled {{doc.title}} in category {{doc.category}}"
      }
    }
  }'

# Ollama embedder (self-hosted)
curl -X PATCH 'http://localhost:7700/indexes/products/settings' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "embedders": {
      "local": {
        "source": "ollama",
        "url": "http://localhost:11434/api/embeddings",
        "model": "nomic-embed-text"
      }
    }
  }'

# Hugging Face embedder (runs locally)
curl -X PATCH 'http://localhost:7700/indexes/products/settings' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "embedders": {
      "hf": {
        "source": "huggingFace",
        "model": "BAAI/bge-base-en-v1.5"
      }
    }
  }'

Supported embedder sources: openAi, ollama, huggingFace, rest (custom endpoint), userProvided (bring your own vectors), and composite (different embedders for indexing vs search).

Binary Quantization

Reduce vector storage by enabling quantization on embedders:

{
  "embedders": {
    "default": {
      "source": "openAi",
      "binaryQuantized": true
    }
  }
}

Configuration

Environment Variables

VariableDefaultDescription
SEARCH_MASTER_KEY--Master API key (required in production)
SEARCH_ENVdevelopmentdevelopment or production
SEARCH_DB_PATH./data.msDatabase storage directory
SEARCH_HTTP_ADDRlocalhost:7700Bind address and port
SEARCH_HTTP_PAYLOAD_SIZE_LIMIT100 MBMaximum request payload size
SEARCH_LOG_LEVELINFOLog level: OFF, ERROR, WARN, INFO, DEBUG, TRACE
SEARCH_NO_ANALYTICSfalseDisable telemetry
SEARCH_SCHEDULE_SNAPSHOTfalseEnable periodic snapshots
SEARCH_SNAPSHOT_DIRsnapshots/Snapshot storage directory
SEARCH_DUMP_DIRdumps/Dump storage directory

S3 Snapshot Configuration

Stream snapshots to S3-compatible storage (Hanzo S3, AWS S3):

VariableDescription
SEARCH_S3_BUCKET_URLS3 endpoint URL
SEARCH_S3_BUCKET_REGIONBucket region
SEARCH_S3_BUCKET_NAMEBucket name
SEARCH_S3_ACCESS_KEYAccess key
SEARCH_S3_SECRET_KEYSecret key

Index Settings

curl -X PATCH 'http://localhost:7700/indexes/products/settings' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "searchableAttributes": ["title", "description", "category"],
    "filterableAttributes": ["category", "price", "tags", "_geo"],
    "sortableAttributes": ["price", "created_at"],
    "rankingRules": ["words", "typo", "proximity", "attribute", "sort", "exactness"],
    "distinctAttribute": "sku",
    "synonyms": {
      "phone": ["smartphone", "mobile"],
      "laptop": ["notebook", "computer"]
    },
    "stopWords": ["the", "a", "an", "is"],
    "typoTolerance": {
      "enabled": true,
      "minWordSizeForTypos": { "oneTypo": 5, "twoTypos": 9 }
    },
    "pagination": { "maxTotalHits": 1000 },
    "faceting": { "maxValuesPerFacet": 100 }
  }'

API Key Management

Create scoped API keys for multi-tenant access:

# Create a search-only key for a specific index
curl -X POST 'http://localhost:7700/keys' \
  -H 'Authorization: Bearer YOUR_MASTER_KEY' \
  --data-binary '{
    "description": "Products search key",
    "actions": ["search"],
    "indexes": ["products"],
    "expiresAt": "2027-01-01T00:00:00Z"
  }'

SDKs

LanguagePackageRepository
JavaScript / TypeScript@hanzo/searchhanzoai/search-js
Pythonhanzo-searchhanzoai/search-python
Gogithub.com/hanzoai/search-gohanzoai/search-go
Rusthanzo-searchhanzoai/search-rust

API Reference

Indexes

MethodPathDescription
GET/indexesList all indexes
POST/indexesCreate an index
GET/indexes/{uid}Get index details
PATCH/indexes/{uid}Update index (primary key)
DELETE/indexes/{uid}Delete an index
POST/swap-indexesSwap two indexes atomically

Documents

MethodPathDescription
POST/indexes/{uid}/documentsAdd or replace documents
PUT/indexes/{uid}/documentsAdd or update documents
GET/indexes/{uid}/documentsList documents
GET/indexes/{uid}/documents/{id}Get a single document
DELETE/indexes/{uid}/documentsDelete documents by filter or IDs
MethodPathDescription
POST/indexes/{uid}/searchSearch an index
GET/indexes/{uid}/searchSearch an index (GET)
POST/indexes/{uid}/facet-searchSearch facet values
POST/multi-searchFederated multi-index search

Chat

MethodPathDescription
GET/chatsList chat workspaces
GET/chats/{uid}Get workspace details
DELETE/chats/{uid}Delete a workspace
POST/chats/{uid}/chat/completionsChat completion with search

Settings

MethodPathDescription
GET/indexes/{uid}/settingsGet all settings
PATCH/indexes/{uid}/settingsUpdate settings
DELETE/indexes/{uid}/settingsReset all settings

Tasks

MethodPathDescription
GET/tasksList tasks
GET/tasks/{uid}Get task status
DELETE/tasksCancel/delete tasks

System

MethodPathDescription
GET/healthHealth check
GET/versionVersion info
GET/statsDatabase statistics
GET/metricsPrometheus metrics
POST/dumpsCreate a database dump
POST/snapshotsCreate a snapshot

Vector similarity search with HNSW indexing for dense embedding workloads and RAG pipelines.

AI knowledge base platform with document ingestion, retrieval, and agent management.

Managed AI inference and services platform with unified billing and API keys.

Observability dashboard for monitoring search performance, usage, and costs.

How is this guide?

Last updated on

On this page