RedisでJSONドキュメントをインデックス化・クエリ・全文検索 ― RedisJSON 2.0とRediSearch 2.2の新機能
RedisJSONとRediSearchは、Redisのクラウドサービスにおいて最も人気のあるモジュールです。RedisJSONとRediSearch(Redisにバンドル)のDockerイメージは、毎日2,000回以上ダウンロードされています。4年前にテクノロジーエバンジェリストのItamar Haberが最初のバージョンを執筆した際、彼を先見者と呼ぶ理由がここにあります。4月にはRedisConfにおいて、JSON、インデックス作成、全文検索機能に関する複数の発表を行いました。そして本日、これらの機能のプライベートプレビューを発表できることを嬉しく思います。
この記事では、まず現在のRedisJSONの機能について概要を説明します。その後、今回のプライベートプレビューの新機能について詳しく掘り下げます。RediSearchを使ってJSONドキュメントのインデックス作成、クエリ実行、全文検索ができるようになったことが、今回のリリースで最も注目すべき新機能です。最後に、すぐに始めるための手順をご紹介します。
JSON機能とは
RedisJSONがない環境では、ネストされたドキュメントをStringデータ構造を使ってRedis上でモデル化する必要があります。
しかし、ドキュメントの一部だけを更新したい場合はどうすればよいのでしょうか?
操作の原子性(アトミック性)を保つためには、以下の手順が必要になります。
- WATCHコマンドでドキュメントを監視する
- 以前のバージョンを読み込んでデシリアライズする
- 更新内容をRedisトランザクションに組み込む
- JSONにシリアライズしてドキュメントを更新する
- トランザクションを実行する
この処理の間に別のクライアントがドキュメントを更新した場合、これらのステップ全体をやり直す必要があるかもしれません。
一方、RedisJSONを使えば、この更新をたった1つのアトミックなトランザクションで実行できます。
もう一つ例を見てみましょう。大きなJSONデータを扱っているが、アプリケーションで必要なのはそのごく一部だけ、というケースです。
RedisJSONなしの場合:
以下の手順が必要です。
- 文字列としてシリアライズされたJSON文字列全体を取得する
- JSONをデシリアライズする
- 必要な部分だけを抽出する
RedisJSONなら、必要なデータだけを1つのコマンドで取得できるため、CPUサイクル、ネットワークオーバーヘッド、そして何より重要なレイテンシを最小限に抑えられます。
このように、RedisJSONはJSONドキュメントの操作を大幅に簡素化します。現在GA版となっているRedisJSON(v1.0)は、コミュニティですでに広く利用されており、Stringデータ構造によるネスト構造のモデリングが抱える課題をまさに解決するものです。主な機能の概要は以下の通りです。
キーに関連付けてJSONドキュメントをRedisに保存(または更新)する
一部分の置換(例:あるキーの文字列値)
コレクションやマップへの要素追加
ドキュメント全体の抽出
JSONPathのサブセットを使った部分抽出
RedisJSON 2.0:プライベートプレビューリリース
このバージョンはRedisConf 2021で発表されました。本日、対象のRedis Enterprise顧客向けにプライベートプレビューとして、またコミュニティ向けにはリリース候補版(RC)として提供開始することをお知らせいたします。このバージョンには3つの主要機能があります。JSONPath式の完全サポート、Active-Active対応(Redis Enterprise)、そしてRediSearchによるJSONドキュメントのインデックス作成・クエリ・全文検索機能です。さらに、それ以外にも多数の新機能があります。それでは詳しく見ていきましょう。
Rustによる書き直し
システムプログラミング言語は、効率性を重視した言語群です。これらの言語で書かれたプログラムは一般に軽量で、最高のパフォーマンスを発揮します。Redisが歴史的にC言語で書かれてきたのはこのためであり、極めて低いレイテンシと高いスループットを実現できている理由もここにあります。ほとんどのRedisモジュールも、同じ系統の言語であるC、C++、Rustで書かれています。
JSONはRustコミュニティによって特に充実したサポートを受けており、非常に高速かつ効率的なJSONシリアライゼーションやJSONPath実装が提供されています。これらの実装の恩恵をRedisユーザーに届けることは自明であり、RedisモジュールAPIとRustの間のマッピングを作成するだけで実現できました。
JSONPathの完全サポート
これこそがRustによる書き直しの成果です。新しいバージョンではJSONPathを包括的にサポートしており、JSONPath式の全表現力を活用できるようになりました。
ワイルドカード(以前は最初の要素のみに制限されていました)
スライスの抽出
フィルター式を使ったより高度な例
Active-Activeのサポート
Active-ActiveはRedis Enterpriseが提供する機能です。地理的に分散した複数のRedis Enterpriseクラスタへデータベースをレプリケーションでき、ユーザーは最寄りのクラスタに接続することで、ローカル並みの読み書きレイテンシを実現できます。
この実装は、コンフリクトフリーレプリケーテッドデータタイプ(CRDT)技術に基づいています。Redisがサポートする主要なデータ構造の多くにこの技術を実装する中で培われた確かな知識と経験が、今回のJSON向け実装によって証明されました。
アプリケーション開発者は、この機能を活用してJSONドキュメントを使った地理分散アプリケーションを構築できるようになりました。以下は、2つのクラスタを持つActive-Active環境での一連の操作例です。
- T1: クライアントがクラスタ1にJSONドキュメントをセットする。
- T2: 同期プロセスがそのドキュメントをクラスタ2にレプリケートする。
- T3: 両クラスタに同一のドキュメントが存在する状態になる。
- T4: クラスタ1であるクライアントがcolors配列に「blue」を追加し、同時にクラスタ2では別のクライアントが同じ配列に「green」を追加する。
- T5: 同期プロセスが操作をマージし、両クラスタのドキュメントを更新する。
- T6: 両クラスタに同一のドキュメントが存在する状態に戻る。
同期フローの詳細については、パブリックプレビューの際に詳しく解説する予定ですが、この機能に興味がある方は、今すぐsupport@redis.comまでお気軽にお問い合わせください。
RediSearch 2.2:プライベートプレビューリリース
この記事では、RediSearch 2.2のプライベートプレビュー提供開始もお知らせします(対象のRedis Enterprise顧客向けにはプライベートプレビューとして、コミュニティ向けにはリリース候補版として提供されます)。
このセクションでは、RediSearchの新版がもたらす新機能について説明します。まず、なぜ2つの人気モジュールを同時にリリースするのか、その理由をご紹介しましょう。
JSONドキュメントのインデックス作成、クエリ、全文検索
この新機能により、RedisのJSON機能はまったく新しいレベルに到達します。従来、RediSearchはハッシュに対してインデックス作成と検索機能を提供してきましたが、それはキーバリューストアの枠を超えるものではありませんでした。内部構造としては、RedisJSON 2.0が内部パブリックAPIを公開しています。「内部」というのは、このAPIがRedisノード内で動作する他のモジュールに対して公開されているという意味であり、「パブリック」というのは、どのモジュールでもこのAPIを利用できるという意味です。そして、RediSearch 2.2もまさにこのAPIを利用しています!
RedisJSONが他のモジュールへ機能を公開することで、RediSearchはJSONドキュメントをインデックス化できるようになり、ユーザーはコンテンツをインデックス化してクエリすることでドキュメントを検索できるようになりました。これら2つのモジュールの組み合わせにより、強力で低レイテンシなJSON指向ドキュメントデータベースが手に入ります!
実際にどのような動作になるのか見てみましょう。
まず、JSON.SETコマンドを使ってJSONドキュメントをデータベースに登録します。
新しいインデックスを作成するには、FT.CREATEコマンドを使用します。インデックスのスキーマはJSONPath式を受け付けられるようになり、式の評価結果が属性(ここではtitle)に関連付けてインデックス化されます。
これで、FT.SEARCHを使って検索クエリを実行し、目的のJSONドキュメントを見つけられるようになりました。
JSONドキュメントに対する集計処理
集計(Aggregation)はRediSearchの強力な機能の一つで、分析レポートの作成やファセット検索スタイルのクエリに活用できます。RediSearchがJSONドキュメントにアクセスできるようになったことで、JSONPath式を使ってJSONドキュメントから任意の値を取り出し、それがインデックス化されているかどうかにかかわらず、パイプラインで利用できるようになりました。
まずインデックスを作成し、次にJSONドキュメントをデータベースに追加します。そして、JSONドキュメントから抽出した2つの数値を使って簡単な計算を実行できます。
より柔軟なインデックス戦略
新版のRediSearchでは、同じ値(ハッシュのフィールドやJSONドキュメントの値)を異なるパラメータでインデックス化できるようになりました。この新機能が解決する典型的なユースケースを紹介します。
カテゴリに属するドキュメントを含むデータベースを想定してください。
TAG型を使えば、任意のカテゴリで検索結果を簡単に絞り込めます。
しかし、カテゴリに対して全文検索も実行したい場合はどうでしょうか?
従来のハッシュでは、同じ値を2つのフィールドに複製する必要があり、メモリを2倍消費していました。
そこで便利なのがFT.CREATE…ASです。先ほどのシンプルなドキュメントに戻って、新しいAS機能を使うと、TAGによるフィルタリングと同じフィールドへの全文検索を、データを複製することなく両方実現できます。
クエリプロファイリング
ほとんどのRedisコマンドの計算量は十分にドキュメント化されています。例えばHMGETの計算量はO(N)で、「Nはリクエストされたフィールドの数」です。RediSearchでは高度なクエリを記述できますが、FT.SEARCHやFT.AGGREGATEコマンドの計算量はクエリの複雑さに依存します。
そこで私たちは、クエリ実行時に内部で何が起きているのかを把握し、どこに時間が費やされているのか、そしてクエリをどう最適化できるのかを理解するためのツールを提供したいと考えました。新しいFT.PROFILEコマンドは、RediSearchがクエリを実行する際の主要なステップを示すツリーを返し、各ステップの所要時間情報を提供します。
例えば、あいまい検索(fuzzy search)を含むクエリを実行したとき、RediSearchの内部では何が起きているのでしょうか?
実際にプロファイリングを実行して結果を分解してみましょう。
redis.cloud:6379> FT.PROFILE idx SEARCH LIMITED QUERY "%hello%"
最初に結果が返されます。プロファイリング対象のクエリが期待通りの結果を返しているか確認するのに役立ちます。
次に総時間(「profile time」)が表示されます。これはプロファイル情報の収集にかかった時間も含まれるためです。
クエリの解析と実行プランの構築に費やされた時間:
辞書からあいまい一致を検索するのに費やされた時間:
そして最後に、検索結果の構築が何を意味するのか考えたことはありますか?各ドキュメントの全文検索スコアを計算し、スコア順にソートし、最後にフィールドを読み込む必要があります。この情報を活用すれば、ボトルネックを特定し、クエリを高速化し、サーバーのパフォーマンスを向上させることができます。
はじめ方
私たちは、これらの新機能がアプリケーション開発者とRedisコミュニティにとってゲームチェンジャーになると確信しています。始め方は以下の通りです。
プレビュー用Dockerイメージを使用する
:previewタグ付きのDockerイメージをプルして始めることができます。
docker run -p 6379:6379 redis/redismod:preview
あるいは、両リポジトリのRC1リリースタグ(RediSearchはv2.2.0、RedisJSONはv2.0.0)からソースをコンパイルし、Redisにロードすることも可能です。
セットアップが完了したら、上記のコマンドをすべて試すか、クイックスタートガイドを参照してください。また、RedisConf 2021の基調講演で紹介したオンライン小売アプリケーションRedisMartに関する一連のブログ記事も公開予定です。RedisMartは、地理分散配置されたRediSearchとRedisJSONを活用し、最高のオンライン小売体験を提供します。このシリーズでは、このアプリケーションの構築方法を段階的に解説していきます。
互換クライアントの最新版で開発する
以下のクライアントライブラリは現在アップグレード作業中で、優れた開発者体験のもとで新機能を利用できるようになります。最新のリリースやプルリクエストを確認してください(現時点では、多くがmasterブランチでプレビュー版に対応しています)。
| RedisJSON | RediSearch | |
| Node.js | redis-modules-sdk | redis-modules-sdk |
| Java | JredisJSON | JRediSearch |
| .NET | NRedisJSON | NRediSearch |
| Python | redisjson-py | redisearch-py |
コミュニティに参加する
General Availability(GA)に向けて開発を進めるにあたり、フィードバック、バグ報告、機能リクエストを歓迎します。ドキュメントサイトや、GitHub上のRediSearchおよびRedisJSONのリポジトリにフィードバックをお寄せいただくか、Discordでお気軽にお問い合わせください。
-
Flutter、Serverless Framework、Upstash(Redis)で構築するフルスタックサーバーレスアプリ 第2部
チュートリアルシリーズ第2部へようこそ。第1部では、UpstashとServerless Framework、Redisを使ってREST APIを構築する方法を解説しました。 この第2部では、そのREST APIのエンドポイントを利用するモバイルアプリケーションをFlutterで構築していきます。 それでは始めましょう 🙃 事前準備 まず、お使いのコンピュータにFlutterがインストールされ、正常に動作している必要があります。 Flutter IDEで新しいFlutterプロジェクトを作成し、任意の名前を付けてください。 依存パッケージの追加 プロジェクトのルートディレクトリにあるpu
-
Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート1
この投稿では、データを保存するためのFlutter、Serverless Framework、Upstash、Redisを使用してサーバーレスモバイルアプリケーションを構築します。 Upstashとは? Upstashは、Redis用のサーバーレスデータベースです。 Upstashを使用すると、リクエストごとに支払います。これは、データベースが使用されていないときに課金されないことを意味します。 Upstashはデータベースを構成および管理します。これは、DynamoDBやFaunaなどの他のデータベースの強力な代替手段であり、などの利点があります。 低レイテンシ REDISAPIと同