Elasticsearchの次世代クエリ言語「ES|QL」に、強力な新機能「ES|QL Views(ビュー)」が登場しました。(Elastic Stack 9.4+, Preview)
この記事では、技術者向けにES|QL Viewsの概要、ユースケース、具体的な実装例、そして内部で動くユニークな最適化ロジック(Query Compaction)までを徹底解説します。
※参考図(NotebookLMによる概要説明図)

1. ES|QL Views とは?
ES|QL Viewsは、一言で表現すると「ES|QLクエリの出力結果をベースにした仮想的なインデックス(Virtual Index)」です。
従来のRDBにおける「ビュー」と同様に、実データそのものを持つわけではありません。あらかじめ定義されたES|QLクエリ(ソースコマンドやパイプライン処理を含む)に名前をつけて保存し、他のクエリから通常のインデックスと全く同じように FROM 句で呼び出すことができます。
主な特徴
- 動的な実行 (Dynamic Execution)
- メインクエリが実行される際、参照されているビューもその場でオンデマンドに実行されます。そのため、元となるソースインデックスが更新されていれば、常に最新のデータが反映されます。
- インデックスと同等の扱い
- 通常のインデックス名だけでなく、ワイルドカードやインデックスパターンと組み合わせて、シームレスに FROM 句に指定可能です。
2. なぜ使うのか?(主要なユースケース)
ES|QLパイプラインが複雑化するにつれ、Viewsは以下のような場面で真価を発揮します。
- 複雑なクエリの再利用(DRY原則の適用)
- 頻繁に使用するフィルタや集計(STATS)、計算(EVAL)のパイプラインをビューとしてカプセル化することで、クエリの重複を排除し、メンテナンス性を向上させます。
- データ構造の抽象化
- フィールド名の変更(RENAME)や型変換、派生フィールドの生成をビュー側で集中管理できます。クエリの利用者は、背後の複雑なマッピングを気にせず、一貫したカラムを参照できます。
- マルチソースの事前処理と結合
- 異なるデータソースごとに個別のフィルタや前処理を施したビューを作成し、それらをメインクエリの FROM 句で一元的に結合・クエリできます。
- 下流ツールの簡素化
- Kibanaのダッシュボードやアラート、アドホックな分析を行うアナリストに対して、裏側のインデックスや煩雑な前処理を隠蔽したシンプルな「ビュー」だけを提供できます。
3. 基本的な使い方
具体的な実装の流れを見てみましょう。ここでは例として、住所データ(addresses)から国名を統一してカウントするビューを作成し、それを呼び出します。
ビューの定義(作成・更新)
REST API を使用して、view_country_addresses という名前のビューを定義します。
PUT /_query/view/view_country_addresses
{
"query": """
FROM addresses
| RENAME city.country.name AS country
| EVAL country = CASE(country == "United States of America", "United States", country)
| STATS count = COUNT() BY country
"""
}ビューの呼び出し
定義したビューは、通常のインデックスと全く同じように FROM でクエリできます。
FROM view_country_addresses出力結果イメージ:
| count | country |
|---|---|
| 1 | Japan |
| 1 | Netherlands |
| 1 | United States |
4. 応用・実戦パターン集
※ 以下の例では、ビューの名前をインデックスと明示的に区別するために view_ プレフィックスを付与しています(付与は任意です)。
4.1. シンプルなフィルタリングとデータのカプセル化
特定の条件(例: HTTP Response のエラー)に合致するログだけを抽出するビューです。裏側の複雑なフィルタ条件をダッシュボードや他のアナリストから隠蔽できます。
ビューの定義
PUT /_query/view/view_error_triage
{
"query": """
FROM kibana_sample_data_logs
| WHERE response == "404" OR response == "503"
"""
}ビューの参照
FROM view_error_triage
| STATS error_count = COUNT(*) BY url
| WHERE error_count > 20
| SORT error_count DESC※Discover での実行例

4.2. ワイルドカードを用いた複数ビューの一括集計
同じスキーマ構造を持つ複数のビューが存在する場合、ワイルドカード(*)を使って同時に呼び出し、さらにマージ・集計(SUM)することが可能です。
複数ビューをまたぐ集計クエリ
FROM view_country_*
| STATS total_count = SUM(count) BY country
| WHERE total_count > 10
| SORT total_count DESC, country ASC(※ 事前に view_country_addresses、view_country_airports などが定義されているケースを想定)
4.3. サブクエリ(Subqueries)を内包したマルチソース統合
異なる複数のデータソース(ゲートウェイ、決済、認証など)のログを、ビューの定義内でサブクエリとして並列展開(ブランチ)して統合する、より高度な構成です。
ビューの定義
PUT /_query/view/view_error_triage_multisource
{
"query": """
FROM
(FROM svc-gateway-* | WHERE http.response.status_code >= 500),
(FROM svc-payments-* | WHERE http.response.status_code >= 500),
(FROM svc-auth-* | WHERE http.response.status_code >= 500)
"""
}- 💡 技術的ポイント (Query Compaction):
- ES|QLは通常1レベルのブランチ(並行処理)しか許容しませんが、ビュー内に記述されたサブクエリは、メインクエリ実行時に後述の「Query Compaction」によって自動的に最適化されます。これにより、ネスト制限を回避しながら複雑なマルチソースクエリをカプセル化できます。
4.4. LOOKUP JOIN を用いたマスタデータとの結合
インデックス同士を LOOKUP JOIN で結合した結果をビューとして保存できます。以下は、特定の空港マスタに合致するデータだけの「フィルタリング済みサブセット」を定義する例です。
ビューの定義
PUT /_query/view/view_airports_mp_filtered
{
"query": """
FROM airports
| RENAME abbrev AS code
| LOOKUP JOIN airports_mp ON abbrev == code
| WHERE abbrev IS NOT NULL
| DROP code
"""
}作成したビュー(結合済みデータ)と、元の未加工インデックスを同時に FROM 句で呼び出して、データの重複度合いを調査するような高度なアドホック分析も行えます。
ビューと通常インデックスを組み合わせた比較クエリ
FROM view_airports_mp_filtered, airports
| STATS duplications = COUNT() BY abbrev
| STATS count = COUNT() BY duplications
| SORT count DESC5. アーキテクチャ深掘り:ネスト制限と「Query Compaction」
技術者として最も押さえておきたいのが、ビューが実行される際のクエリプランと最適化の挙動です。
ネストとブランチングの制限
ES|QL Viewsは、ビューの中に別のビューを含める「ネスト」を最大10階層までサポートしています。
また、1つのインデックスパターン(FROM 句)で複数のビューを指定すると、それらは並列(ブランチ)で実行されます。ただし、リソース制限の観点から、ビュー・サブクエリ・FORK の組み合わせによる最大ブランチ数は「8」に制限されています。
自動最適化ロジック「Query Compaction(クエリの平坦化)」
通常、階層構造を持つブランチ(入れ子になった並列処理)はクエリプランを複雑化させるため、制限を超えるとエラーになります。しかし、ES|QL Viewsには Query Compaction という最適化ロジックが組み込まれています。
例えば、内部でそれぞれ2つのサブクエリ(2ブランチ)を持つ2つのビュー(view_x と view_y)を、メインクエリで同時に呼び出したとします。
- 論理的な階層:
- メインクエリ(2つのビューを呼び出す) → 各ビュー内部(2ブランチずつ) = 2階層の複雑なプラン
- 実際の挙動 (Compaction):
- ES|QLは自動的に内部のビューブランチを外側に「フラット化(展開)」し、単一レベルの「4つの並列ブランチ」として実行プランを再構成します。これによってネストによる階層制限の上限に抵触するのを防いでいます。
- ⚠️ 注意:Query Compaction の適用条件
- Query Compactionが適用されるには条件があります。ビュー定義内のサブクエリの後ろにコマンド(STATS など)が続いていない必要があります。後ろに別の処理が挟まっていると、ブランチを綺麗にバラしてフラット化できないため、ブランチ数制限の上限を超えてクエリが失敗する原因になります。
※参考図 (Gemini による Query Compaction の説明図)

6. 現時点での制限事項(Tech Preview)
実戦投入する前に、現在の技術プレビュー(Tech Preview)段階における制限を把握しておきましょう。
- Serverless環境での未対応:
- 初期フェーズにおいて、Serverless環境およびクロスプロジェクト検索では利用できません。
- クロス・クラスター検索 (CCS) の制限:
- リモートクラスターのビューを指定する FROM cluster:view_name のようなクエリは、ビューではなく「インデックス」としてマッチしようとするため、現状はエラーになります。
- クエリパラメータの隔離:
- メインクエリに指定したクエリパラメータ(引数)は、ビューの定義内には引き継がれません。
- Query DSL フィルタの影響:
- 現段階ではメインクエリに指定したQuery DSLフィルタがビューの「ソースインデックス」にまで影響を及ぼす挙動になっています(将来のリリースで、ビューの「出力結果」に対してフィルタがかかるよう修正予定)。
まとめ
ES|QL Viewsの登場により、Elasticsearchでのデータパイプライン構築の柔軟性が大幅に向上しました。
複雑なロジックをビューに閉じ込めることで、クエリの可読性が上がるだけでなく、チーム間でのデータ利用の標準化(抽象化レイヤーの構築)が容易になります。現在はTech Preview(Stack 9.4+)ですが、将来の正式リリースに向けて、今のうちに検証環境でこの強力な仮想インデックス機能を試してみてはいかがでしょうか?

