2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Elasticsearchについての基礎知識

2
Posted at

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(マッピング) フィールドの型定義 titletext型など

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: エラーが出たときは?

  1. ログを確認
  2. Kibana Dev Toolsでクエリ実行
  3. インデックス状態確認
  4. 必要に応じて再マッピングや再インデックス化

参考資料

まとめ

Elasticsearchは:

  • 転置インデックスで高速な全文検索を実現
  • シャード構成でスケールしやすい
  • Kuromoji/N-gramで日本語にも対応
  • バルク処理と適切なマッピングがパフォーマンスの鍵

MySQLと併用しながら、「検索に強いレイヤー」として使うのがベストプラクティスである。


プロダクトに向き合い、ユーザーとつながる開発を。
ネットネイティブでは、そんなエンジニアを歓迎しています
https://www.wantedly.com/companies/mdpr

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?