Redisモジュールの解説

Redis 4.0で追加されたモジュール機能により、ユーザがRedisの機能を自由に拡張することができます。

今回はRedisのモジュール機能で可能なことの解説、およびRedisのスポンサーであるRedis Labsや他のサードパーティにより公開されている様々なモジュールの紹介を行います。

Redisモジュールとは

Redisモジュールは、Redisに外部モジュールをロードすることで、Redis本体に手を入れることなく機能拡張できる仕組みです。モジュールは通常C/C++で実装されますが、技術的には他の言語でも実装可能です。

Redisモジュールで可能なこと

RedisモジュールではRedisに以下のような機能の拡張が可能です。新しいコマンドを呼び出したときに実行する処理をすべてモジュール側で実装することもできますし、Redisの機能を利用して実装することも可能です。

  • 新しいコマンドの作成
  • Redisの機能をモジュールから呼び出す
  • 新しいデータ型の作成
  • レプリケーション、クラスタにも対応できる (RDB、AOFの永続化処理を実装すればOK)

Redisモジュールのライセンス変更について

Redisのスポンサー企業であるRedis Labsが開発、提供するモジュールについてライセンスの変更が行われました。

対象は RediSearch, RedisGraph, RedisJSON, RedisML, RedisBloom などで、当初のAGPLから、(2018/8) Apache v2.0 modified with Commons Clause -> (2019/2) Redis Source Available License (RSAL)と2回の変更が行われました。これは大手クラウド業者などがRedisモジュールの機能をそのままサービスとして提供することで利益を得る、いわゆるフリーライドを防ぐ意図があります。

なお、Redis本体のライセンスには変更はありません(引き続き3条項BSDライセンスが適用されます)。他のRSALを適用していないモジュールや、ユーザーが実装するモジュールにも制限はありません。

RSALの制限事項

RSALライセンスではソースコードの利用・改変・再配布や、Redisモジュールを使ったサービスや製品の販売は認められています。ただし、以下の開発に使用することは禁止されています。

  • データベース
  • キャッシュエンジン
  • ストリーム処理エンジン
  • 検索エンジン
  • インデックスエンジン
  • 機械学習(ディープラーニング含む)、AIエンジン
  • RedisのAPIやRedis Modules APIを公開する製品やサービス

Redisモジュールの作り方

Redisモジュールをビルドするのに必要なものは、Redisの最新版ソースコードに含まれる redismodule.h のみと非常にシンプルです。ライブラリ等依存コンポーネントがないため、手軽に作成することができます。

Redisのソースコードは以下のページからダウンロードできます。通常はStableを使用してください。

https://redis.io/download

サンプルコード

helloworld.randコマンドを実行するとrand()で生成した乱数を返す単純なモジュールです。

#include "redismodule.h"
#include <stdlib.h>

int HelloworldRand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    RedisModule_ReplyWithLongLong(ctx, rand());
    return REDISMODULE_OK;
}

int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    if (RedisModule_Init(ctx, "helloworld", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    if (RedisModule_CreateCommand(ctx, "helloworld.rand", HelloworldRand_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    return REDISMODULE_OK;
}

コンパイル、配置、ロード

$ gcc --shared -fPIC helloworld.c -o helloworld.so
$ sudo cp helloworld.so /var/lib/redis/helloworld.so
$ redis-cli module load /var/lib/redis/helloworld.so
(設定ファイルに書く場合は /etc/redis.conf に以下を追加)
loadmodule /var/lib/redis/helloworld.so

実行

$ redis-cli
127.0.0.1:6379> helloworld.rand
(integer) 855445334
127.0.0.1:6379> helloworld.rand
(integer) 705120217

公開中のモジュールの紹介

ここではRedisモジュールの活用例として、Redis Modulesのページで公開されているモジュールの中から興味深いものについていくつか紹介します。

  • RediSearch: 全文検索
  • RedisAI/RedisML/neural-redis: 機械学習エンジン
  • RedisGraph: グラフDB

RediSearch

RediSearchはRedisに全文検索エンジンを追加するモジュールです。多言語に対応しており、中国語には対応していますが日本語には残念ながら未対応です(工夫により対応することは可能です)。RediSearchはRedis Labs社によりRSALライセンスで配布されています。

RediSearchのビルド手順は以下のようになります(RHEL7系の場合)。

$ sudo yum install cmake3 --enablerepo=epel
$ git clone https://github.com/RediSearch/RediSearch.git
$ cd RediSearch; mkdir build; cd build
$ cmake3 .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
$ make
$ sudo cp redisearch.so /var/lib/redis/
$ redis-cli module load "/var/lib/redis/redisearch.so"

簡単な使い方を以下に示します。

[スキーマを作成]
127.0.0.1:6379> ft.create myidx schema title text weight 5.0 body text url text

[ドキュメントを追加]
127.0.0.1:6379> ft.add myidx doc1 1.0 fields title "Hello World" body "This is a test document." url "http://localhost"

[検索]
127.0.0.1:6379> ft.search myidx "test" limit 0 10
1) (integer) 1
2) "doc1"
3) 1) title
2) "Hello World"
3) body
4) "This is a test document."
5) url
6) "http://localhost"

あらかじめ分かち書きを行っておくことで日本語も一応使うことが出来ます。

$ redis-cli --raw ※日本語UTF-8文字列をエスケープせずそのまま出力するため--rawを付加
127.0.0.1:6379> ft.create jpidx schema title text weight 5.0 body text title.orig text weight 0.0 body.orig text weight 0.0
127.0.0.1:6379> ft.add jpidx d2 1.0 fields title "日本語 の テスト" body "これは 試験 用 の 文章 です 。" title.orig "日本語のテスト" body.orig "これは試験用の文章です。"
127.0.0.1:6379> ft.search jpidx 日本語
1
d2
title
日本語 の テスト
body
これは 試験 用 の 文章 です 。
body.orig
これは試験用の文章です。
title.orig
日本語のテスト

neural-redis

neural-redisはRedisにニューラルネットワークによる機械学習エンジンを追加するモジュールです。以下のような特徴があります。

  • 非常にシンプルなAPI
  • 他のライブラリに依存せず単体で動作
  • データ自動正規化
  • 別スレッドによるバックグラウンド処理
  • 過学習検知付き自動トレーニング
  • Salvatore Sanfilippo (Redis開発者)が開発
  • 3条項BSDライセンス

他の機械学習・ディープラーニングエンジンとして、Redis Labs社により公開されているRedisMLおよびRedisAIがあります。

neural-redisのビルド手順は以下のようになります。

$ git clone https://github.com/antirez/neural-redis
$ cd neural-redis/
$ make sse
$ sudo cp neuralredis.so /var/lib/redis/
$ redis-cli module load "/var/lib/redis/neuralredis.so"

neural-redis (1) 回帰分析

入力データから数値の予測を行う問題の例として、足し算の答えの予測 (a + b = c)を行います。

ニューラルネットワークの作成
$ redis-cli
127.0.0.1:6379> NR.CREATE net REGRESSOR 2 3 -> 1 NORMALIZE DATASET 50 TEST 10
(integer) 13
学習データを投入
127.0.0.1:6379> NR.OBSERVE net 1 2 -> 3
127.0.0.1:6379> NR.OBSERVE net 4 5 -> 9
127.0.0.1:6379> NR.OBSERVE net 3 4 -> 7
127.0.0.1:6379> NR.OBSERVE net 1 1 -> 2
127.0.0.1:6379> NR.OBSERVE net 2 2 -> 4
127.0.0.1:6379> NR.OBSERVE net 0 9 -> 9
127.0.0.1:6379> NR.OBSERVE net 7 5 -> 12
127.0.0.1:6379> NR.OBSERVE net 3 1 -> 4
127.0.0.1:6379> NR.OBSERVE net 5 6 -> 11
トレーニング開始
127.0.0.1:6379> NR.TRAIN net AUTOSTOP
Training has started
トレーニング結果のテスト

比較的想定に近い結果が出ていることがわかります。

127.0.0.1:6379> NR.RUN net 1 1
1) "2.0505485534667969"
127.0.0.1:6379> NR.RUN net 4 6
1) "10.419864654541016"
127.0.0.1:6379> NR.RUN net 2 3
1) "4.8927350044250488"

neural-redis (2) 分類

入力データをグループ分けする問題の例として、neural-redisにサンプルとして付属しているタイタニック号の乗客の生存予測を行います。

モジュールに同梱されているサンプル
  • 入力パラメータ: 乗客の各種属性(チケットクラス、性別、年齢、兄弟・親子の乗船数、チケット料金)
  • 分類ラベル: 生存 or 死亡
付属のRubyスクリプトで学習データ(CSV形式)の投入とトレーニング
$ cd neural-redis/examples
$ ruby titanic.rb
Before training
185 prediction errors on 290 items
Still training...
After training
47 prediction errors on 290 items
トレーニング結果のテスト

ファーストクラス、女性、30歳、兄弟・親子なしの場合、95%の確率で生存という結果になりました

$ redis-cli
127.0.0.1:6379> NR.RUN mynet 1 0 0 0 1 30 0 0 200
1) "0.066139459609985352"
2) "0.94962334632873535"

年齢を70歳に上げた場合、95%から92.5%に減少しました。

127.0.0.1:6379> NR.RUN mynet 1 0 0 0 1 70 0 0 200
1) "0.08922017365694046"
2) "0.925819993019104"

70歳、サードクラス、格安チケットのように条件を悪くした場合、生存率が32%と大幅に減少しました。

127.0.0.1:6379> NR.RUN mynet 0 0 1 0 1 70 0 0 20
1) "0.6508185863494873"
2) "0.32001861929893494"

より高度な使い方はneural-redisのgithubページを参照してください。

RedisGraph

RedisGraphはRedisにグラフDB機能を追加するモジュールです。グラフDBはグラフ構造に特化したDBのことです。グラフDBとしてメジャーなNeo4jのグラフクエリー言語であるCypherを採用しており、Neo4jの利用経験があればすぐに使うことができます。
RedisGraphはRedis Labs社によりRSALライセンスで配布されています。

RedisGraphのビルドはやや複雑なため、ここではDockerイメージを使用して実行します。

# docker run -p 6379:6379 -it --rm redislabs/redisgraph

RedisGraphではGRAPH.QUERYコマンドに対してスキーマ名とCypherクエリー文字列を指定して使用します。簡単な使い方を以下に示します。

グラフを作成

例として人同士の関係をグラフとして作成してみます。以下はJohnの友人はFred、Lisaの友人はMaryという関係をグラフ化したものです。

$ redis-cli
127.0.0.1:6379> GRAPH.QUERY People
"CREATE (:Person {name:'John'})-[:friend]->(:Person {name:'Fred'}),
(:Person {name:'Lisa'})-[:friend]->(:Person {name:'Mary'})"
1) 1) "Labels added: 1"
2) "Nodes created: 4"
3) "Properties set: 4"
4) "Relationships created: 2"
5) "Query internal execution time: 3.208423 milliseconds"

クエリ実行

上記で登録した人同士の関係のグラフから、Fred の友人を検索してみます。

127.0.0.1:6379> GRAPH.QUERY People
"MATCH (p1:Person)-[:friend]->(p2:Person)
WHERE p2.name = 'Fred'
RETURN p1.name, p2.name"
1) 1) "p1.name"
2) "p2.name"
2) 1) 1) "John"
2) "Fred"
3) 1) "Query internal execution time: 0.326652 milliseconds"

条件にマッチした数をカウントすることもできます。以下ではMaryの友人の数をカウントしています。

127.0.0.1:6379> GRAPH.QUERY People
"MATCH (p1:Person)-[:friend]->(p2:Person {name:'Mary'})
RETURN count(p1)"
1) 1) "count(p1)"
2) 1) 1) (integer) 1
3) 1) "Query internal execution time: 0.290916 milliseconds"

まとめ

今回はRedisモジュールについて紹介しました。RedisモジュールによりユーザーがRedisに対して自由に機能拡張を行うことができます。HA機能を含むRedisの既存の機能を利用してRedisモジュールを実装することができるため、Redisコア機能の恩恵が得られます。

現在既に様々な高機能なRedisモジュールが提供されており、今後も新しいRedisモジュールの登場が期待できます。