はじめに
Heroku では Redis という DB が公式で提供されています。
キーバリュー型データストア Redis をクラウドで | Heroku
これは SQL やテーブル設計が不要なデータベースで、
例えば Python の場合、以下のように手軽に扱えます。
>>> conn.set('タイトル', 'Redisで始めるDB入門') # データの格納
True
>>> conn.get('タイトル') # データの取得
'Redisで始めるDB入門'
この記事では Redis の導入方法から、基本的な使い方までを紹介します。
データの永続化とデータベースの基本
興味があれば読んでください(クリックで開く)
消えたら困るデータをどこかに保存しておかなければならない
というのは、プログラミングを続ける上で直面しやすい問題です。
変数はプログラムが終了すると消えてしまいますからね。
そのようなデータの保存は一般的に データの永続化
と呼ばれ、主に
JSONなどのファイルにテキストとして保存する方法と、
データベース管理システム(DBMS)
を利用する方法があります。
単純なデータの保存であればファイル管理でも良いのですが、
複雑なデータ構造を扱う場合や、複数人が同時に操作するような場面だと難しく、
データ管理に特化した DBMS の方が扱いやすくなります。
また、Herokuでは基本的にファイルを一時的にしか保存できないため、
DB を利用せざるを得ない場面も多いと思います。
この記事では簡単のため、 DBMS もまとめて DB と表記します。
DBの種類
いくつかありますが、主なカテゴリの RDB
と NoSQL
の2種類を紹介します。
RDB
関係データベース(Relational DataBase)
の略で、MySQL や PostgreSQL など、
世の中で使われている DB や解説されている DB の多くは RDB です。
初学者にとっては、SQLの学習コストやテーブル設計の難しさが壁になります。
Heroku では PostgreSQL が公式 Add-on で提供されています。
Postgres - SQL データベース・サービス | Heroku
NoSQL
NoSQL
は(No SQLではなく) Not only SQL
の略で、
SQL を使わずに、Pythonの文字列やリストなどを扱うような感覚で、
シンプルにデータを管理できるという魅力があります。
NoSQL
というカテゴリの中にも様々な種類があり、
例えば MongoDB は ドキュメント型
で、Neo4j は グラフ型
です。
今回使う Redis は キーバリュー型(Key-Value-Store : KVS)
です。
Redis
オンメモリで読み書きが高速、永続化も可能な KVS です。
主にキャッシュのために使われることが多いですが、
最近ではランキングデータに使われるという話もよく見かけます。
String
List
Set
Hash
SortedSet
などの
様々なデータ型をサポートしています。
An introduction to Redis data types and abstractions – Redis
Heroku Redis の初期設定
Heroku のアカウント登録、アプリ作成、クレカ登録は以下から済ませておいてください。
プラン毎の定額課金方式のため、予期せぬ請求の心配はないです。
Heroku Redis の Free プランは25MBが上限で、
自動バックアップは対応していないという制限があります。
障害などでデータが失われるリスクがある点は留意しておいてください。
参考:Heroku Redisについてまとめてみた - Qiita
Heroku Redis のインストール
以下から、作成したアプリに Heroku-Redis をインストールします。
Heroku Redis - Add-ons - Heroku Elements
右上の Install Heroku Redis
をクリック。
Add-on plan
が Hobby Dev - Free
になっていることを確認してから、
App to provision to
に作成したアプリ名を入力し、
Provision add-on
をクリックすると、2~3分程でインストールが完了します。
REDIS_URLの確認
インストールが完了すると、Dashboard->Settings->Config Vars に
環境変数 REDIS_URL
が設定されています。Redisに接続する際に使います。
このURLは絶対に外部に公開しないでください。
使用状況の確認
Dashboard の Overview または Resources の Heroku Redis
から、
使用状況を確認することができます。
Pythonで操作する
以下の内容は python3.8.0
と redis-py 3.3.11
で動作確認しています。
参考リンク(クリックで開く)
redis-py のインストール
簡単に操作を行うためのライブラリを導入します。
ローカルで試す場合は以下をターミナル(コマンドプロンプト)で実行してください。
python3 -m pip install --upgrade pip # 念の為実行しておく
python3 -m pip install redis # redis-pyのインストール
Heroku 上で実行する場合は requirements.txt
に redis
を追加する必要があります。
redis==3.3.11
Redisに接続する
ここで環境変数 REDIS_URL
を使います。
Heroku上で実行する場合はそのままで大丈夫ですが、
ローカルで実行する場合は設定しておくか、redis://~
を直接書いてください。
まず接続用のモジュールを用意しておきます。
import redis
import os
def connect():
return redis.from_url(
url=os.environ.get('REDIS_URL'), # 環境変数にあるURLを渡す
decode_responses=True, # 日本語の文字化け対策のため必須
)
以下、これをPythonインタプリタで使っていきます。
※ コマンドプロンプトに python3
や py -3
と入力すると立ち上がる実行環境
$ python3
>>> import r
>>> conn = r.connect() # このconnを通じて操作する
基本操作
Redis では 1つのKey に 1つのValue が紐付くという形が基本です。
Keyは必ず文字列ですが、Valueは文字列以外の指定も可能です。
ただしデータ型によって使うメソッドが異なります。
文字列型データの格納
set()
メソッドに Key と Value を指定して格納します。
例えば、Key が タイトル
で Value が Redisで始めるDB入門
の場合は
>>> result = conn.set('タイトル', 'Redisで始めるDB入門')
>>> print(result)
True # 格納に成功すると True
という形になります。
文字列型データの取得
get()
メソッドにKeyを指定して取得します。
>>> result = conn.get('タイトル')
>>> print(result)
'Redisで始めるDB入門' # Keyに紐付くValueが返る
また、引数に存在しない Key を指定した場合は
>>> result = conn.get('title')
>>> type(result)
<class 'NoneType'>
のように None が返ります。エラーは発生しません。
Keyの存在確認
Key が登録されているかを確認するには exists()
メソッドを使います。
>>> conn.exists('タイトル')
1
exists メソッドの引数には複数のKeyを指定することが可能で、
そのうち登録されているKeyの数が返ってきます。
>>> conn.exists('title', 'id', 'tag')
0 # 指定したKeyは全て登録されていないので
各操作の前にこのメソッドで確認しておくと安全です。
Keyの一覧を取得
今現在どの Key が格納されているかを確認するには keys()
メソッドを使います。
>>> conn.keys()
['タイトル']
Keyの変更
Key を別の文字列に変更したい場合は rename()
か renamenx()
メソッドを使います。
第1引数に変更前の Key を、第2引数に変更後の Key を指定します。
>>> conn.rename('タイトル', 'title')
True # 変更に成功
>>> conn.renamenx('title', 'タイトル')
True # 変更に成功
これらは変更先の文字列が存在する場合に挙動が変わります。
>>> conn.set('title', '変更しないでね') # 変更先のKeyを登録
True
>>> conn.renamenx('タイトル', 'title')
False # 変更できない
>>> conn.rename('タイトル', 'title')
True # 上書きしてしまう
>>> conn.get('title')
'Redisで始めるDB入門' # 'タイトル' に紐付いていた Value
>>> conn.get('タイトル')
None # 変更前のKeyは消滅している
Keyの削除
Key を削除したい場合は delete()
メソッドを使います。紐付く Value も消えます。
複数の Key を指定可能で、削除に成功した Key の数が返ります。
>>> conn.delete('title')
1
また、全ての Key を削除したい場合は flushdb()
メソッドを使います。
>>> conn.flushdb()
True
集合型の場合
Redisで扱えるデータ型には様々ありますが、
特に便利な集合型(Set)について特筆します。
Redis の集合型は Python の集合型と同様の性質で、
要素の重複が許されない順不同な集合データです。
集合型データの格納・取得
文字列型では set()
と get()
を使いましたが、
集合型では sadd()
と smembers()
を使います。
>>> conn.sadd('タグ', 'Heroku', 'Redis')
2 # 追加できた要素の数が返る
>>> conn.smembers('タグ')
{'Redis', 'Heroku'} # 順不同なので追加した順番と違う
sadd()
は第一引数に Key を、第二引数以降に集合型データの要素を指定します。
集合型データに要素を追加・削除
要素の追加にも sadd()
を使います。
>>> conn.sadd('タグ', 'Python')
1
>>> conn.smembers('タグ')
{'Redis', 'Heroku', 'Python'}
ただし、既にある要素は追加できません。
>>> conn.sadd('タグ', 'Redis', 'redis-py')
1 # 'redis-py' は追加されるが 'Redis' は重複するので追加されない
>>> conn.smembers('タグ')
{'Redis', 'Heroku', 'redis-py', 'Python'}
要素の削除には srem()
を使います。
>>> conn.srem('タグ', 'Heroku', 'Redis')
2
>>> conn.smembers('タグ')
{'redis-py', 'Python'}
Key の削除は文字列型と同様に delete()
メソッドを使います。
その他のデータ型や操作について
記事にはまとめきれない多くのデータ型や操作があります。
それらは公式リファレンスに記載されています。
Welcome to redis-py’s documentation! — redis-py 2.10.5 documentation
そして redis-py で使えるメソッド名は Redis 公式のコマンド名に準拠しています。
Command reference – Redis
ただし del
は Python の予約語と衝突するので delete
になっています。
また、様々な疑問を自力で解決するのは難しいので、
Python や各種技術に関する情報交換ができるコミュニティを紹介しておきます。
Python.jp Discordサーバ - python.jp
最後に
大規模なシステムで全てのデータを NoSQL で管理するのは狂気の沙汰です。
いずれは RDBMS の偉大さを学んでください。
また、上記の内容を活用した例を紹介しているので、
興味があれば読んでみてください。
NoSQL×PaaSで運用するナレッジベース+WebAPI - Qiita