1. Elasticsearchとは
Elasticsearch は、分散環境で大容量データを高速に検索・分析できる分散型全文検索エンジンである。
主な用途
- 全文検索(記事・ユーザー・タグなど)
- ログ分析(Kibanaで可視化)
- 集計・統計分析
- リアルタイム検索
名前の由来
Elastic(弾力性)+ Search(検索)=「柔軟にスケールする検索エンジン」
なぜ全文検索が重要か
従来のRDBでは「完全一致」や「前方一致」検索が主で、LIKE '%結婚%' のような検索は全件スキャンが必要となる。
Elasticsearchは転置インデックスを用いて、「どの単語がどの文書に含まれるか」を記録することで、高速な全文検索を実現している。
例:
-- RDB(遅い)
SELECT * FROM articles WHERE title LIKE '%結婚%';
-- Elasticsearch(高速)
{
"query": {
"match": { "title": "結婚" }
}
}
2. RDBとの違い
| 観点 | RDB | Elasticsearch |
|---|---|---|
| データ構造 | テーブル・カラム(固定スキーマ) | ドキュメント型(JSON) |
| クエリ言語 | SQL | Query DSL |
| 検索速度 | LIKE文は遅い | 転置インデックスで高速 |
| スケール | 垂直スケーリング中心 | 水平スケーリング対応 |
| 柔軟性 | 型定義が厳密 | 動的マッピングで柔軟 |
Elasticsearchは「スキーマレス」ではなく、実際は柔軟なスキーマ定義(マッピング)を持つ。
3. 基本用語とアーキテクチャ
用語一覧
| 用語 | 意味 | 例 |
|---|---|---|
| Index(インデックス) | データ集合。RDBのテーブルに相当 |
articles, users
|
| Document(ドキュメント) | 1件のデータ。JSON形式 | 1記事・1ユーザー |
| Field(フィールド) | ドキュメントの属性 |
title, tags
|
| Mapping(マッピング) | フィールドの型定義 |
title → text型など |
IndexとDocumentの関係
Index: articles
├─ Document 1
│ ├─ title: "女優〇〇が電撃結婚"
│ └─ tags: ["電撃", "結婚"]
└─ Document 2
├─ title: "ミスコン2025開催"
└─ tags: ["イベント", "ミスコン2025"]
Mappingの例
{
"settings": {
"index": {
"number_of_shards": 2,
"number_of_replicas": 1
}
},
"mappings": {
"properties": {
"title": {
"type": "keyword",
"fields": {
"text": {
"type": "text",
"analyzer": "ja_kuromoji_index_analyzer"
},
"ngram": {
"type": "text",
"analyzer": "ja_ngram_index_analyzer"
}
}
}
}
}
}
シャードとレプリカ
- シャード(Shard):インデックスを分割保存し、並列検索を実現
- レプリカ(Replica):シャードのコピー。冗長化と読み取り分散に利用
構成例:
articles
├─ shard_1 (primary)
│ └─ replica_1
└─ shard_2 (primary)
└─ replica_2
4. コード例:Elasticsearchの使い方
接続設定
func newElasticSearch(cfg *config.ElasticSearch) (*search.Elastic, error) {
return search.NewElastic(
elastic.SetURL(cfg.Endpoint),
elastic.SetSniff(false),
elastic.SetHealthcheck(false),
elastic.SetBasicAuth(cfg.User, cfg.Password),
)
}
ポイント:
-
SetSniff(false):自動ノード検出OFF -
SetHealthcheck(false):起動時のヘルスチェック無効化 - 本番環境ではBasic認証を利用
ドキュメント登録(バルク処理)
bulk := es.Bulk()
req := elastic.NewBulkUpdateRequest().
Index("articles").
Id(strconv.Itoa(article.ID)).
Doc(article).
Upsert(article)
bulk.Add(req)
res, err := bulk.Do(ctx)
ポイント
- バルク処理で高速登録
-
Upsertにより冪等性を確保(同一操作の繰り返しでも結果が一定)
検索クエリの例
svc := es.Search("users").
Timeout("10s").
Query(
elastic.NewBoolQuery().Must(
elastic.NewTermQuery("authority", "user"),
elastic.NewBoolQuery().Should(
elastic.NewMatchQuery("nickname", qk).Operator("and"),
elastic.NewMatchQuery("comment", qk).Operator("and"),
),
),
).
SortBy(
elastic.NewScoreSort().Desc(),
elastic.NewFieldSort("id").Desc(),
)
res, err := svc.Do(ctx)
BoolQuery はSQLのWHERE条件に相当:
-
Must→ AND -
Should→ OR -
MustNot→ NOT
5. アナライザー(Analyzer)
アナライザーとは「文字列を検索可能な単位に分割する仕組み」。
| 種類 | 処理内容 | 出力例(入力: "電撃結婚") |
|---|---|---|
| keyword | 完全一致 | ["電撃結婚"] |
| Kuromoji | 形態素解析 | ["電撃", "結婚"] |
| N-gram | 部分一致用分割 | ["電撃", "撃結", "結婚"] |
→ Kuromojiは意味単位で分割、N-gramは連続文字列単位で分割。
6. よくあるエラーと対処法
| エラー種別 | 原因 | 対処 |
|---|---|---|
| Connection Error | ESサーバー停止、URLや認証誤り |
curl http://localhost:9200で接続確認 |
| Timeout Error | クエリが重い、インデックス巨大 | クエリ条件を絞る・TerminateAfter利用 |
| Bulk Error | マッピング不一致、ドキュメント肥大 | 定義確認・フィールドサイズ削減 |
Timeout例
svc := es.Search("articles").
Timeout("10s").
Query(BoolQuery().Must(
TermQuery("status", 1),
RangeQuery("published_at").Gte("2024-01-01"),
))
7. 運用・パフォーマンス最適化
設計の基本
- 適切なシャード数とレプリカ設定(例:2シャード1レプリカ)
- 日本語検索は Kuromoji + N-gram を併用
- タイムアウト設定を明示(
Timeout("10s")) - フェッチ対象フィールドを限定
バルク処理の重要性
bulk := es.Bulk()
for _, a := range articles {
bulk.Add(elastic.NewBulkIndexRequest().Index("articles").Doc(a))
}
bulk.Do(ctx)
1件ずつ登録 vs バルク登録
| 方法 | リクエスト回数 | 所要時間 |
|---|---|---|
| 個別登録 | 1000回 | 約100秒 |
| バルク登録 | 1回 | 約1秒 |
→ 約100倍高速化できるケースもある。
タイムアウト処理例
const EsTimeout = "10s"
res, err := svc.Do(ctx)
if err != nil {
if elastic.IsContextErr(err) {
return failure.Translate(err, enum.GatewayTimeout)
}
return failure.Wrap(err)
}
Contextエラーを特別扱いし、APIとして適切に応答する。
8. Q&A・学習リソース
Q: MySQLとElasticsearchの使い分けは?
| 処理 | 適用先 |
|---|---|
| 全文検索・リアルタイム検索 | Elasticsearch |
| トランザクション・JOIN・集計 | MySQL |
Q: チューニングのコツは?
- シャード数をデータ量に合わせる
- フィールドを最小限に制限
- クエリを最適化(BoolQueryの構造を見直す)
Q: エラーが出たときは?
- ログを確認
- Kibana Dev Toolsでクエリ実行
- インデックス状態確認
- 必要に応じて再マッピングや再インデックス化
参考資料
まとめ
Elasticsearchは:
- 転置インデックスで高速な全文検索を実現
- シャード構成でスケールしやすい
- Kuromoji/N-gramで日本語にも対応
- バルク処理と適切なマッピングがパフォーマンスの鍵
MySQLと併用しながら、「検索に強いレイヤー」として使うのがベストプラクティスである。
プロダクトに向き合い、ユーザーとつながる開発を。
ネットネイティブでは、そんなエンジニアを歓迎しています
https://www.wantedly.com/companies/mdpr