Database
MeiliSearch
Overview
MeiliSearch is a lightweight and fast full-text search engine developed in Rust. It features excellent typo tolerance and search response times under 50 milliseconds, with simple operations via RESTful API. As a self-hostable open-source software optimized for multiple languages including Japanese, it provides an easy-to-use search solution for developers.
Details
MeiliSearch is developed by Meilisearch company in Paris, France, as a next-generation search engine. Leveraging Rust's safety and high performance, it aims to solve the challenges of traditional search engines. It was open-sourced in 2020, with stable version v1.0 released in July 2023.
Key features of MeiliSearch:
- Ultra-fast search: Average 4 millisecond search response time
- Strong typo tolerance: Returns appropriate search results even with typos
- Lightweight design: Operates with low memory usage
- Multi-language support: Built-in Japanese morphological analyzer Lindera
- RESTful API: Simple and intuitive API design
- Faceted search: Filtering by attributes
- Geospatial search: Location-based search
- Ranking customization: Adjustable search result ranking rules
- Synonym functionality: Search expansion with synonyms
- Highlight functionality: Emphasis display of search keywords
- Vector search: Semantic search (experimental feature)
- Multi-tenancy: User-specific access control
Pros and Cons
Pros
- Excellent typo tolerance: Returns expected results even with input errors
- Ultra-fast search: 4 millisecond response time for instant result display
- Lightweight resources: Operates with minimal memory and CPU
- Easy setup: Can be built in under 5 minutes with Docker
- Excellent UX: Supports typeahead search and autocomplete
- Japanese optimization: High-precision Japanese search with Lindera morphological analyzer
- Developer-friendly: Intuitive API and rich client libraries
- Open source: Free for commercial use
- Active development: Continuous feature improvements and community support
Cons
- Relatively new technology: Less proven track record compared to Elasticsearch
- Enterprise feature limitations: Advanced clustering features are limited
- Plugin ecosystem: Not as rich plugin ecosystem as Elasticsearch
- Distributed processing limitations: Challenges in large-scale distributed environments
- Complex analysis features: Not as advanced as Elasticsearch's aggregation features
- Backup tools: Limited enterprise-level backup functionality
Key Links
Code Examples
Docker Execution
# Start MeiliSearch Docker container
docker run -d \
--name meilisearch \
-p 7700:7700 \
-e MEILI_ENV=development \
-v $(pwd)/meili_data:/meili_data \
getmeili/meilisearch:v1.3.0
# Production startup with master key
docker run -d \
--name meilisearch \
-p 7700:7700 \
-e MEILI_ENV=production \
-e MEILI_MASTER_KEY=your-master-key-here \
-v $(pwd)/meili_data:/meili_data \
getmeili/meilisearch:v1.3.0
# Check startup
curl http://localhost:7700/health
Index Creation and Document Addition
# Create index
curl -X POST 'http://localhost:7700/indexes' \
-H 'Content-Type: application/json' \
--data-binary '{
"uid": "movies",
"primaryKey": "id"
}'
# Bulk add multiple documents
curl -X POST 'http://localhost:7700/indexes/movies/documents' \
-H 'Content-Type: application/json' \
--data-binary '[
{
"id": 1,
"title": "Spider-Man",
"genre": ["Action", "Adventure"],
"director": "Sam Raimi",
"release_year": 2002,
"rating": 7.3,
"overview": "The story of ordinary high school student Peter Parker transforming into Spider-Man"
},
{
"id": 2,
"title": "The Avengers",
"genre": ["Action", "Sci-Fi"],
"director": "Joss Whedon",
"release_year": 2012,
"rating": 8.0,
"overview": "Epic story of Earths mightiest heroes saving the world"
}
]'
# Add single document
curl -X POST 'http://localhost:7700/indexes/movies/documents' \
-H 'Content-Type: application/json' \
--data-binary '{
"id": 3,
"title": "Your Name",
"genre": ["Animation", "Romance"],
"director": "Makoto Shinkai",
"release_year": 2016,
"rating": 8.2,
"overview": "Beautiful animation depicting love transcending space and time"
}'
Basic Search
# Simple search
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "Spider"
}'
# Typo tolerance search (searching "Spider" with "Spide")
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "Spide"
}'
# Limit and offset
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "Action",
"limit": 5,
"offset": 0
}'
# Return only specific attributes
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "Avengers",
"attributesToRetrieve": ["title", "director", "release_year"]
}'
Filtering Search
# Set filterable attributes
curl -X PATCH 'http://localhost:7700/indexes/movies/settings' \
-H 'Content-Type: application/json' \
--data-binary '{
"filterableAttributes": ["genre", "release_year", "rating", "director"]
}'
# Filter by genre
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"filter": "genre = Action"
}'
# Filter with multiple conditions
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"filter": "release_year > 2010 AND rating >= 8.0"
}'
# OR condition filtering
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"filter": "director = \"Makoto Shinkai\" OR director = \"Sam Raimi\""
}'
# Search in array elements
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"filter": "genre IN [Animation, Sci-Fi]"
}'
Sort Functionality
# Set sortable attributes
curl -X PATCH 'http://localhost:7700/indexes/movies/settings' \
-H 'Content-Type: application/json' \
--data-binary '{
"sortableAttributes": ["release_year", "rating", "title"]
}'
# Sort by rating (descending)
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"sort": ["rating:desc"]
}'
# Sort with multiple conditions
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"sort": ["release_year:desc", "rating:desc"]
}'
# Combination of search query and sort
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "Action",
"filter": "release_year >= 2000",
"sort": ["rating:desc"]
}'
Highlight Functionality
# Set highlight attributes
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "Spider-Man",
"attributesToHighlight": ["title", "overview"],
"highlightPreTag": "<mark>",
"highlightPostTag": "</mark>"
}'
# Highlight all attributes
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "hero",
"attributesToHighlight": ["*"]
}'
Faceted Search
# Get facet distribution
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"facets": ["genre", "director"]
}'
# Limit maximum facet values
curl -X POST 'http://localhost:7700/indexes/movies/search' \
-H 'Content-Type: application/json' \
--data-binary '{
"q": "",
"facets": ["genre"],
"maxValuesPerFacet": 10
}'
Typo Tolerance Settings
# Check typo tolerance settings
curl -X GET 'http://localhost:7700/indexes/movies/settings/typo-tolerance'
# Disable typo tolerance
curl -X PATCH 'http://localhost:7700/indexes/movies/settings/typo-tolerance' \
-H 'Content-Type: application/json' \
--data-binary '{
"enabled": false
}'
# Set minimum character count
curl -X PATCH 'http://localhost:7700/indexes/movies/settings/typo-tolerance' \
-H 'Content-Type: application/json' \
--data-binary '{
"minWordSizeForTypos": {
"oneTypo": 4,
"twoTypos": 10
}
}'
# Disable typo tolerance for specific words
curl -X PATCH 'http://localhost:7700/indexes/movies/settings/typo-tolerance' \
-H 'Content-Type: application/json' \
--data-binary '{
"disableOnWords": ["Avengers", "Spider-Man"]
}'
# Disable typo tolerance for specific attributes
curl -X PATCH 'http://localhost:7700/indexes/movies/settings/typo-tolerance' \
-H 'Content-Type: application/json' \
--data-binary '{
"disableOnAttributes": ["director"]
}'
JavaScript Client
// MeiliSearch client initialization
import { MeiliSearch } from 'meilisearch'
const client = new MeiliSearch({
host: 'http://localhost:7700',
apiKey: 'your-api-key' // Required in production
})
// Get index
const index = client.index('movies')
// Add documents
const documents = [
{
id: 1,
title: 'Your Name',
genre: ['Animation', 'Romance'],
director: 'Makoto Shinkai',
release_year: 2016
}
]
await index.addDocuments(documents)
// Execute search
const searchResults = await index.search('Your Name', {
attributesToHighlight: ['title'],
filter: 'release_year > 2015',
sort: ['release_year:desc'],
limit: 10
})
console.log(searchResults.hits)
// Typo-tolerant search
const typoResults = await index.search('Yor Nam') // Typo of "Your Name"
console.log(typoResults.hits)
// Faceted search
const facetResults = await index.search('', {
facets: ['genre', 'director']
})
console.log(facetResults.facetDistribution)
Python Client
# MeiliSearch client initialization
import meilisearch
client = meilisearch.Client('http://localhost:7700', 'your-api-key')
index = client.index('movies')
# Add documents
documents = [
{
'id': 1,
'title': 'The Avengers',
'genre': ['Action', 'Sci-Fi'],
'director': 'Joss Whedon',
'release_year': 2012,
'rating': 8.0
}
]
index.add_documents(documents)
# Execute search
search_results = index.search('Avengers', {
'filter': 'rating >= 8.0',
'attributesToHighlight': ['title', 'overview'],
'sort': ['rating:desc']
})
print(search_results['hits'])
# Update settings
index.update_filterable_attributes(['genre', 'rating', 'release_year'])
index.update_sortable_attributes(['rating', 'release_year'])
# Typo tolerance settings
index.update_typo_tolerance({
'minWordSizeForTypos': {
'oneTypo': 4,
'twoTypos': 10
},
'disableOnAttributes': ['director']
})
Go Client
package main
import (
"fmt"
"github.com/meilisearch/meilisearch-go"
)
func main() {
// Client initialization
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://localhost:7700",
APIKey: "your-api-key",
})
// Get index
index := client.Index("movies")
// Execute search
searchRes, err := index.Search("Spider-Man", &meilisearch.SearchRequest{
Filter: "release_year > 2000",
Sort: []string{"rating:desc"},
Limit: 10,
AttributesToHighlight: []string{"title", "overview"},
})
if err != nil {
panic(err)
}
fmt.Printf("Found %d results\n", len(searchRes.Hits))
// Update typo tolerance settings
_, err = index.UpdateTypoTolerance(&meilisearch.TypoTolerance{
MinWordSizeForTypos: meilisearch.MinWordSizeForTypos{
OneTypo: 4,
TwoTypos: 10,
},
DisableOnWords: []string{"Avengers"},
})
if err != nil {
panic(err)
}
}
Performance Optimization
# Index optimization (recommended for regular execution)
curl -X POST 'http://localhost:7700/indexes/movies/documents' \
-H 'Content-Type: application/json' \
--data-binary '[]' # Optimize index with empty array
# Batch settings update
curl -X PATCH 'http://localhost:7700/indexes/movies/settings' \
-H 'Content-Type: application/json' \
--data-binary '{
"filterableAttributes": ["genre", "release_year", "rating"],
"sortableAttributes": ["release_year", "rating"],
"searchableAttributes": ["title", "overview", "director"],
"displayedAttributes": ["title", "director", "release_year", "rating"],
"rankingRules": [
"words",
"typo",
"proximity",
"attribute",
"sort",
"exactness",
"rating:desc"
]
}'