MeiliSearch

高速で関連性の高い検索エンジン。インスタント検索、タイポ耐性、マルチ言語対応。セットアップが簡単で開発者フレンドリー。

Search EngineOpen SourceFast SearchReal-timeMulti-languageTypo ToleranceRESTfulAI Search

サーバー

MeiliSearch

概要

MeiliSearchは、Rustで構築された高速でユーザーフレンドリーなオープンソースの検索エンジンです。50ミリ秒以下での高速検索、AIパワードのハイブリッド検索、タイポ許容機能を特徴とし、開発者とエンドユーザーの両方に優れた検索体験を提供します。セルフホスト型ソリューションとして、企業はデータを完全にコントロールできます。

詳細

MeiliSearch 2024版では、ベクトル検索とキーワード検索を融合したAIパワードのハイブリッド検索、マルチモーダル検索(画像、動画、音声)、マルチインデックス検索など、次世代の検索機能を提供しています。Rustによる高性能アーキテクチャにより、従来のElasticsearchが500ミリ秒以上かかる検索を50ミリ秒で実現し、開発者向けの直感的なAPIとセルフホスト可能な柔軟な展開オプションが特徴です。

主要機能

  • AI駆動検索: セマンティック検索とフルテキスト検索を組み合わせたハイブリッド検索
  • 高速性能: 50ミリ秒以下での検索応答時間
  • タイポ許容: スペルミスがあっても関連性の高い結果を返却
  • 多言語対応: 包括的な多言語サポートと言語固有の最適化
  • シンプルAPI: 開発者フレンドリーなRESTful API
  • セルフホスト: 完全なデータコントロールと柔軟な展開

メリット・デメリット

メリット

  • セットアップが簡単で、開発者フレンドリーなAPIによる高い開発効率
  • ElasticsearchやAlgoliaと比較して大幅に高速な検索性能
  • オープンソースによるコスト削減と技術的自由度
  • 豊富な検索機能(ファセット、フィルタリング、ジオサーチ)をシンプルに利用可能
  • コミュニティによる活発な開発とサポート
  • 小中規模ビジネスに適した柔軟な価格体系

デメリット

  • Elasticsearch程の大規模データ処理能力はない
  • プラグインエコシステムが他の成熟した検索エンジンより小さい
  • 複雑な分析クエリにおいてElasticsearchに劣る場合がある
  • 大規模エンタープライズ向け機能が限定的
  • 本格的な商用サポートオプションが限られている
  • 一部の高度なカスタマイゼーション要件では制約がある場合がある

参考ページ

書き方の例

セットアップとインストール

# Dockerでの実行
docker run -it --rm \
  -p 7700:7700 \
  -v $(pwd)/meili_data:/meili_data \
  getmeili/meilisearch:v1.5

# macOSでのインストール(Homebrew)
brew install meilisearch

# Linuxでのバイナリインストール
curl -L https://install.meilisearch.com | sh

# 開発環境での起動
./meilisearch --master-key=yourMasterKey --db-path ./meili_data

# Docker Composeでの設定
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
  meilisearch:
    image: getmeili/meilisearch:v1.5
    ports:
      - "7700:7700"
    volumes:
      - ./meili_data:/meili_data
    environment:
      - MEILI_MASTER_KEY=yourSecureMasterKey
      - MEILI_DB_PATH=/meili_data
      - MEILI_HTTP_ADDR=0.0.0.0:7700
      - MEILI_LOG_LEVEL=INFO
    restart: unless-stopped
EOF

docker-compose up -d

インデックス作成とドキュメント追加

# インデックス作成
curl -X POST 'http://localhost:7700/indexes' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "uid": "movies",
    "primaryKey": "id"
  }'

# 単一ドキュメント追加
curl -X POST 'http://localhost:7700/indexes/movies/documents' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "id": 1,
    "title": "千と千尋の神隠し",
    "overview": "宮崎駿監督による日本のアニメーション映画",
    "genre": ["アニメーション", "ファミリー", "ファンタジー"],
    "release_date": "2001-07-20",
    "duration": 125,
    "rating": 9.2,
    "director": "宮崎駿",
    "studio": "スタジオジブリ"
  }'

# 複数ドキュメントの一括追加
curl -X POST 'http://localhost:7700/indexes/movies/documents' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '[
    {
      "id": 2,
      "title": "君の名は。",
      "overview": "新海誠監督による青春ファンタジーアニメ",
      "genre": ["アニメーション", "ロマンス", "ドラマ"],
      "release_date": "2016-08-26",
      "duration": 106,
      "rating": 8.4,
      "director": "新海誠",
      "studio": "CoMix Wave Films"
    },
    {
      "id": 3,
      "title": "鬼滅の刃 無限列車編",
      "overview": "吾峠呼世晴原作による人気アニメの映画版",
      "genre": ["アニメーション", "アクション", "歴史"],
      "release_date": "2020-10-16",
      "duration": 117,
      "rating": 8.7,
      "director": "外崎春雄",
      "studio": "ufotable"
    }
  ]'

# CSVファイルからの一括インポート
curl -X POST 'http://localhost:7700/indexes/movies/documents' \
  -H 'Content-Type: text/csv' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary @movies.csv

# ドキュメント更新
curl -X PUT 'http://localhost:7700/indexes/movies/documents' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "id": 1,
    "rating": 9.3
  }'

検索クエリの実装

# 基本的な検索
curl -X POST 'http://localhost:7700/indexes/movies/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourSearchKey' \
  --data-binary '{
    "q": "千と千尋"
  }'

# 詳細検索オプション
curl -X POST 'http://localhost:7700/indexes/movies/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourSearchKey' \
  --data-binary '{
    "q": "アニメ",
    "attributesToRetrieve": ["id", "title", "overview", "rating"],
    "attributesToHighlight": ["title", "overview"],
    "attributesToCrop": ["overview"],
    "cropLength": 10,
    "filter": "genre = \"アニメーション\" AND rating > 8.0",
    "sort": ["rating:desc", "release_date:desc"],
    "facets": ["genre", "director", "studio"],
    "limit": 20,
    "offset": 0
  }'

# フィルタリング検索
curl -X POST 'http://localhost:7700/indexes/movies/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourSearchKey' \
  --data-binary '{
    "q": "",
    "filter": "director = \"宮崎駿\" OR director = \"新海誠\"",
    "facets": ["director", "studio", "genre"]
  }'

# ジオサーチ(位置情報検索)
curl -X POST 'http://localhost:7700/indexes/theaters/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourSearchKey' \
  --data-binary '{
    "q": "映画館",
    "filter": "_geoRadius(35.6762, 139.6503, 5000)",
    "sort": ["_geoPoint(35.6762, 139.6503):asc"]
  }'

# タイポ許容の設定
curl -X POST 'http://localhost:7700/indexes/movies/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourSearchKey' \
  --data-binary '{
    "q": "せんとちひろ",
    "matchingStrategy": "all"
  }'

スキーマ設計とインデックス設定

# 検索可能属性の設定
curl -X PUT 'http://localhost:7700/indexes/movies/settings/searchable-attributes' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '[
    "title",
    "overview", 
    "director",
    "genre"
  ]'

# フィルタリング可能属性の設定
curl -X PUT 'http://localhost:7700/indexes/movies/settings/filterable-attributes' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '[
    "genre",
    "director",
    "studio",
    "rating",
    "release_date",
    "_geo"
  ]'

# ソート可能属性の設定
curl -X PUT 'http://localhost:7700/indexes/movies/settings/sortable-attributes' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '[
    "rating",
    "release_date",
    "duration",
    "title"
  ]'

# ランキングルールの設定
curl -X PUT 'http://localhost:7700/indexes/movies/settings/ranking-rules' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '[
    "words",
    "typo",
    "proximity",
    "attribute",
    "sort",
    "exactness",
    "rating:desc"
  ]'

# シノニムの設定
curl -X PUT 'http://localhost:7700/indexes/movies/settings/synonyms' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "アニメ": ["アニメーション", "動画"],
    "映画": ["フィルム", "ムービー"],
    "ジブリ": ["スタジオジブリ", "宮崎駿"]
  }'

# タイポ許容の設定
curl -X PUT 'http://localhost:7700/indexes/movies/settings/typo-tolerance' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "enabled": true,
    "minWordSizeForTypos": {
      "oneTypo": 5,
      "twoTypos": 9
    },
    "disableOnWords": ["ジブリ", "千尋"],
    "disableOnAttributes": ["director"]
  }'

パフォーマンス最適化

# インデックス統計の確認
curl -X GET 'http://localhost:7700/indexes/movies/stats' \
  -H 'Authorization: Bearer yourMasterKey'

# タスクの監視
curl -X GET 'http://localhost:7700/tasks' \
  -H 'Authorization: Bearer yourMasterKey'

# インデックス設定の最適化
curl -X PUT 'http://localhost:7700/indexes/movies/settings' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "pagination": {
      "maxTotalHits": 10000
    },
    "faceting": {
      "maxValuesPerFacet": 1000
    },
    "searchCutoffMs": 1500
  }'

# メモリ使用量の設定(起動時)
export MEILI_MAX_INDEXING_MEMORY="2Gb"
export MEILI_MAX_INDEXING_THREADS=4
./meilisearch

# 本番環境での設定
cat > meili.env << 'EOF'
MEILI_DB_PATH=/var/lib/meilisearch/data
MEILI_HTTP_ADDR=0.0.0.0:7700
MEILI_MASTER_KEY=yourProductionMasterKey
MEILI_ENV=production
MEILI_LOG_LEVEL=WARN
MEILI_MAX_INDEXING_MEMORY=4Gb
MEILI_MAX_INDEXING_THREADS=4
MEILI_EXPERIMENTAL_SEARCH_QUEUE_SIZE=2000
EOF

SDKとフレームワーク連携

// JavaScript/Node.js SDK
import { MeiliSearch } from 'meilisearch'

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

// インデックス作成
const index = await client.createIndex('movies', { primaryKey: 'id' })

// ドキュメント追加
const documents = [
  {
    id: 1,
    title: '千と千尋の神隠し',
    overview: '宮崎駿監督による日本のアニメーション映画',
    genre: ['アニメーション', 'ファミリー', 'ファンタジー'],
    rating: 9.2
  }
]

let task = await index.addDocuments(documents)
await index.waitForTask(task.taskUid)

// 検索実行
const searchResults = await index.search('千と千尋', {
  attributesToHighlight: ['title', 'overview'],
  filter: 'rating > 8.0',
  sort: ['rating:desc'],
  limit: 10
})

console.log(searchResults.hits)

// 高度な検索設定
await index.updateSettings({
  searchableAttributes: ['title', 'overview', 'director'],
  filterableAttributes: ['genre', 'rating', 'release_date'],
  sortableAttributes: ['rating', 'release_date'],
  synonyms: {
    'アニメ': ['アニメーション', '動画'],
    'ジブリ': ['スタジオジブリ', '宮崎駿']
  }
})
# Python SDK
import meilisearch

client = meilisearch.Client('http://localhost:7700', 'yourMasterKey')

# インデックス作成
index = client.create_index('movies', {'primaryKey': 'id'})

# ドキュメント追加
documents = [
    {
        'id': 1,
        'title': '千と千尋の神隠し',
        'overview': '宮崎駿監督による日本のアニメーション映画',
        'genre': ['アニメーション', 'ファミリー', 'ファンタジー'],
        'rating': 9.2
    }
]

task = index.add_documents(documents)
index.wait_for_task(task['taskUid'])

# 検索実行
search_results = index.search('千と千尋', {
    'attributesToHighlight': ['title', 'overview'],
    'filter': 'rating > 8.0',
    'sort': ['rating:desc'],
    'limit': 10
})

print(search_results['hits'])

# 設定更新
index.update_settings({
    'searchableAttributes': ['title', 'overview', 'director'],
    'filterableAttributes': ['genre', 'rating', 'release_date'],
    'sortableAttributes': ['rating', 'release_date'],
    'synonyms': {
        'アニメ': ['アニメーション', '動画'],
        'ジブリ': ['スタジオジブリ', '宮崎駿']
    }
})

セキュリティとAPIキー管理

# APIキーの作成
curl -X POST 'http://localhost:7700/keys' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "description": "Search only key for production",
    "actions": ["search"],
    "indexes": ["movies"],
    "expiresAt": "2024-12-31T23:59:59Z"
  }'

# 読み取り専用キーの作成
curl -X POST 'http://localhost:7700/keys' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "description": "Read-only key for analytics",
    "actions": ["search", "documents.get", "indexes.get", "stats.get"],
    "indexes": ["*"],
    "expiresAt": null
  }'

# 管理用キーの作成
curl -X POST 'http://localhost:7700/keys' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer yourMasterKey' \
  --data-binary '{
    "description": "Admin key for index management",
    "actions": ["*"],
    "indexes": ["movies", "users"],
    "expiresAt": "2025-06-30T23:59:59Z"
  }'

# APIキー一覧の確認
curl -X GET 'http://localhost:7700/keys' \
  -H 'Authorization: Bearer yourMasterKey'

# SSL/TLS設定(Nginx使用)
cat > /etc/nginx/sites-available/meilisearch << 'EOF'
server {
    listen 443 ssl http2;
    server_name search.example.com;
    
    ssl_certificate /path/to/ssl/certificate.crt;
    ssl_certificate_key /path/to/ssl/private.key;
    
    location / {
        proxy_pass http://localhost:7700;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
EOF

MeiliSearchは、高速性とシンプルさを重視した現代的な検索エンジンで、特に日本語を含む多言語コンテンツの検索で優れた性能を発揮します。オープンソースの利点を活かしながら、商用グレードの検索機能を低コストで実現できる優れた選択肢です。