Migrating from Typesense
[TODO i18n — see issue #76] "Step-by-step guide for moving from Typesense to AACsearch Engine — migrate indexes, API keys, and search widgets."
Migrating from Typesense
This guide walks you through moving from Typesense to AACsearch Engine. The process is designed for minimal downtime and usually takes just a few hours.
Migration overview
| Step | What you do | Time |
|---|---|---|
| 1 | Export the index from Typesense | ~5 minutes |
| 2 | Create the index in AACsearch | ~5 minutes |
| 3 | Import the data | ~10 minutes |
| 4 | Configure filters and synonyms | ~15 minutes |
| 5 | Update API keys | ~10 minutes |
| 6 | Update the frontend | ~30 minutes |
| 7 | Switch to the new endpoint | ~5 minutes |
Step 1: Export the index from Typesense
Use the Typesense CLI or API:
# Export documents to JSON
curl "http://localhost:8108/collections/products/documents/export" \
-H "X-TYPESENSE-API-KEY: your_api_key" \
> typesense-export.jsonOr use the Typesense Python client:
import typesense
import json
client = typesense.Client({
'nodes': [{'host': 'localhost', 'port': '8108', 'protocol': 'http'}],
'api_key': 'your_api_key',
'connection_timeout_seconds': 2
})
collection = client.collections['products'].retrieve()
documents = client.collections['products'].documents.export()
with open('typesense-export.json', 'w') as f:
f.write(documents)Step 2: Create the index in AACsearch
In the AACsearch dashboard or via the API:
curl -X POST "https://app.aacsearch.com/api/v1/indexes" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "products",
"fields": [
{"name": "id", "type": "string", "indexing": true},
{"name": "title", "type": "string", "indexing": true},
{"name": "description", "type": "string", "indexing": true},
{"name": "price", "type": "float", "sort": true},
{"name": "category", "type": "string", "facet": true},
{"name": "rating", "type": "float", "sort": true},
{"name": "in_stock", "type": "bool", "facet": true}
]
}'Step 3: Import the data
Transform the exported data and upload it:
# Exported documents typically come in JSON Lines format.
# You can usually import them directly:
curl -X POST "https://app.aacsearch.com/api/v1/indexes/products/documents/batch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @typesense-export.jsonOr transform into the expected format:
import json
# Read the exported documents
with open('typesense-export.json', 'r') as f:
lines = f.readlines()
documents = [json.loads(line) for line in lines]
# Make sure every document has an "id" field
for doc in documents:
if 'id' not in doc:
doc['id'] = str(doc.get('object_id', '')) # or another unique identifier
# Save as JSON
with open('import-data.json', 'w') as f:
json.dump(documents, f)
# Upload
import requests
with open('import-data.json', 'r') as f:
response = requests.post(
'https://app.aacsearch.com/api/v1/indexes/products/documents/batch',
headers={'Authorization': 'Bearer YOUR_API_KEY'},
json=json.load(f)
)
print(response.json())Step 4: Configure search settings
Filters (facets)
Translate Typesense parameters:
| Typesense | AACsearch | Notes |
|---|---|---|
facet_by: ["category"] | "facet": true on the field | Filterable field |
group_by: ["brand"] | String array "type": "string[]" | Result grouping |
Synonyms
Export synonyms from Typesense and import them into AACsearch:
# Export synonyms from Typesense
curl "http://localhost:8108/synonyms" \
-H "X-TYPESENSE-API-KEY: your_api_key" \
> typesense-synonyms.json
# Import into AACsearch
curl -X POST "https://app.aacsearch.com/api/v1/indexes/products/synonyms" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{"synonyms": ["sneakers", "trainers", "running shoes"]},
{"synonyms": ["phone", "smartphone", "mobile"]},
{"synonyms": ["laptop", "notebook", "computer"]}
]'Relevance sorting
Typesense uses a textMatchScore * popularity formula. AACsearch ships built-in ranking strategies:
# Update ranking rules
curl -X PUT "https://app.aacsearch.com/api/v1/indexes/products/ranking" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sortByFields": [
{"field": "relevance", "order": "desc"},
{"field": "rating", "order": "desc"},
{"field": "price", "order": "asc"}
]
}'Step 5: Update API keys
Create new API keys in AACsearch:
# Create a search key (public)
curl -X POST "https://app.aacsearch.com/api/v1/keys" \
-H "Authorization: Bearer YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Search API Key",
"scope": "search",
"indexes": ["products"]
}'
# Result:
# {
# "key": "ss_search_...",
# "keyHash": "..."
# }Important: the search key (public) is safe to embed in the client. Never use admin keys on the client.
Step 6: Update the frontend
JavaScript
// Old Typesense code
const typesense = new Typesense.SearchClient({
nodes: [{
host: 'localhost',
port: 8108,
protocol: 'http'
}],
apiKey: 'your_api_key',
connectionTimeoutSeconds: 2
});
// New AACsearch code
const searchClient = new AACSearchClient({
apiKey: 'ss_search_...',
baseURL: 'https://app.aacsearch.com'
});
// Search
const results = await searchClient.search({
indexSlug: 'products',
query: 'sneakers',
filters: { category: 'footwear', price: { lte: 10000 } },
limit: 20
});Python
import aac_search
client = aac_search.AACSearchClient(
api_key='ss_search_...',
base_url='https://app.aacsearch.com'
)
results = client.search(
index_slug='products',
query='sneakers',
filters={'category': 'footwear', 'price': {'lte': 10000}},
limit=20
)
for hit in results['hits']:
print(hit['title'], hit['price'])cURL
curl -X POST "https://app.aacsearch.com/api/v1/indexes/products/search" \
-H "Authorization: Bearer ss_search_..." \
-H "Content-Type: application/json" \
-d '{
"query": "sneakers",
"filters": {"category": "footwear", "price": {"lte": 10000}},
"limit": 20
}'Step 7: Switch to the new endpoint
Update the URL in your app
// Before
const searchURL = 'http://localhost:8108/collections/products/documents/search';
// After
const searchURL = 'https://app.aacsearch.com/api/v1/indexes/products/search';Update the search widget
<!-- Old Typesense widget -->
<script src="https://cdn.jsdelivr.net/npm/typesense-instantsearch-adapter@2/dist/typesense-instantsearch-adapter.min.js"></script>
<!-- New AACsearch widget -->
<div id="aac-search"></div>
<script
src="https://app.aacsearch.com/api/widget/widget.js"
data-api-key="ss_search_..."
data-index-slug="products"
data-container="#aac-search">
</script>Verifying the migration
-
Document count: confirm all documents were loaded
curl "https://app.aacsearch.com/api/v1/indexes/products" \ -H "Authorization: Bearer YOUR_API_KEY" -
Search works: try a few searches
curl -X POST "https://app.aacsearch.com/api/v1/indexes/products/search" \ -H "Authorization: Bearer ss_search_..." \ -d '{"query": "sneakers"}' -
Filters work: verify category and price filters
-
Performance: compare the latency of the old and new search
Rolling back to Typesense
If you hit issues you can roll back to Typesense:
// Point the URL back to Typesense
const searchURL = 'http://localhost:8108/collections/products/documents/search';
// Clear the browser cache (Ctrl+Shift+Delete)Frequently asked questions
Q: Did all documents load? A: Check the AACsearch dashboard → Search → Stats. The total should match Typesense.
Q: Why does search behave differently? A: AACsearch and Typesense use different ranking algorithms. That is expected. You can fine-tune sort order in index settings.
Q: Do I need to optimize anything? A: AACsearch optimizes indexes automatically. You don't need to do anything.
Q: How fast are new documents indexed? A: New documents are indexed within a few seconds.
Q: Does AACsearch support hierarchical filters?
A: Yes, use string arrays for hierarchical filters (e.g., ["Women's footwear", "Sneakers"]).