OpenSearch vs PostgreSQL:検索エンジンの選び方
IT全般情報 16 min read

OpenSearch vs PostgreSQL:検索エンジンの選び方

avatar-m-1

karrinn

著者

「商品検索が遅い」「LIKE検索だと全然ヒットしない」—こんな悩みを抱えていませんか?
PostgreSQLでの検索に限界を感じてOpenSearchの導入を検討している方に向けて、両者の仕組みの違いと使い分けを解説します。

KEY TAKEAWAYS

この記事でわかること

  • OpenSearchが高速な理由(転置インデックスの仕組み)
  • PostgreSQLのB-Treeインデックスとの根本的な違い
  • どちらを選ぶべきか判断するための具体的な基準
  • PostgreSQL拡張で全文検索を実現する代替案

OpenSearchとは

WHAT IS

OpenSearch

Apache Luceneをベースにした全文検索エンジン。2021年にElasticsearchからフォークされたOSSで、AWS主導でLinux Foundation傘下のプロジェクトとして開発が続けられています。

WHY FAST

転置インデックス

「単語 → 文書」の逆引き辞書を事前に構築。検索時は辞書を引くだけなので、100万件でも数十ミリ秒で結果が返ります。PostgreSQLのLIKE検索とは根本的に異なるアプローチです。

Source: OpenSearch Documentation

転置インデックスの仕組み

OpenSearchが高速な最大の理由は「転置インデックス」にあります。本の巻末にある索引と同じ原理で、検索を劇的に高速化しています。

PostgreSQLのLIKE検索(フルスキャン)

通常のデータベースでLIKE '%ラーメン%'を実行すると、100万件のレコードを1件ずつ確認していきます。 これは本を1ページ目から全部読んで「ラーメン」という単語を探すようなものです。

  • 計算量: O(n × m) ※n=件数, m=文字長
  • 100万件で数秒〜数十秒かかることも
  • インデックスが効かない(前方に%があるため)

OpenSearchの転置インデックス(辞書引き)

OpenSearchは事前に「単語 → 文書」の辞書を作っておきます。 検索時は辞書を引くだけなので、データ量に関係なく一定時間で結果が返ります。

  • 計算量: O(1) 〜 O(log n)
  • 100万件でも数十ミリ秒
  • 複数単語のAND/OR検索も高速

Source: Alibaba Cloud - Introduction to inverted indexes

B-Treeインデックス vs 転置インデックス

「PostgreSQLにもインデックスあるのに、なぜ全文検索が遅いの?」と疑問に思う方も多いでしょう。実は解いている問題が根本的に違います。

観点PostgreSQL B-TreeOpenSearch 転置インデックス
目的値・範囲の高速検索単語→文書の逆引き
構造ツリー構造辞書(ハッシュ的)
= 'Sony'O(log n) 高速O(1) 高速
LIKE '%ワイヤレス%'インデックス効かないO(1) 高速
BETWEEN 1000 AND 5000O(log n) 高速フィルタで対応可
あいまい検索別途pg_trgm等が必要標準で対応(fuzziness)
形態素解析なしあり(「走った」→「走る」)

B-Treeは「この値どこ?」を木構造で探す。転置インデックスは「この単語どの文書?」を辞書で引く。根本的に解いている問題が違います。

なぜB-Treeは中間一致が苦手なのか

B-Treeは「先頭から順に並んでいる」前提で設計されています。LIKE 'Sony%'(前方一致)なら「S」で始まる範囲を一気に絞れますが、LIKE '%ワイヤレス%'(中間一致)だと「どこから探せばいいかわからない」ため、結局全件スキャンになります。

OpenSearchが高速なその他の理由

転置インデックス以外にも、OpenSearchには高速化のための仕組みがいくつかあります。

トークナイズ(形態素解析)

日本語の文章を単語に分解し、検索可能にします。

  • 「東京で人気のラーメン店」→ [東京, 人気, ラーメン, 店]
  • ストップワード(で、の、は等)は除去
  • Kuromoji等のアナライザーで日本語対応

セグメントとイミュータブル設計

データを「セグメント」単位で管理し、一度書いたら変更しない設計です。

  • ロック不要で並列読み取りが超高速
  • OSのページキャッシュに乗りやすい
  • トレードオフ: 更新はRDBほど得意ではない

シャーディング(分散処理)

データを複数のシャードに分割し、並列で検索します。

  • 100万件を5分割 → 5並列で検索
  • 理論上5倍速い
  • レプリカで可用性も確保

メモリ活用

できるだけデータをメモリに載せて高速化しています。これがOpenSearchが高コストな理由でもあります。

  • JVM Heap: フィールドデータ、クエリキャッシュ
  • OS Page Cache: セグメントファイル
  • 推奨: 物理メモリの50%をJVM Heapに

Source: Instaclustr - OpenSearch and Elasticsearch Architecture

OpenSearchの本当の強み

JOINコスト削減は副次的メリット。本当の強みは「検索体験」を作れることです。

機能説明PostgreSQLでの対応
あいまい検索「ワイヤレスイアホン」(typo)でも「ワイヤレスイヤホン」がヒットpg_trgmで一部対応可能
関連度スコアリング検索キーワードとの関連度で順位付けts_rank関数である程度可能
形態素解析「走った」で「走る」もヒットPGroongaで対応可能
ファセット検索「カテゴリ別の件数」を一発集計GROUP BY + 複数クエリが必要
ハイライトマッチした箇所を強調表示ts_headline関数で対応可能

具体例:ECサイトの商品検索

実際のECサイトでどのように使い分けるか見てみましょう。

PostgreSQLの正規化テーブル

商品、ブランド、カテゴリ、タグ、レビューをそれぞれ別テーブルで管理します。正規化によりデータの整合性は保たれますが、検索時に多数のJOINが必要になります。

  • products: 商品マスタ
  • brands: ブランドマスタ
  • product_categories: 商品×カテゴリの中間テーブル
  • reviews: レビューテーブル
schema.sql
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    description TEXT,
    price INTEGER,
    brand_id INTEGER REFERENCES brands(id)
);

CREATE TABLE brands (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100)
);

CREATE TABLE product_categories (
    product_id INTEGER REFERENCES products(id),
    category_id INTEGER REFERENCES categories(id)
);

PostgreSQLでの検索(辛いパターン)

商品検索で名前、ブランド、カテゴリ、レビュー評価を一度に取得しようとすると、JOINが5つ必要になります。さらにLIKE検索ではインデックスが効きません。

  • JOINが5つ → 重い
  • LIKE '%...%' → 全件スキャン
  • typoでヒットしない
  • 関連度順にできない
search_query.sql
SELECT p.id, p.name, b.name AS brand_name,
       AVG(r.rating) AS avg_rating
FROM products p
LEFT JOIN brands b ON p.brand_id = b.id
LEFT JOIN product_categories pc ON p.id = pc.product_id
LEFT JOIN categories c ON pc.category_id = c.id
LEFT JOIN reviews r ON p.id = r.product_id
WHERE p.name LIKE '%ワイヤレスイヤホン%'
   OR p.description LIKE '%ワイヤレスイヤホン%'
GROUP BY p.id, b.id
ORDER BY avg_rating DESC;

OpenSearchのドキュメント構造

JOINを事前に解決して、1商品1ドキュメントで格納します。非正規化により冗長性は増しますが、検索は劇的に高速化します。

  • 関連データをすべて1ドキュメントに
  • JOINが不要
  • 転置インデックスで爆速検索
product_document.json
{
  "id": 12345,
  "name": "Sony WF-1000XM5 ワイヤレスイヤホン",
  "description": "業界最高クラスのノイキャン...",
  "price": 36000,
  "brand": { "name": "Sony", "country": "日本" },
  "categories": [
    { "name": "オーディオ" },
    { "name": "完全ワイヤレスイヤホン" }
  ],
  "tags": ["ノイキャン", "Bluetooth", "ハイレゾ"],
  "rating": { "average": 4.5, "count": 328 }
}

OpenSearchでの検索クエリ

1つのクエリで、あいまい検索、フィルタリング、ソート、ファセット集計がすべて実行できます。

  • fuzziness: typoでもヒット
  • ^3: nameフィールドを3倍重視
  • aggs: ブランド別件数も一発取得
search_query.json
{
  "query": {
    "bool": {
      "must": [{
        "multi_match": {
          "query": "ワイヤレスイアホン",
          "fields": ["name^3", "description", "tags"],
          "fuzziness": "AUTO"
        }
      }],
      "filter": [
        { "range": { "price": { "lte": 50000 } } }
      ]
    }
  },
  "aggs": {
    "brands": { "terms": { "field": "brand.name.keyword" } }
  }
}

コストについて考える

OpenSearchは高機能ですが、その分コストもかかります。判断基準を見てみましょう。

項目AWS OpenSearch ServicePostgreSQL (RDS)
最小構成約$350/月〜(Serverless 最小)約$15/月〜(db.t3.micro)
本番冗長構成10万円/月超えも普通数万円/月〜
無料枠t3.small.search 750時間/月db.t2.micro 750時間/月
運用コストシャード設計、インデックス管理標準的なDB運用

OpenSearchを選ぶべきケース

  • 検索がプロダクトの核(EC、メディア)
  • 大量のログ分析・可視化が必要
  • あいまい検索・ファセットが必須
  • 将来的に大規模スケールが見込まれる

PostgreSQLで十分なケース

  • 検索は「あれば便利」程度
  • データ量が数十万件程度
  • インフラコストを抑えたい
  • トランザクションの整合性が最重要

Source: AWS OpenSearch Service Pricing

代替案:PostgreSQLで全文検索を実現する

OpenSearchを導入するほどではないけれど、LIKE検索の遅さは解消したい。そんな場合はPostgreSQLの拡張機能を使う方法があります。

拡張用途日本語対応
pg_trgmあいまい検索(trigram)一部動作する
PGroonga日本語全文検索(高機能) 完全対応
pg_bigm日本語全文検索(軽量) 完全対応
tsvector(組み込み)組み込みの全文検索英語等のみ

PGroongaを使った日本語全文検索

PGroongaはGroongaという全文検索エンジンをバックエンドに使用しており、日本語の形態素解析にも対応しています。PostgreSQLのテーブルにインデックスを作成するだけで使えます。

  • &@~: 全文検索演算子
  • recheckが不要で高速
  • 更新中も検索性能が落ちない
pgroonga_setup.sql
-- PGroonga拡張を有効化
CREATE EXTENSION IF NOT EXISTS pgroonga;

-- 検索用の非正規化ビューを作成
CREATE MATERIALIZED VIEW product_search AS
SELECT p.id, p.name, p.description, p.price,
       b.name AS brand_name,
       p.name || ' ' || COALESCE(p.description, '') AS search_text
FROM products p
LEFT JOIN brands b ON p.brand_id = b.id;

-- PGroongaインデックス作成
CREATE INDEX idx_search_text
ON product_search USING pgroonga (search_text);

-- 検索
SELECT * FROM product_search
WHERE search_text &@~ 'ワイヤレスイヤホン';

Source: PGroonga公式 - PGroonga versus textsearch and pg_trgm

スモールスタートのすすめ

小〜中規模ならPostgreSQLの拡張(PGroonga等)でしのいで、本当に限界が来たらOpenSearch導入、というのが現実的なアプローチです。最初から大規模インフラを構築する必要はありません。

Elasticsearch vs OpenSearch:どちらを選ぶか

OpenSearchを検討する際に避けて通れないのが、Elasticsearchとの比較です。両者の違いを見てみましょう。

ライセンス問題とフォークの経緯

Elasticsearchは2021年にApache 2.0ライセンスからSSPL/Elastic Licenseに変更されました。これは厳密にはオープンソースではなくなることを意味します。

  • 2015年: AWS「Amazon Elasticsearch Service」開始。Elastic社のコードを使ってマネージドサービス提供。
  • 2021年: Elastic社がライセンス変更(SSPL/Elastic License)。AWSなどクラウドベンダーの「いいとこ取り」を制限。
  • 2021年: AWS、対抗してElasticsearchをフォーク。OpenSearch誕生(Apache 2.0ライセンス維持)。
  • 2024年: OpenSearchがLinux Foundation傘下に。より中立的なOSSプロジェクトへ。

Elastic社から見れば「自分たちが開発したものをAWSが勝手に商売に使っている」という不満があり、AWSから見れば「オープンソースの精神に反する」という主張。どちらの言い分にも一理ある、業界では有名なドラマです。

機能・性能比較

項目ElasticsearchOpenSearch
ライセンスSSPL / Elastic License(非OSS)Apache 2.0(真のOSS)
運営Elastic社Linux Foundation(AWS主導)
パフォーマンス40〜140%高速(Elastic社ベンチマーク)Big5ワークロードで1.6x高速(Trail of Bits調査)
AWS統合自前でEC2に構築等マネージドサービス完備
可視化ツールKibanaOpenSearch Dashboards

ベンチマーク結果は計測者やワークロードによって異なります。自身の環境でテストすることをおすすめします。

選び方の指針

OPENSEARCH向き

  • AWSメインで使っている
  • 真のOSSライセンスが必要(SaaSとして再販等)
  • コスト重視でマネージドサービスを使いたい
  • ベンダーロックインを避けたい

ELASTICSEARCH向き

  • GCP/Azureメイン
  • 最新機能・最高パフォーマンスが必要
  • Elastic Cloudを使う予算がある
  • Elastic社のサポートが欲しい

正直なところ、普通に使う分にはほぼ同じです。インフラ環境とライセンス要件で決めるのが現実的でしょう。

Source: InfoQ - Elastic Changes Licences, Trail of Bits - Benchmarking

用途別の選び方

用途最適解
トランザクション、データの整合性PostgreSQL
大量テキストの全文検索OpenSearch
ログ分析・集計OpenSearch
JOINを減らして高速化したいだけRDB内で非正規化/マテビュー
ECサイトの商品検索を作りたいOpenSearch または PGroonga
中小規模の日本語検索PGroonga

もっと詳しく知りたい人へ(参考文献)

関連トピック

コメント (0)

まだコメントはありません。最初のコメントを残しませんか?

コメントを投稿

メールアドレスが公開されることはありません。必須項目には * が付いています