[入門] Elasticsearchとは?概要から使い方までわかりやすく解説

Elasticsearch

Elasticsearch とは、キーワードで文書を検索する検索エンジンです。

具体的には google 検索や、github のソースコード検索のような検索ができます。

Elasticsearch & OpenSearch の使い方
スポンサーリンク

検索の種類

Elasticsearch では、主に次の 2 種類の検索方法があります。

  • 全文検索 (実現手段:grep 型/索引 [= インデックス] 型)
  • セマンティック検索 (実現手段:ベクトル検索)

全文検索とは

全文検索とは、複数のファイルから特定のキーワードを検索することです。

全文検索には、主に以下の2つの方法があります。

grep 型とは

grepとは、ファイルを上から順番に検索する方法です。

UNIX の grep コマンドは、こちらに相当します。

grep 型は、ファイルの数が増えると検索速度が大幅に低下する特徴があります。

索引 (インデックス) 型とは

索引型とは、予め作成した索引を利用して、検索する方法です。

Elasticsearch の全文検索は、こちらに相当します。

転置インデックスは、どのファイル (正確にはドキュメント) にあるか?どの位置にあるのか?を記録します

索引型は、不要なファイルをスキャンしないので、高速に検索できます。

索引 (転置インデックスと呼ぶ) の作成方法は、以下の記事をご覧ください。(こちらも)

セマンティック検索とは

セマンティック検索とは、検索文の意味を解釈して検索する方法です。

例えば、「東京スカイツリー 観光」と検索すると、近場のランチの場所もヒットします。

セマンティック検索の実現方法の1つとして、ベクトル検索が存在します。

ベクトルデータベースを利用したベクトル検索の詳細は、以下の記事をご覧ください。

スポンサーリンク

Elasticsearch 用途/事例/できる事

Elasticsearch の主な利用用途は以下の 3 つです。

企業における全文検索の利用例は以下のとおりです。

■ZOZOTOWN: 商品検索

GitHub: ソースコード検索

ソフトウェア開発の加速化
エンドユーザーと開発者の両方にとって強力な検索が可能に ApacheSolrからElasticsearchへの移行により、スケ ールアウトが可能になり急激に拡大するユーザーのニ ーズ対応に ほとんどのタイプのデータをインデックスして検索可 能に 開発者アプリケーションでプログラムによる高度な検 索が可能に 新し...

日経新聞: 記事の検索、アクセスログの解析

日本経済新聞社: ドキュメント総数1.6億件、国内最大級のデータベース事業の検索を担う
1876 年創刊の日本経済新聞をはじめとする新聞を中核に、出版や放送など幅広い事業を展開。 デジタル分野でも、2010 年に日本初の本格的有料電子版サービスとして創刊した「日経電子版」 や、1984 年にサービスを開始した「日経テレコン」など多くのサービスを手掛ける。 ...

異常検知

企業における異常検知の利用例は以下のとおりです。

■RICOH: セキュリティインシデントの検知

SOCにおけるリアル、CSIRT:株式会社リコーを実現”見える化、“タイムデータの活用を促進しすることでリコーグループのセキュリティを強化
1日2TBにおよぶITデバイスのログを35ノードのElasticsearchで瞬時に検索し、セキュリティ上の脅威をプロアクティブに排除...

Netflix: セキュリティログの監視

可視化

Elasticsearch 用の可視化ソフトウェアである Kibana を利用し、データを可視化できます。

https://www.elastic.co/jp/what-is/kibana-reporting

なお、データ収集には Fluentd がよく利用され、Elasticsearch, Fluentd, Kibana の 3 つを合わせて、EFK スタックと呼ばれます。

スポンサーリンク

Elasticsearch のアーキテクチャ

Elasticsearch では、データを以下のように JSON 形式で持ちます。

データの型以外にも、色んなパラメータを設定できます (マッピングパラメータ一覧)

ドキュメント

ドキュメントとは、JSON 形式のデータです。

フィールド

フィールドとは、JSON オブジェクトのキーバリュー(名前と値の組) に相当します。

マッピング

マッピングとは、フィールドのデータ型などを定義するものです。(データ型一覧)

Elasticsearch は、ドキュメントを以下のように配置します。

クラスター

クラスターとは、ノードの集合 (≒複数のコンピュータ) です。

ノード

ノードとは、Elasticsearch サーバー (≒1台のコンピュータ) のことです。

ノードには、主に次の4種類が存在します。

ノードの種類役割
マスターノードクラスターのメタデータなどを管理するノード
・マスターノードはクラスターに 1 台のみ
・それ以外は、マスター候補ノードと呼ぶ
・マスター候補ノードが昇格するとマスターノードになる
データノードデータを格納・リクエストの処理 (検索や集計などを) するノード
Ingest ノードデータの変換や加工をして、データノードに格納するノード
Coordinating ノードリクエストを適切なデータノード※にルーティングするノード
※正確には、データノードの持つシャード
1つのノードに複数の役割を割り当てることも可能。ノードの役割一覧はこちら
最初はデータノードで全ての役割兼任し、スペックが足りなくなった時点で専属の役割を持つノードを追加すると良い

インデックス

インデックスとは、ドキュメントの格納先です。

一般的に、インデックスはログの種類や、日/週/月ごとに分けます。

シャード

シャードとは、インデックスを分割したものです。
複数のデータノードシャードを分散配置することで、分散処理を実現します。

シャードの種類には、以下の2種類が存在します。

シャードの種類説明
プライマリーシャード読み書きを行うシャード
レプリカシャードプライマリーシャードのコピー (レプリケーション)
読み取りの負荷分散や、データのバックアップとして利用

Elasticsearch の実体

Elasticsearch は、Apache Lucene がベースとなっており、実体は以下のとおりです。

  • Elasticsearch のシャードは、Lucene インデックスに相当
  • Lucene インデックスは、複数のセグメント (ファイル) から構成される
  • セグメントは、複数のドキュメントを持つ
https://thoughts.t37.net/designing-the-perfect-elasticsearch-cluster-the-almost-definitive-guide-e614eabc1a87 より。一部改変

Elasticsearch のインストール

Docker を使った Elasticsearch のインストール方法を紹介します。

Docker を使わないインストール方法はこちら

ここでは Amazon Linux 2 でインストールする方法を紹介します。

その他の OS については以下のドキュメントをご覧ください。

■Elasticsearch のインストール

Installing Elasticsearch | Elasticsearch Guide [8.12] | Elastic

Kibana のインストール

Kibanaのインストール | Kibanaユーザーガイド [5.4] | Elastic

Java のインストール

Elasticsearch を実行するには Java 8 が必要なので、まずは Java 8 をインストールします。

sudo yum install java-1.8.0-openjdk -y
sudo yum install java-1.8.0-openjdk-devel -y
java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)

openjdk version "1.8****" 以上であれば OK です。

Elasticsearch のインストール

次に Elasticsearch をインストールします。

sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
sudo vim /etc/yum.repos.d/elasticsearch.repo
[elasticsearch]
name=Elasticsearch repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
autorefresh=1
type=rpm-md
sudo yum install --enablerepo=elasticsearch elasticsearch -y
sudo systemctl start elasticsearch
curl localhost:9200
{
  "name" : "***",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "***",
  "version" : {
    "number" : "7.10.0",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "***",
    "build_date" : "2020-11-09T21:30:33.964949Z",
    "build_snapshot" : false,
    "lucene_version" : "8.7.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Kibana のインストール

Kibana をインストールします。

sudo vim /etc/yum.repos.d/kibana.repo
[kibana-7.x]
name=Kibana repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
sudo yum install kibana -y
sudo vim /etc/kibana/kibana.yml
server.host: "0.0.0.0"
sudo systemctl start kibana

ブラウザから Kibana(localhost:5601) にアクセスします。

以下のページが表示されれば成功です。(この記事は Kibana バージョン 7.10.0です)

アクセスできない場合

Elastic Kibana v7.3.0でSystemctrlを用いた起動ができず再起動を繰り返す。 - szkhaven.com
自分的メモです。 v6.7を使用してたのですが、そろそろv7に上げよう 続きを読む

docker コンテナを作成

version: '3'
services:
  elasticsearch:
    image: elasticsearch:7.12.1
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
    ports:
      - 9200:9200
  kibana:
    image: kibana:7.12.1
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200

これでシングルノードの Elasticsearch コンテナが立ち上がります。

Elasticsearch にアクセス

curl localhost:9200
{
  "name" : "123456789abc",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "1234567890abcdefghijkl",
  "version" : {
    "number" : "7.12.1",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "1234567891456789123456789",
    "build_date" : "2021-04-20T20:56:39.040728659Z",
    "build_snapshot" : false,
    "lucene_version" : "8.8.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

起動に成功している場合は、上記のような結果が返ってきます。

※ 「curl: (56) Recv failure: Connection reset by peer」が返ってくる場合は初期化処理が完了するまでお待ちください。

Kibana にアクセス

Kibana コンテナにアクセスするために、ブラウザで http://localhost:5601 を開きます。

Kibana は、Dev Tools を使うことで、REST API 経由で Elasticsearch を操作できます。

Dev Tools の開き方(kibana 7.10.0 の場合)

以降では、Dev Tools で REST API を実行し、Elasticsearch を操作する方法を解説します。

CRUD 操作 + Bulk API

Elasticsearch 基本操作として、REST API による CRUD 操作を紹介します。

REST API説明対応する CRUD
Index APIインデックスにドキュメントを追加Create
Get APIインデックスのドキュメントを取得Read
Index API
Update API
インデックスのドキュメントを更新Update
Delete APIインデックスのドキュメントを削除Delete

Index API (Create)

Index API とは、インデックスにドキュメントを追加する API です。
PUT /<インデックス名>/_doc/<ドキュメント ID>
{
 "フィールドのキー":"フィールドの値"
}
PUT /test/_doc/1
{
  "date":"2020/11/01 09:00 JST",
  "Tweet":"ツイッターをはじめました。",
  "User ID":"hoge"
}

右上の三角ボタンで実行します。

curlREST API を実行する場合

curl localhost:9200/test/_doc/1?pretty -XPUT -H "Content-Type: application/json" -d '
{
  "date":"2020/11/01 09:00 JST",
  "Tweet":"ツイッターをはじめました。",
  "User ID":"hoge"
}'

補足 データストリームへドキュメントを追加する場合

データストリームとは、複数のインデックスを1つにまとめたものです。

データストリームの詳細は以下のドキュメントに記載がございます。

Data streams | Elasticsearch Guide [8.12] | Elastic

データストリームにドキュメントを追加するためには、以下の REST API を利用します。

PUT /tweet/_create/1
{
  "date":"2020/11/01 09:00 JST",
  "Tweet":"ツイッターをはじめました。",
  "User ID":"hoge"
}

Get API (Read)

Get API とは、インデックスからドキュメントを取得する API です。
GET /<インデックス名>/_doc/<ドキュメントID>
GET /test/_doc/1
{
  (中略)
  "_source" : {
    "date" : "2020/11/01 09:00 JST",
    "Tweet" : "ツイッターをはじめました。",
    "User ID" : "hoge"
  }
}

curlREST API を実行する場合

curl localhost:9200/test/_doc/1?pretty
{
  (中略)
  "_source" : {
    "date" : "2020/11/01 09:00 JST",
    "Tweet" : "ツイッターをはじめました。",
    "User ID" : "hoge"
  }
}

Update API (Update)

Update API とは、インデックスのドキュメントを更新する API です。

なお、インデックス作成で利用した Index API でも更新可能です。

Update APIIndex API
説明スクリプトでフィールドを上書き既にドキュメントがある場合は上書き
用途一部のフィールドだけ更新したい時
更新処理を自分で書きたい時
ドキュメントを上書きしたい時

一部のフィールドを更新

POST /<インデックス名>/_update/<ドキュメント ID>
{
  "doc": {
    "更新するフィールドのキー":""
  }
}

具体的な使用例は、以下のとおりです。

POST /test/_update/1
{
  "doc": {
    "Tweet":"フィールドを更新したよ。"
  }
}
GET /test/_doc/1
  "_version" : 2
  "_source" : {
    "date" : "2020/11/01 09:00 JST",
    "Tweet" : "フィールドを更新したよ。",
    "User ID" : "hoge"
  }

"Tweet" フィールドの値が更新され、_version が 2 に変化していることがわかります。

全てのフィールドを更新 (ドキュメントの上書き)

PUT /<インデックス名>/_doc/<ドキュメント ID>
{
 "フィールドのキー":"フィールドの値"
}

具体的な使用例は、以下のとおりです。

PUT /test/_doc/1
{
  "Tweet":"ドキュメントを置き換えたよ"
}
GET /test/_doc/1
  "_version" : 3,
  "_source" : {
    "Tweet" : "ドキュメントを置き換えたよ"
  }

以下の3つが確認できます。

  • Tweet フィールドが上書き
  • date, User ID フィールドが消える (上書きしたドキュメントに存在しないので)
  • _version が 3 に変化

curlREST API を実行する場合

curl localhost:9200/test/_doc/1?pretty -XPOST -H "Content-Type: application/json" -d '
{
  "date":"2020/11/01 09:00 JST",
  "Tweet":"ドキュメントを更新したよ。",
  "User ID":"hoge"
}'
curl localhost:9200/test/_doc/1?pretty
{
(中略)
  "_version" : 2,
  "_source" : {
    "date" : "2020/11/01 09:00 JST",
    "Tweet" : "ドキュメントを更新したよ。",
    "User ID" : "hoge"
  }

"Tweet" フィールドの値が更新され、_version が2に変化していることがわかります。

POST <index>/_update/<_id> を使う場合

POST /test/_update/1
{
  "doc": {
    "Tweet":"ドキュメントを一部更新したよ。"
  }
}
GET /test/_doc/1
{
(中略)
  "_source" : {
    "date" : "2020/11/01 09:00 JST",
    "Tweet" : "ドキュメントを一部更新したよ。",
    "User ID" : "hoge"
  }

Delete API (Delete)

Delete API とは、インデックスのドキュメントを削除する API です。
DELETE /<インデックス名>/_doc/<ドキュメント ID>
DELETE /test/_doc/1
GET /test/_doc/1
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "found" : false
}

found" が false となりました。("_source" のフィールドが削除されました。)

curlREST API を実行する場合

curl localhost:9200/test/_doc/1?pretty -XDELETE
curl localhost:9200/test/_doc/1?pretty
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "found" : false
}

"found" が false となりました。("_source" のフィールドが削除されました。)

Bulk API (一括処理)

Bulk API とは、1回の API 呼び出しで、ドキュメントの操作を複数回行える API です。
POST /_bulk
{ "アクション名" : { "_index" : "インデックス名", "_id" : "ドキュメント ID" } }

Bulk API では、以下のアクションを一括で行えます。

アクション説明クエリの 2 行目
Createインデックスが存在しない場合、ドキュメントを作成フィールドが必要
Indexインデックスのドキュメントを全て更新 (置き換え)フィールドが必要
Updateインデックスのドキュメントを一部更新doc が必要
Deleteインデックスのドキュメントを削除-
POST /_bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "フィールドのキー" : "フィールドの値を置き換え" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "フィールドのキー" : "フィールドの値を作成" }
{ "update" : { "_index" : "test", "_id" : "3" } }
{ "doc" : {"フィールドのキー" : "フィールドの値を更新"} }
GET /test/_search
      {
        "_index": "test",
        "_id": "3",
        "_score": 1,
        "_source": {
          "フィールドのキー": "フィールドの値を更新"
        }
      },
      {
        "_index": "test",
        "_id": "1",
        "_score": 1,
        "_source": {
          "フィールドのキー": "フィールドの値を置き換え"
        }
      }

なお、GET test/_search の意味は、この下で解説します。

curlREST API を実行する場合

Bulk API で操作する内容を記載した json ファイルを作成します。

{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
curl localhost:9200/_bulk?pretty -XPOST --data-binary @bulk.json -H "Content-Type: application/json"

ドキュメントの検索 (search API)

Elasticsearch では、search API を利用してインデックス内にあるドキュメントを検索します。

search API でよく利用するクエリグループは、次の 4 つです。

クエリグループクエリ説明
Full textmatch, match_phrase全文検索。(転置インデックスで検索)
Term-levelterm, terms, wildcard, range完全一致検索 (転置インデックスは使わない)
Vectorknn (別記事で解説)セマンティック検索 (ベクトル検索)
Compoundbool複合検索 (他のクエリを組み合わせる)
クエリ一覧はこちら (左側にある Query DSL)。

今回は、以下のデータを使用して、search API を解説します。

POST /_bulk
{ "index" : { "_index" : "demo_search", "_id" : "1" } }
{ "text" : "This is Elasticsearch test.", "num" : 1 }
{ "index" : { "_index" : "demo_search", "_id" : "2" } }
{ "text" : "Elasticsearch is search engine.", "num" : 2 }
{ "index" : { "_index" : "demo_search", "_id" : "3" } }
{ "text" : "This is a pen.", "num" : 3 }

クエリなし (条件なし検索)

まずは、検索条件を指定せずに search API でドキュメントを検索してみます。

GET /demo_search/_search
    "hits" : [
      {
        "_index" : "demo_search",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "text" : "This is Elasticsearch test.",
          "num" : 1
        }
      },
      {
        "_index" : "demo_search",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "text" : "Elasticsearch is search engine.",
          "num" : 2
        }
      },
      {
        "_index" : "demo_search",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "text" : "This is a pen.",
          "num" : 3
        }
      }
    ]

作成した3つのドキュメントがすべて検索できています。

Full text (全文検索)

Full text クエリは、転置インデックスで全文検索を行います。

そのため、検索するフィールドには、転置インデックスを利用可能な text 型を主に使います。

Full text クエリとして、match と match_phrase クエリを紹介します。

match (全文検索)

match クエリとは、全文検索を行うクエリです。
GET /demo_search/_search
{
  "query":{
    "match": {
      "text" : "engine"
    } 
  }
}
(中略)
        "_source": {
          "text": "Elasticsearch is search engine."

「engine」を含むドキュメントが検索できました。

また、match クエリでは、AND 検索や OR 検索もできます。

GET /demo_search/_search
{
  "query":{
    "match": {
      "text": {
        "query": "Elasticsearch engine",
        "operator":"AND"
      }
    } 
  }
}
(中略)
        "_source" : {
          "text" : "Elasticsearch is search engine."

[Elasticsearch] と [engine] の両方を含むドキュメントが検索できました。

match_phrase (フレーズ)

match_phrase とは、単語の順序が一致するドキュメントを全文検索するクエリです。
GET /demo_search/_search
{
  "query":{
    "match_phrase": {
      "text": "Elasticsearch test"
    } 
  }
}
    "hits" : [
        (省略)
        "_source" : {
          "text" : "This is Elasticsearch test."
        }
      }

語順が「Elasticsearch test」であるドキュメントを検索できました。

クエリの語順が一致しない場合

GET /demo_search/_search
{
  "query":{
    "match_phrase": {
      "text":{
        "query": "test Elasticsearch"
      }
    } 
  }
}
"hits" : [ ]

語順が違うのでヒットしないことが確認できます。

Term-level (完全一致検索)

Term-level クエリは、完全一致検索を行います。

そのため、転置インデックスではなく、そのまま内容を格納した keyword 型を主に使います。

Term-level クエリとして、term, terms, wildcard, range クエリを紹介します。

term (完全一致検索)

term クエリとは、完全一致検索を行うクエリです。
GET /demo_search/_search
{
  "query":{
    "term": {
      "text.keyword": "This is Elasticsearch test."
    } 
  }
}
        "_source" : {
          "text" : "This is Elasticsearch test."

完全一致しているドキュメントが検索できました。

match クエリとの違い

term は完全一致検索なので、単語一致で検索できません。(match を使ってください。)

GET /demo_search/_search
{
  "query":{
    "term": {
      "text.keyword": "Elasticsearch"
    } 
  }
}
"hits" : [ ]

"Elasticsearch" は "This is Elasticsearch test." と完全一致でないので検索にヒットしない。

単語検索をしたい場合は、match クエリを利用しましょう。

GET /demo_search/_search
{
  "query":{
    "match": {
      "text": "Elasticsearch"
    } 
  }
}
      {
        "_index": "demo_search",
        "_id": "2",
        "_score": 0.2876821,
        "_source": {
          "text": "Elasticsearch is search engine.",
          "num": 2
        }
      },
      {
        "_index": "demo_search",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "text": "This is Elasticsearch test.",
          "num": 1
        }
      }

terms (複数形)

terms とは、複数の完全一致検索をするクエリです。
GET /demo_search/_search
{
  "query":{
    "terms": {
      "text.keyword":["This is Elasticsearch test.","This is a pen."]
    } 
  }
}
"_source" : {
          "text" : "This is Elasticsearch test."
        }
        (中略)
        "_source" : {
          "text" : "This is a pen."
        }

wildcard (ワイルドカード)

wildcard とは、パターンに一致するドキュメントを検索するクエリです。
GET /demo_search/_search
{
  "query":{
    "wildcard": {
      "text" : "eng*"
    } 
  }
}
        "_source": {
          "text": "Elasticsearch is search engine.",
          "num": 2
        }

range (範囲検索)

Range クエリとは、指定した値を元に範囲検索するクエリです。
GET /demo_search/_search
{
  "query":{
    "range": {
      "num":{
        "gte": "1",
        "lte": "2"
      }
    } 
  }
}
    "hits" : [
      {
        "_index" : "demo_search",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "text" : "This is Elasticsearch test.",
          "num" : 1
        }
      },
      {
        "_index" : "demo_search",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "text" : "Elasticsearch is search engine.",
          "num" : 2
        }
      }

num フィールドの値が1以上、2以下のドキュメントを検索できました。

Compound (複合検索)

Compound クエリは、今まで紹介したような他のクエリを組み合わせることができます。

Compound クエリとして、bool クエリを紹介します。

bool クエリbool クエリとは、複数のクエリに対して AND, OR, NOT 等を実施するクエリです。

bool クエリには、以下の4種類のクエリが存在します。

bool クエリの種類説明
must クエリAND 条件
should クエリOR 条件
must_not クエリNOT 条件
filter クエリフィルタリング

must クエリ

must クエリとは、AND 条件を表すクエリです。
GET /demo_search/_search
{
  "query":{
    "bool": {
      "must":[
        {"match":{"text":"Elasticsearch"}},
        {"range":{"num":{"lte":"1"}}}
      ]
    } 
  }
}
        "_source" : {
          "text" : "This is Elasticsearch test.",
          "num" : 1
        }

「text = "Elasticsearch" を含む」AND「num = 1以下」のドキュメントを検索できています。

should クエリ

should クエリとは、OR 条件を表すクエリです。
GET /demo_search/_search
{
  "query":{
    "bool": {
      "should":[
        {"match":{"text":"engine"}},
        {"range":{"num":{"gte":"2"}}}
      ]
    } 
  }
}
      {
        "_index": "demo_search",
        "_id": "2",
        "_score": 1.287682,
        "_source": {
          "text": "Elasticsearch is search engine.",
          "num": 2
        }
      },
      {
        "_index": "demo_search",
        "_id": "3",
        "_score": 1,
        "_source": {
          "text": "This is a pen.",
          "num": 3
        }
      }

「text = "engine" を含む」OR「num = 2以上」のドキュメントを検索できています。

なお、両方の条件を満たすドキュメントのほうが "_score" の値が高くなります。

must_not クエリ

must_not クエリとは、NOT 条件を表すクエリです。
GET /demo_search/_search
{
  "query":{
    "bool": {
      "must_not":[
        {"match":{"text":"Elasticsearch"}}
      ]
    } 
  }
}
    "hits" : [
      {
        "_index" : "demo_search",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.0,
        "_source" : {
          "text" : "This is a pen.",
          "num" : 3
        }
      }

[Elasticsearch] を含まないドキュメントが検索できました。

match と全く一致してないので、当然 "_score" は 0 のドキュメントです。

filter クエリ

filter クエリとは、指定したドキュメント以外を検索結果から除外するクエリです。
GET /demo_search/_search
{
  "query":{
    "bool": {
      "must": [
        {"match":{"text":"Elasticsearch"}}
      ], 
      "filter":[
        {"range":{"num":{"lte":"1"}}}
      ]
    } 
  }
}
        "_source" : {
          "text" : "This is Elasticsearch test.",
          "num" : 1
        }

[Elasticsearch is search engine.] は match 条件に一致しますが、"num" = 2 のため、検索結果から除外されています。

Aggregations (集計)

Aggregations には、主に次の 3 種類が存在します。

以下の "demo_agg" インデックスを利用して、Aggregations の動きを確認します。

POST /_bulk
{ "index" : { "_index" : "demo_agg", "_id" : "1" } }
{ "text" : "This is Elasticsearch test.", "num" : 1 }
{ "index" : { "_index" : "demo_agg", "_id" : "2" } }
{ "text" : "Elasticsearch is search engine.", "num" : 2 }
{ "index" : { "_index" : "demo_agg", "_id" : "3" } }
{ "text" : "This is a pen.", "num" : 3 }

Metrics aggregations (計算)

Metrics Aggregations とは、ドキュメントのメトリクスを集計 (集めて計算) します。

Metrics aggregations では、以下のような集計ができます。

Metrics aggregations の種類説明
Avg aggregation平均を取得する
Sum aggregation合計値を取得する
Max aggregation最大値を取得する
Min aggregation最小値を取得する
Stats aggregation上記全部の値を取得する
Cardinary aggregation異なる値の数を取得する
※[1,2,3,2]の場合は1,2,3 の3種類
Metrics aggregations の一覧はこちら (左のナビゲーションペインから確認してください)

ここでは、Avg aggregation を利用してみます。

Avg aggregation

Avg aggregation とは、検索したドキュメントにあるフィールドの平均値を求めます。
GET demo_agg/_search
{
  "size": 0,
  "aggs": {
    "集計の名前": {
      "avg": {
        "field":"num"
      }
    }
  }
}
  "aggregations" : {
    "集計の名前" : {
      "value" : 2.0
    }
  }

"num" フィールドの値は [1, 2, 3, 2] なので、平均の 2.0 を正しく計算できています。

Buckets aggregations (分類)

Buckets Aggregations とは、フィールドの値を分類し、各バケットに格納します。

Buckets aggregations では、以下のような分類ができます。

Buckets aggregations の種類説明
Range aggregation指定した範囲ごとにバケットを作成
(0~99円, 100~1000円 等)
Histogram aggregation指定した等間隔でバケットを作成
(100円ごと等)
IP range aggregationIP アドレスの範囲ごとにバケットを作成
(192.168.0.0/24, 192.168.1.0/24 ごと等)
Geo-distance aggregation距離ごとにバケットを作成
(指定した位置から 99km まで、100km~300km 等)
Buckets aggregations の一覧はこちら (左のナビゲーションペインより)

ここでは、Range aggregationHistogram aggregation を利用してみます。

Range aggregation

Range aggregation とは、指定した範囲ごとに、バケットを作成する方法です。
GET demo_agg/_search
{
  "size": 0,
  "aggs": {
    "バケットの名前": {
      "range": {
        "field":"num",
        "ranges": [
          {
            "from": 0,
            "to":2
          },
          {
            "from": 2
          }
        ]
      }
    }
  }
}
  "aggregations" : {
    "バケットの名前" : {
      "buckets" : [
        {
          "key" : "0.0-2.0",
          "from" : 0.0,
          "to" : 2.0,
          "doc_count" : 1
        },
        {
          "key" : "2.0-*",
          "from" : 2.0,
          "doc_count" : 3
        }
      ]
    }

次の結果が確認できます。

  • num の値が [0 以上 ~ 2 未満] を格納するバケットに、1つのドキュメント (num = [1])
  • num の値が [2 以上] を格納するバケットに、3つのドキュメント (num = [2, 3, 2])

Histogram aggregation

Histogram aggregation とは、指定した等間隔でバケットを作成する方法です。
1000 間隔でバケットを分けたヒストグラムの例
GET demo_agg/_search
{
  "size": 0,
  "aggs": {
    "バケットの名前": {
      "histogram": {
        "field":"num",
        "interval": 1
      }
    }
  }
}
  "aggregations" : {
    "バケットの名前" : {
      "buckets" : [
        {
          "key" : 1.0,
          "doc_count" : 1
        },
        {
          "key" : 2.0,
          "doc_count" : 2
        },
        {
          "key" : 3.0,
          "doc_count" : 1
        }
      ]

num の値が 1 ごとにバケットが作成されていることがわかります。

Pipeline aggregations (多段集計)

Pipeline aggregations とは、他の集計結果を利用して集計します。
POST /demo_agg/_search
{
  "size": 0,
  "aggs": {
    "1段目の名前": {
      "range": {
        "field": "num",
        "ranges": [
          {
            "from": 1,
            "to":2
          },
          {
            "from": 2
          }
        ]
      },
      "aggs": {
        "2段目の名前": {
          "sum": {
            "field": "num"
          }
        }
      }
    }
  }
}
    "1段目の名前": {
      "buckets": [
        {
          "key": "1.0-2.0",
          "from": 1,
          "to": 2,
          "doc_count": 1,
          "2段目の名前": {
            "value": 1
          }
        },
        {
          "key": "2.0-*",
          "from": 2,
          "doc_count": 2,
          "2段目の名前": {
            "value": 5

以下のように 1 段目のバケットの内容を使って、2 段目で処理できています。

  • 1段目の Range Aggregation で、[0 以上 ~ 1未満] と [2 以上] の 2 つのバケットを作成
  • 2段目の Sum Aggregation で、1 段目のバケットの合計をそれぞれ計算
    ※[0 以上 ~ 1未満] は 1, [2 以上] は 2 +3 = 5

最後に

関連記事

Elasticsearch & OpenSearch の使い方
RAG (検索拡張生成)

参考文献

公式ドキュメント

Elasticsearch Guide [8.12] | Elastic