【メモ】Elasticsearchのインデックス設計:RDBとの考え方の違い
最近、Elasticsearch(以下、ES)を触る機会があり、インデックス設計について学んだことを自分用のメモとして残しておきます。
RDBでは「データを重複させない」が基本
これまでRDB(リレーショナルデータベース)を中心に扱ってきたので、最初にESの設計を見たときに少し違和感がありました。
RDBでは、同じデータを複数の場所に持たないように、テーブルを分割して正規化するのが基本です。
例えば、ユーザーと注文の情報がある場合、
users
----------------
id | name
1 | 田中
2 | 山田
orders
----------------
id | user_id | product
1 | 1 | PC
2 | 1 | キーボード
3 | 2 | マウス
のように、ordersにはユーザーの名前を直接持たせず、user_idを使ってusersと紐付けます。これによって、「田中」というデータを何度も保存する必要がなくなります。
つまりRDBでは、「データをできるだけ正規化し、重複を減らして綺麗に管理する」という考え方が重要になります。
Elasticsearchでは考え方が少し違う
一方、ESでは必ずしもこの考え方をそのまま適用しません。
ESは、RDBのようにデータを綺麗に管理することよりも、検索を高速に行うことを重要視します。
そのため、検索時に複雑なJOINを行う必要がないように、必要な情報を1つのドキュメントにまとめて持たせる、という設計を取ることがあります。
例えば、商品を検索する場合、
{
"product_id": 1,
"product_name": "キーボード",
"category": "PC周辺機器",
"brand": "〇〇",
"seller": {
"id": 10,
"name": "〇〇ショップ"
}
}
のように、RDBなら別テーブルに分けるような情報まで、検索に必要であれば1つのドキュメントに含めます。
その結果、同じショップ名やカテゴリ名などが複数のドキュメントに存在することもあります。
つまり、「多少データが重複しても、検索時に必要な情報を1つのドキュメントにまとめる」という考え方です。
なぜ重複させるのか?
理由の一つは、検索時の処理をシンプルかつ高速にするためです。
RDBでは、
orders → users → products
のように複数のテーブルをJOINして必要なデータを取得することがあります。
一方、ESでは検索に必要な情報をあらかじめ1つのドキュメントに持たせておけば、検索時に複数のテーブルをJOINする必要がありません。
「検索するために必要な形に、あらかじめデータを加工しておく」というイメージです。
データの綺麗さと検索パフォーマンス
ここで面白いと思ったのが、「データを綺麗に管理すること」と「検索パフォーマンス」は、必ずしも両立しないということです。
RDBでは、
データの重複を減らす → 正規化する → 綺麗に管理する
という方向に設計することが多いです。
一方、ESでは、
検索に必要なデータをまとめる → ある程度の重複を許容する → 検索しやすい形にする
という設計を取ることがあります。
つまり、「データを綺麗に保存する」のではなく、「検索しやすい形で保存する」という発想が重要なのだと学びました。
ただし、何でも重複させればいいわけではない
今回の学びから、「ESではデータを重複させまくればいい」と考えてしまいそうですが、そこは注意が必要だと思いました。
データを複製すると、当然ながら更新時の問題が発生します。
例えば、ショップ名を100万件のドキュメントにコピーしていた場合、ショップ名が変更されたときに、それらのドキュメントを更新する必要があります。
そのため、以下のような点を考えた上で、インデックスの設計を行う必要があります。
- どのデータをESに持たせるのか
- どこまで非正規化するのか
- 更新頻度はどのくらいなのか
- 検索時にどのような情報が必要なのか
今回の学び
今回ESのインデックス設計について学んで、一番印象に残ったのは、「RDBとESでは『良いデータ設計』の考え方が違う」ということです。
RDBではデータの整合性や重複の排除を意識する一方で、ESでは検索要件を起点に、必要に応じてデータを非正規化して持ちます。
「データをどう保存したいか」ではなく、「どう検索したいか」から逆算してインデックスを設計する。
これが今回の一番大きな学びでした。
まだESを触り始めたばかりなので、今後実際にインデックス設計をしていく中で、今回の理解がどう変わっていくのかも記録していきたいと思います。