- 大江聖太郎
- 約 2,600 文字
- 1,100 View
目次
はじめに
はじめまして。2023年秋入社した、Technology Innovation Group (TIG) 大江聖太郎です。
ElasticsearchからOpenSearchに移行した際のGo用クライアントの実装についてまとめます。
背景
ElasticsearchからOpenSearchへ移行した際に、利用するGoのクライアントもElasticsearch用のものからOpenSearch用に変更しました。
このクライアントに関しては実装例が少なく、公式ドキュメントも情報が足りない印象を受けました。時にはどのような型のデータを入れていいかドキュメントを見ても分からず、クライアントのリポジトリのコードを読み、ようやく分かったということもありました。
そんな苦労がありましたので、少しでもお役に立てればという思いから実装例を紹介していきます。
使用するクライアント
- 今まで使っていたクライアント: olivere/elastic
- 今回新たに使うクライアント: opensearch-go
各メソッド
それでは、各メソッドの実装の違いについて詳しく見ていきましょう。
この記事では分量を少なくする目的で、ステータスコードのエラーハンドリングの章を除き、エラーハンドリングを全て握りつぶして記載します。
追加/更新系メソッド
Index
Indexメソッドは、OpenSearchにおいてデータをIndex1に登録し、既に既存のデータがある場合は上書きする処理です。RDSにおけるUpsertのようなものです。
olivere/elasticの実装
package main |
opensearch-goの実装
package main |
Update
Updateはその名の通り既に存在するドキュメントを更新する操作です。
ドキュメントを更新する際、IndexとUpdateのどちらを使用するのが適切かは、次の三点の違いを考慮すると良いでしょう。
- 内部の動作として、Indexは今あるドキュメントを削除して新しいドキュメントに置き換える一方、Updateはドキュメントの特定のフィールドのみを更新する
- 特にドキュメントに変更点がない場合、Indexはバージョンがインクリメントされるが、Updateはされない
- Updateの方がパフォーマンス面では優れている
olivere/elasticの実装
package main |
opensearch-goの実装
package main |
実装方法の違い
パラメーターは同じですが、大きな違いとして4点あります。
- ドキュメントの渡し方
- olivere/elasticでは、ドキュメントがinterface{}型で渡せたので、Goの構造体をそのまま渡すことが出来ましたが、opensearch-goではio.Reader型を満たす型に変換する必要があります。例では*bytes.Reader型に変換しています
- 引数の記述方法
- olivere/elasticではメソッドチェーンで書くことが出来ましたが、opensearch-goではIndex()のパラメーターとして記述します
- olivere/elasticはDo()メソッドを明示的に呼び出して操作を適用しますが、opensearch-goはIndex()メソッドが自動的にDo()を実行する設計となっています
- opensearch-goではアップデートするフィールドと値を、”doc”フィールドの中に入れてネストする必要があります。olivere/elasticの方ではそのようにする必要はないです
取得系メソッド
GET
Getは、特定の1つのドキュメントを取得する操作です。
olivere/elasticの実装
package main |
opensearch-goの実装
package main |
SEARCH
Searchは、クエリパラメーターを渡し、特定の条件に当てはまるドキュメントのリストを取得する操作です。
olivere/elasticの実装
package main |
opensearch-goの実装
package main |
実装方法の違い
- olivere/elasticでは取得したドキュメント本体がそのまま*json.RawMessage型のレスポンスで返るのに対し、opensearch-goではドキュメント本体以外にSeqNoやPrimaryTermを含むio.ReadCloser型の構造体として返る。そのためopensearch-goではアプリ側でレスポンスをjson.Decoderを使ってDecodeした上で、そこからドキュメント本体を抜き出す必要がある
- queryStringを渡す際、olivere/elasticの場合はNewQueryStringQueryを呼び出し、elastic.QueryStringQueryの構造体にする必要がある。opensearch-goの場合はWithQueryにそのまま渡せる
- ソートフィールドを渡す時、olivere/elasticの場合はSort項目用に[]elastic.Sorter型が用意されていて、SortByに[]elastic.Sorter型の構造体を渡せばよい。一方opensearch-goの場合はそもそもソートフィールド用の型が用意されていないため、自前の構造体を作成し、WithBodyの形で渡す必要がある
ステータスコードのエラーハンドリング
olivere/elasticの実装
package main |
opensearch-goの実装
package main |
実装方法の違い
ドキュメントが見つからなかったとき、登録に失敗したときなど、Elasticsearch/OpenSearchから400や404のステータスコードでのエラーが返ってきますが、その際に以下の違いがあります。
- olivere/elasticでは返り値のerrとして返るのでそれを見ればよいが、opensearch-goではステータスコードのエラーはレスポンスの中に含まれており、レスポンスの中身を見て判断する必要がある
おわりに
ElasticsearchのクライアントとOpenSearchのクライアントの違いについてまとめました。
ElasticsearchからOpenSearchへ切り替えるときなどにお役に立てれば幸いです。
どちらのクライアントも一長一短あり、やりたいことによっては一工夫する必要があることが分かりました。個人的には、あまりこねくり回すことなくビジネスロジックに集中できるライブラリが出来たらいいなと感じました。