11
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

メタップスアドベントカレンダー4日目の記事です。

最近OpenSearchと格闘しています。

OpenSearchとは?

OpenSearchとは、高速な検索エンジンです。 ログ分析やサイト内の検索機能の実装など、結構いろんなことができるみたいです。
ドキュメントDBにようにJSON形式のデータをインデックス内に格納します。

インデックス: 従来のDBで言うところの『テーブル』
ドキュメント: 従来のDBで言うところの『レコード』

OpenSearchとElasticSearchの違い

検索エンジンとして有名なツールにElasticSearchがあります。両者は使い方が非常に似ているのですが、それもそのはず。OpenSearchはElasticsearchからForkされる形で誕生しました。
その理由はライセンス問題です。Elastic Searchは有名な検索エンジンで、過去にOSSとして公開されていましたが、商用サービス化を制限するライセンスへ変更することを発表しました。OSSとしての使用を続けるべくAmazon主導でForkされました。OpenSearchとElasticSearchはその歴史的な経緯から似ていますが、versionが上がるにつれて、独自の機能や記法が追加されています。とはいっても、同じような感覚で使えるのではないでしょうか。私はOpenSearchで開発をしていても、ElasticSearchの記事を読んだりしています。

OpenSearchの環境構築をしてみる

OpenSearchはDockerで簡単に環境構築が可能です。
以下のDocker構成で試してみてくだされ
※ volumeは貼ってないので、必要なら追加してください。都度passwordを入力するのが面倒なため、セキュリティプラグインを無効化しています。

version: "3.8"
services:
  opensearch:
    image: opensearchproject/opensearch:latest
    container_name: opensearch
    environment:
      - DISABLE_SECURITY_PLUGIN=true
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    ports:
      - 9200:9200
      - 9600:9600
  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:latest
    container_name: opensearch-dashboards
    environment:
      - DISABLE_SECURITY_DASHBOARDS_PLUGIN=true
      - OPENSEARCH_HOSTS=http://opensearch:9200
    ports:
      - 5601:5601
    depends_on:
      - opensearch

簡単!

$ docker compose up -d

OpenSearchの操作方法

OpenSearchはHTTPベースでインデックス作成、データの投入、検索等が可能です。
curlコマンドやpostmanといった馴染みのツールで進めることもできますが、付属の専用dashbordを使うと便利です。
http://localhost:5601でdashboardを開くことができます

開いたら右上のDev Toolsを開いてください
名称未設定のデザイン.png

OpenSearch『インデックス』作成

今回は求人サイトの検索機能を作成する前提で『インデックス』を作成します。
インデックスは従来のDBでいうところのテーブルです。

以下をそのままダッシュボードに貼り付けて、右上のsend Rqeustボタンを押してください

PUT jobs
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "status": {
        "type": "keyword"
      },
      "created_at": {
        "type": "date",
        "format": "yyyy-MM-dd"
      },
      "updated_at": {
        "type": "date",
        "format": "yyyy-MM-dd"
      },
      "employee": {
        "properties": {
          "full_time": {
            "type": "integer"
          },
          "freelance": {
            "type": "integer"
          }
        }
      },
      "positon": {
        "type": "keyword"
      },
      "stack": {
        "type": "nested",
        "properties": {
          "type": {
            "type": "keyword"
          },
          "skill": {
            "type": "keyword"
          }
        }
      },
      "salary": {
        "properties": {
          "basic": {
            "type": "integer"
          },
          "benefits": {
            "type": "integer"
          }
        }
      }
    }
  }
}

以下のようなレスポンスが返ってきます

{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "jobs"
}

作成したindex構造を確認

GET jobs/_mapping

データの追加

opensearchはデータを一括でindexに追加する際は以下のような構成にする必要があります。

// データは改行なしにする必要があります。
{"index":{}}
{データ}
{"index":{}}
{データ}
{"index":{}}
{データ}

JSONの整形や操作にはjqがおすすめです。

以下をdashbordに貼り付けて実行

POST jobs/_bulk
{"index": {}}
{"id":"XJB8431","status":"active","created_at":"2024-04-12","updated_at":"2024-09-23","employee":{"full_time":30,"freelance":10},"positon":"backend","stack":[{"type":"backend","skill":"Rails"},{"type":"frontend","skill":"React"}],"salary":{"basic":40,"benefits":5}}
{"index": {}}
{"id":"XJF9652","status":"active","created_at":"2024-03-15","updated_at":"2024-09-20","employee":{"full_time":50,"freelance":15},"positon":"frontend","stack":[{"type":"frontend","skill":"Vue.js"},{"type":"frontend","skill":"TypeScript"},{"type":"backend","skill":"Node.js"}],"salary":{"basic":45,"benefits":8}}
{"index": {}}
{"id":"XJM7123","status":"inactive","created_at":"2024-05-01","updated_at":"2024-09-25","employee":{"full_time":20,"freelance":25},"positon":"mobile","stack":[{"type":"mobile","skill":"React Native"},{"type":"mobile","skill":"Swift"},{"type":"backend","skill":"Firebase"}],"salary":{"basic":42,"benefits":6}}

indexの中身を確認

GET jobs/_search

検索

statusがactiveな求人のみを検索

GET jobs/_search
{
  "query": {
    "match": { "status": "active" }
  }
}

求人作成日が2024-03-01 ~ 2024-04-31の間の求人を検索

GET jobs/_search
{
  "query": {
    "range": {
      "created_at": {
        "gte": "2024-03-01",
        "lte": "2024-04-31"
      }
    }
  }
}

stack.skillにReactがある求人を検索
mapping(index構造)でnestedしている場合は検索時もnestedであることを明示します

GET jobs/_search
{
  "query": {
    "nested": {
      "path": "stack",
      "query": {
        "match": {
          "stack.skill": "React"
        }
      }
    }
  }
}

求人がactiveでstack.typeにbackendがある(複数条件)
boolとfilterを使うのがポイント

GET jobs/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match": { "status": "active" }
        },
        {
          "nested": {
            "path": "stack",
            "query": {
              "match": {
                "stack.type": "backend"
              }
            }
          }
        }
      ]
    }
  }
}

集計

OpenSearchは検索したドキュメントに対して集計処理をすることもできます。
求人のid別にtotal_incomeとしてsalary.basic + salary.benefitsしてみます

GET jobs/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "result": {
      "terms": {
        "field": "id"
      },
      "aggs": {
        "total_income": {
          "sum": {
            "script": {
              "source": "doc['salary.basic'].value + doc['salary.benefits'].value"
            } 
          }
        }
      }
    }
  }
}

hits.hitsに検索対象のdocumentが、aggregationsに集計結果が格納されて返ってきます

終わりに

今回OpenSearchと格闘する上で有益だった記事を置いておきます。
先人達に感謝

11
1
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
11
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?