1.Pythonアクセスと操作 リレーショナルデータベース実戦
1.リレーショナルデータベース
リレーショナル データベースは、長い間、データの保存と操作の標準でした。テクノロジーは成熟しており、どこにでもあります。
Python はさまざまなリレーショナル データベースに接続できますが、Python はすべてのデータベースをほぼ同じ方法で処理するため、ここではデータベースの 1 つである sqlite3 を使用して基本原理を示し、選択および使用する際のいくつかの違いと注意事項について説明します。データ ストレージの問題のリレーショナル データベース。
2. sqlite3 データベースの使い方
Python にはさまざまなデータベース用のモジュールが多数用意されていますが、次の例では sqlite3 のみを紹介します。大規模でトラフィックの多いアプリケーションには適していませんが、sqlite3 には 2 つの利点があります。
sqlite3 は標準ライブラリの一部であるため、依存関係の追加を心配することなく、データベースが必要な場所ならどこでも使用できます。
sqlite3 はすべてのレコードをローカル ファイルに格納するため、PostgreSQL、MySQL、およびその他の大規模データベースで必要となるクライアント側とサーバー側の必要はありません。
上記の機能により、sqlite3 は小さなアプリケーションやラピッド プロトタイピング システムに便利な選択肢となります。
sqlite3 データベースを使用するには、最初に Connection オブジェクトが必要です。connect 関数を呼び出して Connection オブジェクトを取得するだけです。パラメータは、データの保存に使用するファイル名です。
>>> import sqlite3
>>> conn = sqlite3.connect("datafile.db")
ファイル名として「:memory:」を使用することもできるため、データはメモリに保存されます。Python の整数、文字列、浮動小数点数を格納する場合、他のパラメーターは必要ありません。
sqlite3 で一部の列のクエリ結果を他の型に自動的に変換する場合は、detect_types パラメータを使用すると便利です. sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES に設定すると、Connection オブジェクトをクエリ ステートメントを解析し、それらをカスタム コンバーターと一致させようとします。
2 番目のステップは、Connection から Cursor オブジェクトを作成することです。
>>> cursor = conn.cursor()
>>> cursor
<sqlite3.Cursor object at 0xb7a12980>
この時点で、データベースを照会できます。この場合、データベースにはまだテーブルやレコードがないため、最初にテーブルを作成していくつかのレコードを挿入する必要があります。
>>> cursor.execute("create table people (id integer primary key, name text,
count integer)")
>>> cursor.execute("insert into people (name, count) values ('Bob', 1)")
>>> cursor.execute("insert into people (name, count) values (?, ?)",
... ("Jill", 15))
>>> conn.commit()
最後の挿入ステートメントは、変数を使用してクエリを作成するための推奨される方法を示しています。ここでは、クエリ文字列を作成する代わりに、より安全な "?" を使用して各変数を表し、複数の変数を 1 つのタプルにまとめて、パラメーターとして execute メソッドに渡します。これの利点は、エラーのエスケープについて心配する必要がなく、sqlite3 がそれを処理することです。
「:」接頭辞が付いた変数名もクエリで使用できます。渡される変数は、挿入される対応する値を含む辞書になります。
>>> cursor.execute("insert into people (name, count) values (:username, \
:usercount)", {"username": "Joe", "usercount": 10})
テーブルにデータを入力した後、SQL コマンドを使用してデータをクエリするか、「?」を使用して変数バインディング関係を表すか、変数名と辞書を使用できます。
>>> result = cursor.execute("select * from people")
>>> print(result.fetchall())
[('Bob', 1), ('Jill', 15), ('Joe', 10)]
>>> result = cursor.execute("select * from people where name like :name",
... {"name": "bob"})
>>> print(result.fetchall())
[('Bob', 1)]
>>> cursor.execute("update people set count=? where name=?", (20, "Jill"))
>>> result = cursor.execute("select * from people")
>>> print(result.fetchall())
[('Bob', 1), ('Jill', 20), ('Joe', 10)]
利用可能な fetchall メソッドに加えて、fetchone メソッドはクエリ結果からデータの行を取得でき、fetchmany は任意の数のデータ行を返すことができます。便宜上、ファイルの反復処理と同様に、カーソル オブジェクト内のデータ行を反復処理することもできます。
>>> result = cursor.execute("select * from people")
>>> for row in result:
... print(row)
...
('Bob', 1)
('Jill', 20)
('Joe', 10)
デフォルトでは、sqlite3 はトランザクションをすぐにはコミットしません。これは、トランザクションが失敗したときにトランザクションをロールバックすることを選択できることを意味しますが、すべての変更が確実に保存されるように Connection オブジェクトの commit メソッドを使用する必要があることも意味します。close メソッドはアクティブなトランザクションを自動的にコミットしないため、データベース接続を閉じる前にコミットすることをお勧めします。
>>> cursor.execute("update people set count=? where name=?", (20, "Jill"))
>>> conn.commit()
>>> conn.close()
一般的な sqlite3 データベース操作:
操作する | sqlite3 コマンド |
データベース接続の作成 | conn = sqlite3.connect(ファイル名) |
データベース接続にカーソルを作成する | カーソル = conn.cursor() |
カーソルを介してクエリを実行 | カーソル.execute(クエリ) |
クエリ結果を返す | cursor.fetchall()、cursor.fetchmany(num_rows)、cursor.fetchone() カーソル内の行:.... |
トランザクションをデータベースに送信します | conn.commit() |
データベース接続を閉じる | conn.close() |
通常、上記の操作で sqlite3 データベースを操作するだけで十分です。
3. MySQL、PostgreSQL およびその他のリレーショナル データベースの使用
前述のように、他のいくつかの SQL データベースでは、DB-API 仕様に準拠したクライアント ライブラリが提供されています。したがって、Python でこれらのデータベースにアクセスする方法は非常に似ていますが、注意すべき違いがいくつかあります。
- SQLite とは異なり、これらのデータベースには、クライアントが接続するためのデータベース サーバーが必要です。クライアントとサーバーは同じマシン上にある場合もあれば、異なるマシン上にある場合もあるため、データベース接続には、通常、ホスト、アカウント名、パスワードなど、より多くのパラメーターを運ぶ必要があります。
- 「select * from test where name like:name」のようなクエリにパラメーターを挿入する方法は、?、%s5(name)s などのように、異なる形式を使用する場合があります。
上記の変更は大きなものではありませんが、異なるデータベース間でコードを完全に移植することを妨げる傾向があります。
4. ORM を使用してデータベース操作を簡素化する
前述の DB-API データベース クライアント ライブラリにはいくつかの問題があり、生の SQL ステートメントを記述する必要があることにも問題があります。
- SQL データベースが異なれば、SQL の実装もわずかに異なるため、あるデータベースから別のデータベースに移行する場合、同じ SQL ステートメントが常に機能するとは限りません。ローカル開発が sqlite3 で行われ、本番環境で MySQL または PostgreSQL が使用される場合、この種の移行要件が発生する可能性があります。また、前述のように、データベース製品が異なれば、クエリ ステートメントにパラメーターを渡す方法など、実装方法も異なります。
- 2 つ目の欠点は、生の SQL ステートメントを使用する必要があることです。コードに SQL ステートメントを含めると、特にコード サイズが大きい場合は、保守が難しくなります。この時点で、これらのステートメントの一部はテンプレートやルーチン プロシージャになりますが、その他は非常に複雑で扱いにくいものになります。また、すべてのステートメントをテストする必要があり、面倒になる可能性があります。
- SQL を記述する必要があるということは、Python とある種の SQL の少なくとも 2 つの言語を考慮する必要があることを意味します。多くの場合、生の SQL は問題を起こす価値がありますが、他の多くの場合はそうではありません。
上記の問題を考慮すると、人々はデータベースを扱うためのより管理しやすい方法を備えた Python を必要とし、通常の Python コードを記述するだけで済みます。このソリューションは、リレーショナル データベースのデータ型とデータ構造を Python オブジェクトに変換またはマップするオブジェクト リレーショナル マッパー (ORM) です。
Python の世界では、最も一般的な 2 つの ORM は Django ORM と SQLAlchemy ですが、他にも多くの ORM があります。Django ORM は Django Web フレームワークと緊密に統合されており、通常、外部で単独で使用されることはありません。ここで注意すべきことは、Django ORM が Django アプリケーションのデフォルトのオプションであり、十分に開発されたツールと豊富なコミュニティ サポートを備えていることです。
1. SQLアルケミー
SQLAlchemy は、Python の世界でもう 1 つの有名な ORM です。SQLAlchemy の目標は、開発者がデータベースを制御し、基礎となる SQL にアクセスできるようにしながら、時間のかかるデータベース タスクを自動化し、データへの Python オブジェクト ベースのインターフェイスを提供することです。以下は、リレーショナル データベースにデータを格納し、SQLAlchemy で取得する基本的な例です。
SQLAlchemy は、pip を使用して Python 環境にインストールできます。
> pip install sqlalchemy
注: SQLAlchemy および関連ツールを使用するという観点からは、同じ仮想環境で 2 つのシェル ウィンドウを開く方が便利です。1 つは Python 用で、もう 1 つはシステム コマンド ライン用です。
SQLAlchemy には、データベースやテーブルと対話する方法がいくつか用意されています。ORM では必要に応じて SQL ステートメントを作成することもできますが、ORM の機能はまさにその名前が示すとおりです。つまり、リレーショナル データベースのテーブルと列を Python オブジェクトにマッピングします。
次の操作は、SQLAlchemy を使用して繰り返されます: テーブルの作成、3 つのデータ行の追加、テーブルのクエリ、および 1 つの行の更新。ORM を使用する場合は構成作業が少し増えますが、大規模なプロジェクトではその価値があります。
まず、データベースに接続し、テーブルを Python オブジェクトにマッピングするために、いくつかのコンポーネントをインポートする必要があります。基本的な sqlalchemy パッケージでは、メソッド create_engine と select、およびクラス MetaData と Table を使用する必要があります。ただし、Table オブジェクトを作成するときにスキーマ情報を指定する必要があるため、Column クラスと、各列のデータ型 (この例では Integer と String) の対応するクラスもインポートする必要があります。
また、sqlalchemy.orm サブパッケージから sessionmaker 関数をインポートする必要があります。
>>> from sqlalchemy import create_engine, select, MetaData, Table, Column,
Integer, String
>>> from sqlalchemy.orm import sessionmaker
これで、データベースへの接続を検討できます。
>>> dbPath = 'datafile2.db'
>>> engine = create_engine('sqlite:///%s' % dbPath)
>>> metadata = MetaData(engine)
>>> people = Table('people', metadata,
... Column('id', Integer, primary_key=True),
... Column('name', String),
... Column('count', Integer),
... )
>>> Session = sessionmaker(bind=engine)
>>> session = Session()
>>> metadata.create_all(engine)
データベースを作成して接続するには、データベースに対応したエンジンを作成する必要があります。次に、テーブルとその構造を管理するためのコンテナである MetaData オブジェクトが必要です。次に、people という名前の Table オブジェクトを作成します。指定されたパラメーターは、データベース内のテーブル名、作成したばかりの MetaData オブジェクト、作成する列、およびそのデータ型です。最後に、sessionmaker 関数を使用してエンジンの Session クラスを作成し、このクラスを使用してセッション オブジェクトをインスタンス化します。この時点で、データベースは接続されており、最後のステップは create_all メソッドを使用してテーブルを作成することです。
データベース テーブルが作成されたら、次のステップはいくつかのレコードを挿入することです。SQLAlchemy にも複数の挿入方法がありますが、この場合はより明示的になります。挿入オブジェクトを作成してから、次を実行します。
>>> people_ins = people.insert().values(name='Bob', count=1)
>>> str(people_ins)
'INSERT INTO people (name, count) VALUES (?, ?)'
>>> session.execute(people_ins)
<sqlalchemy.engine.result.ResultProxy object at 0x7f126c6dd438>
>>> session.commit()
ここでは、insert() メソッドを使用して挿入オブジェクトを作成し、挿入するフィールドと値を指定します。people_ins は挿入オブジェクトであり、正しい SQL コマンドが実際にバックグラウンドで作成されていることを str() 関数で示すことができます。
次に、セッション オブジェクトの execute() メソッドを使用して挿入操作を実行し、commit() メソッドでデータベースに送信します。
>>> session.execute(people_ins, [
... {'name': 'Jill', 'count':15},
... {'name': 'Joe', 'count':10}
... ])
<sqlalchemy.engine.result.ResultProxy object at 0x7f126c6dd908>
>>> session.commit()
>>> result = session.execute(select([people]))
>>> for row in result:
... print(row)
...
(1, 'Bob', 1)
(2, 'Jill', 15)
(3, 'Joe', 10)
辞書のリストを渡すことで、操作を簡素化し、複数のレコードの挿入を実行できます。挿入された各レコードは、フィールド名とフィールド値を含む辞書です。
>>> result = session.execute(select([people]).where(people.c.name == 'Jill'))
>>> for row in result:
... print(row)
...
(2, 'Jill', 15)
select() メソッドを where() メソッドとともに使用して、指定されたレコードを検索することもできます。上記の例では、name 列が「Jill」に等しいすべてのレコードが検索されます。where 式が people.c.name を使用していることに注意してください。c は name が people テーブルの列であることを示します。
>>> result = session.execute(people.update().values(count=20).where
(people.c.name == 'Jill'))
>>> session.commit()
>>> result = session.execute(select([people]).where(people.c.name == 'Jill'))
>>> for row in result:
... print(row)
...
(2, 'Jill', 20)
>>>
update() メソッドを where() メソッドと組み合わせて使用して、単一のレコードを更新することもできます。
これまでテーブル オブジェクトを直接使用してきましたが、実際、SQLAlchemy を使用して、テーブルを直接クラスにマップすることもできます。このマッピング手法の利点は、データ列がクラスの属性に直接マップされることです。
デモ用にクラス People を作成しましょう。
>>> from sqlalchemy.ext.declarative import declarative_base
>>> Base = declarative_base()
>>> class People(Base):
... __tablename__ = "people"
... id = Column(Integer, primary_key=True)
... name = Column(String)
... count = Column(Integer)
...
>>> results = session.query(People).filter_by(name='Jill')
>>> for person in results:
... print(person.id, person.name, person.count)
...
2 Jill 20
マッピング クラスの新しいインスタンスを作成してセッションに追加する限り、挿入操作を完了できます。
>>> new_person = People(name='Jane', count=5)
>>> session.add(new_person)
>>> session.commit()
>>>
>>> results = session.query(People).all()
>>> for person in results:
... print(person.id, person.name, person.count)
...
1 Bob 1
2 Jill 20
3 Joe 10
4 Jane 5
更新操作も非常に簡単です。更新が必要なレコードを取得し、マッピング インスタンスの値を変更してから、更新されたレコードをライトバック データベース セッションに追加するだけです。
>>> jill = session.query(People).filter_by(name='Jill').first()
>>> jill.name
'Jill'
>>> jill.count = 22
>>> session.add(jill)
>>> session.commit()
>>> results = session.query(People).all()
>>> for person in results:
... print(person.id, person.name, person.count)
...
1 Bob 1
2 Jill 22
3 Joe 10
4 Jane 5
削除操作は、変更と非常によく似ています. まず、削除するレコードを取得してから、セッション オブジェクトの delete() メソッドを使用して削除します:
>>> jane = session.query(People).filter_by(name='Jane').first()
>>> session.delete(jane)
>>> session.commit()
>>> jane = session.query(People).filter_by(name='Jane').first()
>>> print(jane)
None
SQLAlchemy を使用すると、生の SQL を使用するよりも構成作業が少し増えますが、実際の利点がいくつかあります。まず、ORM を採用するということは、さまざまなデータベースがサポートする SQL ステートメントのニュアンスを気にする必要がないということです。上記の例は、エンジンの作成時に提供される文字列が異なることを除いて、sqlite3、MySQL、および PostgreSQL で正常に機能し、正しいデータベース ドライバーが使用可能であることを確認するため、コードを変更する必要はありません。
もう 1 つの利点は、Python オブジェクトを介してデータのやり取りを行うことができることです。これは、SQL プログラミングの経験がないプログラマーにとってより簡単な場合があります。SQL ステートメントを作成する代わりに、Python オブジェクトとそのメソッドを使用できます。
2. Alembic でデータベース構造を変更する
リレーショナル データベースを使用した開発では、多くの場合、作業開始後にデータベース構造を変更する必要があります。これが一般的でない場合でも、少なくとも一般的です。フィールドを追加するには、フィールド タイプを変更します。もちろん、データベース テーブルとそれらにアクセスする ORM コードを手動で変更することは可能ですが、いくつかの欠点があります。まず、このような変更は、必要に応じて元に戻すことが困難です。第 2 に、特定のバージョンのコードで使用されるデータベース構成も追跡が困難です。
解決策は、データベース移行 (移行) ツールを使用して変更を支援し、変更を記録することです。移行はコードで操作されます。コードには、それらを実行するために必要な変更と逆の操作の両方が含まれている必要があります。このようにして、変更を記録し、正しい順序で実行またはロールバックできます。これにより、開発中にデータベースを任意の状態に確実にアップグレードまたはダウングレードできます。
例として、SQLAlchemy の人気のある軽量移行ツールである Alembic について簡単に紹介します。Alembic を起動するには、システム コマンド ライン ウィンドウに切り替えて、プロジェクトが配置されているディレクトリを入力し、Alembic をインストールして、alembic init を使用して共通の動作環境を作成します。
> pip install alembic
> alembic init alembic
上記のコードは、Alembic でのデータ移行に必要なファイル構造を作成します。少なくとも 1 か所で編集する必要がある alembic.ini ファイルを次に示します。
現在の状況に応じて、squalchemy.url 行を変更する必要があります。
sqlalchemy.url = driver://user:pass@localhost/dbname
この行を次のように変更します。
sqlalchemy.url = sqlite:///datafile.db
ローカルの sqlite ファイルが使用されるため、ユーザー名やパスワードは必要ありません。
次のステップは、Alembic のリビジョン コマンドでリビジョンを作成することです。
> alembic revision -m "create an address table"
Generating /home/naomi/qpb_testing/alembic/versions/
384ead9efdfd_create_a_test_address_table.py ... done
上記のコードは、リビジョン スクリプト 384ead9efdfd_create_a_test_address_table.py を alembic/versions ディレクトリに作成します。スクリプト ファイルは次のようになります。
"""create an address table
Revision ID: 384ead9efdfd
Revises:
Create Date: 2017-07-26 21:03:29.042762
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '384ead9efdfd'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
pass
def downgrade():
pass
ファイルのヘッダー情報には、リビジョン ID と日付が含まれています。このファイルには、各バージョンのロールバックをガイドするために使用される down_revision 変数も含まれています。2 番目のリビジョンがある場合、その down_revision 変数にはそのリビジョン ID が含まれている必要があります。
リビジョンを実行してリビジョン スクリプトを更新するには、upgrade() メソッドでリビジョンを実行するコードを指定し、downgrade() メソッドでフォールバック コードを指定します。
def upgrade():
op.create_table(
'address',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('address', sa.String(50), nullable=False),
sa.Column('city', sa.String(50), nullable=False),
sa.Column('state', sa.String(20), nullable=False),
)
def downgrade():
op.drop_table('address')
上記のコードを作成したら、アップグレードを実行できます。ただし、まず、Python シェル ウィンドウに戻り、データベースに存在するテーブルを確認してください。
>>> print(engine.table_names())
['people']
予想どおり、以前に作成されたテーブルは 1 つだけです。これで、Alembic のアップグレード コマンドを実行して、アップグレードを実行し、新しいテーブルを追加できます。システム コマンド ライン ウィンドウに切り替えて、次を実行してください。
> alembic upgrade head
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 384ead9efdfd, create an
address table
Python シェル ウィンドウに戻って確認すると、データベースにさらに 2 つのテーブルがあることがわかります。
>>> engine.table_names()
['alembic_version', 'people', 'address'
最初の新しいテーブル「alembic バージョン」は、データベースの現在のバージョンを記録するために Alembic によって作成されます (アップグレードおよびダウングレードの将来の参照用)。2 番目の新しいテーブル 'address' は、アップグレード操作によって結合され、準備ができています。
データベースの状態を以前の状態にロールバックする場合は、システム コマンド ウィンドウで Alembic ダウングレード コマンドを実行するだけです。ダウングレード コマンドに「-1」パラメータを追加して、バージョンをダウングレードするよう Alembic に指示してください。
> alembic downgrade -1
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running downgrade 384ead9efdfd -> , create
an address table
ここで Python セッションにログインすると、開始状態に戻りますが、バージョン レコード テーブルは引き続き存在します。
>>> engine.table_names()
['alembic_version', 'people']
もちろん、いつでもアップグレードを再度実行して、テーブルを再度アップグレードしたり、新しいリビジョンを追加したり、アップグレードを実行したりできます。
2.非リレーショナルデータベース戦闘のPythonアクセスと操作
1. NoSQL データベース
リレーショナル データベースは古くても、データを格納するための唯一のオプションではありません。リレーショナル データベースが行うのは、リレーショナル テーブルのデータを正規化することだけですが、他のスキームではデータの見方が異なります。多くの場合、これらのタイプのデータベースは NoSQL データベースと呼ばれます。これは、通常、SQL が作成されて記述された行、列、テーブルの構造に従っていないためです。
NoSQL データベースは、データを行、列、およびテーブルのコレクションとして扱うのではなく、格納されたデータをキーと値のペア、インデックス付きドキュメント、さらにはグラフとして表示できます。利用可能な NoSQL データベースは多数ありますが、それらはすべて多少異なる方法でデータを処理します。一般に、これらのデータは厳密に正規化されている可能性は低く、正規化により情報検索がより簡単かつ迅速になります。
Python が 2 つの一般的な NoSQL データベースである Redis と MongoDB にアクセスする方法を次に示します。NoSQL データベースと Python の機能の表面をなぞっただけですが、何ができるかについて大まかなアイデアが得られるはずです。
Redis または MongoDB に精通している方は、Python クライアント ライブラリの使用方法について少し学ぶことができます。NoSQL データベースを初めて使用する場合は、少なくともこれらのデータベースがどのように機能するかの感触をつかむことをお勧めします。
2. Redis でキー/値ストレージを実装する
Redis は、メモリベースのネットワーク化されたキー/値ストレージ システムです。値はメモリに保存されるため、ルックアップは非常に高速になり、ネットワークを介したアクセスの設計により、多くの場合に適しています。Redis は、キャッシュ、メッセージ ブローカー、高速情報検索システムとして一般的に使用されています。Redis はリモート ディクショナリ サーバー (リモート ディクショナリ サーバー) からその名前を取得します。これは、実際にはこれを考えるのに最適な方法であり、Web サービスに変換された Python ディクショナリのように動作します。
次の例は、Python で Redis を使用する方法を示しています。Redis コマンド ライン インターフェイスに精通している場合、または他のプログラミング言語で Redis クライアントを使用したことがある場合、これらの小さなルーチンは Python で Redis を使用するためのガイダンスを提供するはずです。
利用可能な Python Redis クライアントはいくつかありますが、Redis の公式 Web サイトによると、推奨されるソリューションは redis-py であり、pip install redis でインストールできます。
Redis サーバーを実行してコード テストを実行するには、正常に実行されている Redis サーバーが必要です。クラウドベースの Redis サービスを利用できますが、コードのテストには、Docker インスタンスを使用するか、コンピューターに自分でサービスをインストールすることをお勧めします。
すでに Docker がインストールされている場合、Docker インスタンスを使用することが、おそらく Redis サーバーを起動して実行するための最も迅速で簡単な方法です。> docker run -p 6379:6379 redis のようなコマンドを使用すると、コマンド ラインで Redis インスタンスが起動します。
Linux システムでは、システム パッケージ マネージャーを使用して Redis を簡単にインストールできます。Mac システムでは、brew install redis を使用する限り、正常にインストールできるはずです。
動作中の Redis サーバーを使用して、Python を介して Redis とやり取りする簡単な例を次に示します。まず、Redis ライブラリをインポートして、Redis 接続オブジェクトを作成する必要があります。
>>> import redis
>>> r = redis.Redis(host='localhost', port=6379)
ホスト、ポート、パスワード、SSH 資格情報など、Redis 接続を作成するときに、いくつかのオプションの接続パラメーターを使用できます。Redis サーバーが localhost のデフォルト ポート 6379 で実行されている場合、オプションのパラメーターを使用する必要はありません。接続オブジェクトを取得したら、それを使用してキー/値ストアにアクセスできます。
最初に行うことは、keys() メソッドを使用してデータベース内のキーのリストを取得し、現在保存されているキーのリストを返すことです。次に、さまざまなタイプのいくつかのキーを設定し、さまざまな方法で対応する値の取得を試みることができます。
>>> r.keys()
[]
>>> r.set('a_key', 'my value')
True
>>> r.keys()
[b'a_key']
>>> v = r.get('a_key')
>>> v
b'my value'
>>> r.incr('counter')
1
>>> r.get('counter')
b'1'
>>> r.incr('counter')
2
>>> r.get('counter')
b'2'
上記の例は、Redis データベースでキーのリストを取得し、キーに値を設定し、キーに変数カウンターを設定して、変数をインクリメントする方法を示しています。
次の例では、配列またはリストの格納を処理します。
>>> r.rpush("words", "one")
1
>>> r.rpush("words", "two")
2
>>> r.lrange("words", 0, -1)
[b'one', b'two']
>>> r.rpush("words", "three")
3
>>> r.lrange("words", 0, -1)
[b'one', b'two', b'three']
>>> r.llen("words")
3
>>> r.lpush("words", "zero")
4
>>> r.lrange("words", 0, -1)
[b'zero', b'one', b'two', b'three']
>>> r.lrange("words", 2, 2)
[b'two']
>>> r.lindex("words", 1)
b'one'
>>> r.lindex("words", 2)
b'two'
キーが最初に設定されたとき、リスト「単語」はまだデータベースにありませんが、リストの最後に値を追加またはプッシュする操作により、キーが作成され、値として空のリストが作成され、それに値「1」。ここで rpush の r は、右から挿入することを意味します。次に、rpush を使用して、最後に単語を追加し続けます。リスト内の値は lrange() 関数で取得できます。パラメータはキー、開始インデックス、終了インデックスで、インデックス -1 はリストの終わりを示します。
また、lpush() を使用すると、リストの先頭または左側に値を追加できることに注意してください。lranger() と同じ方法で lindex() を使用して単一の値を取得しますが、値のインデックスが与えられます。
値の有効期限. キーと値のペアの有効期限を設定する機能である、キャッシュに特に役立つ Redis 機能があります。タイムアウト後にキーと値の両方が削除されます。この手法は、Redis をキャッシュとして使用する場合に特に役立ちます。キーに対応する値を設定するときに、タイムアウト値を秒単位で設定することもできます。
>>> r.setex("timed", "10 seconds", 10)
True
>>> r.pttl("timed")
7165
>>> r.pttl("timed")
5208
>>> r.pttl("timed")
1542
>>> r.pttl("timed")
>>>
上記は、「時限」の有効期限を 10 秒に設定します。次に、pttl() メソッドを使用して、有効期限が切れるまでの残り時間をミリ秒単位で表示します。値の有効期限が切れると、キーと値の両方がデータベースから自動的に削除されます。この機能と、Redis が提供するきめ細かい制御は、非常に便利です。単純なキャッシング アプリケーションの場合、これ以上コードを書かなくても問題を解決できる場合があります。
Redis はデータをメモリに保持することに注意してください。そのため、データは永続的ではないことに注意してください。サーバーがクラッシュすると、一部のデータが失われる可能性があります。データ損失の可能性を減らすために、Redis には永続性を管理するためのオプションのパラメーターがいくつかあります.各変更をディスクに書き込むか、事前に決められた時間にスナップショットを作成するか、ディスクにまったく保存しないかを選択できます. You can also use the save() and bgsave() methods of the Python client to force a snapshot save programmatically. Save() は保存が完了するまで現在の操作をブロックしますが、 bgsave() は保存操作をバックグラウンドで実行します.
3. MongoDB のドキュメント
もう 1 つの一般的な NoSQL データベースは MongoDB で、ドキュメント ベースのデータベースと呼ばれることもあります。MongoDB は行と列を配置せず、ドキュメントのみを格納するためです。MongoDB は、複数のクラスターにまたがる複数のノードにわたって自由にスケーリングできるように設計されており、数十億のドキュメントを同時に処理できます。MongoDB では、ドキュメント ストレージの形式は BSON (Binary JSON、Binary JSON) と呼ばれるため、ドキュメントは JSON オブジェクトまたは Python 辞書のように見えるキーと値のペアで構成されます。
次の例は、Python を使用して MongoDB のコレクションとドキュメントを操作する方法と、適切な使用方法のリマインダーを提供する方法を示しています。MongoDB は、データのスケーリングと分散が必要で、挿入率が高く、テーブル構造が複雑で不確実な場合に最適です。しかし多くの場合、MongoDB は最良の選択ではありません。そのため、選択を行う前に、要件とオプションを徹底的に調査してください。
MongoDB サーバーの実行 Redis と同様に、MongoDB をテストするには、MongoDB サーバーにアクセスする必要があります。利用可能なクラウド ホスト型の Mongo サービスは多数ありますが、テストだけの場合は、Docker インスタンスを実行するか、独自のサーバーにインストールすることをお勧めします。
Redis の場合と同様に、最も簡単な解決策は Docker インスタンスを実行することです。すでに Docker をお持ちの場合は、コマンド ラインで > docker run -p 27017:27017 mongo と入力するだけです。
Linux システムでは、パッケージ マネージャーによってインストールする必要があり、Mac システムでは、brew install mongodb を使用できます。Windows システムの場合、Windows のバージョンとインストール手順については、MongoDB の公式 Web サイトを参照してください。Redis と同様に、サーバーを構成して起動する方法については、オンラインで検索してください。
Redis の場合と同様に、MongoDB データベースに接続するための Python クライアント ライブラリがいくつかあります。それらがどのように機能するかを示すために、pymongo を紹介しましょう。pymongo を使用するための最初のステップは、pip で実行できるインストールです。
> pip install pymongo
pymongo のインストールが完了したら、MongoClient インスタンスを作成し、一般的な接続情報を指定してから、MongoDB サーバーに接続できます。
>>> from pymongo import MongoClient
>>> mongo = MongoClient(host='localhost', port=27017) ⇽--- host='localhost'和port=27017是默认值,不需要指定
MongoDB の組織構造には、複数のコレクションを含むデータベースが含まれており、各コレクションには複数のドキュメントを含めることができます。ただし、データベースやコレクションにアクセスする前に、それらを作成する必要はありません。データベースとコレクションが存在しない場合、それらは挿入時に自動的に作成され、レコードを取得しても結果は返されません。
クライアントをテストできるようにするには、Python 辞書などのサンプル ドキュメントを作成します。
>>> import datetime
>>> a_document = {'name': 'Jane',
... 'age': 34,
... 'interests': ['Python', 'databases', 'statistics'],
... 'date_added': datetime.datetime.now()
... }
>>> db = mongo.my_data ⇽--- 选中一个尚未创建的数据库
>>> collection = db.docs ⇽--- 选中数据库中的一个集合,也尚未创建
>>> collection.find_one() ⇽--- 查询第一条记录,即使集合或数据库不存在也不会引发异常
>>> db.collection_names()
[]
上記は、データベースとドキュメント コレクションに接続されています。現時点では存在しませんが、アクセスすると作成されます。データベースとコレクションが存在しない場合でも、例外はスローされないことに注意してください。コレクションのリストを要求すると、コレクションにはまだコンテンツがないため、空のリストが返されます。
ドキュメントを保存する場合は、コレクションの insert() メソッドを使用してください。操作が成功すると、ドキュメントの一意の ObjectId が返されます。
>>> collection.insert(a_document)
ObjectId('59701cc4f5ef0516e1da0dec') ⇽--- 唯一的ObjectId
>>> db.collection_names()
['docs']
ドキュメントが docs コレクションに保存されたので、データベース内のコレクション名が要求されたときにコレクションが表示されます。ドキュメントがコレクションに格納されると、クエリ、更新、置換、および削除を行うことができます。
>>> collection.find_one() ⇽--- 获取第一条记录
{'_id': ObjectId('59701cc4f5ef0516e1da0dec'), 'name': 'Jane', 'age': 34,
'interests': ['Python', 'databases', 'statistics'], 'date_added':
datetime.datetime(2017, 7, 19, 21, 59, 32, 752000)}
>>> from bson.objectid import ObjectId
>>> collection.find_one({"_id":ObjectId('59701cc4f5ef0516e1da0dec')}) ⇽--- 获取符合指定条件的记录,这里是用了ObjectId
{'_id': ObjectId('59701cc4f5ef0516e1da0dec'), 'name': 'Jane',
'age': 34, 'interests': ['Python', 'databases',
'statistics'], 'date_added': datetime.datetime(2017,
7, 19, 21, 59, 32, 752000)}
>>> collection.update_one({"_id":ObjectId('59701cc4f5ef0516e1da0dec')},
{"$set": {"name":"Ann"}}) ⇽--- 按照$set对象的内容对记录做出更新
<pymongo.results.UpdateResult object at 0x7f4ebd601d38>
>>> collection.find_one({"_id":ObjectId('59701cc4f5ef0516e1da0dec')})
{'_id': ObjectId('59701cc4f5ef0516e1da0dec'), 'name': 'Ann', 'age': 34,
'interests': ['Python', 'databases', 'statistics'], 'date_added':
datetime.datetime(2017, 7, 19, 21, 59, 32, 752000)}
>>> collection.replace_one({"_id":ObjectId('59701cc4f5ef0516e1da0dec')},
{"name":"Ann"}) ⇽--- 用新的对象将记录替换
<pymongo.results.UpdateResult object at 0x7f4ebd601750>
>>> collection.find_one({"_id":ObjectId('59701cc4f5ef0516e1da0dec')})
{'_id': ObjectId('59701cc4f5ef0516e1da0dec'), 'name': 'Ann'}
>>> collection.delete_one({"_id":ObjectId('59701cc4f5ef0516e1da0dec')}) ⇽--- 删除符合条件的记录
<pymongo.results.DeleteResult object at 0x7f4ebd601d80>
>>> collection.find_one()
最初に、MongoDB はフィールドとその値の辞書と照合することに注意してください。辞書は、$lt (より小さい) や $gt (より大きい) などの演算子や、レコードを更新する $set などのコマンドを表すためにも使用されます。
もう 1 つ注意すべき点は、レコードが削除され、コレクションが空であっても、コレクションの削除を指定しない限り、コレクションは存在し続けるということです。
>>> db.collection_names()
['docs']
>>> collection.drop()
>>> db.collection_names()
[]
もちろん、MongoDB はさらに多くのことができます。同じコマンドには、1 つのレコードを操作するだけでなく、find_many や update_many など、複数のレコードを操作するバージョンもあります。MongoDB は、パフォーマンスを向上させるインデックスもサポートしており、データのグループ化、カウント、および集計のためのいくつかのメソッドと、組み込みの MapReduce メソッドを提供しています。
要約:
- Python には一連のデータベース API (DB-API) が付属しており、複数のリレーショナル データベースのクライアントに対してほぼ一貫したインターフェイスを提供します。
- オブジェクト リレーショナル マッパー (ORM) を使用すると、複数のデータベース間でコードをより標準化できます。
- ORM を使用すると、SQL クエリの代わりに Python コードとオブジェクトを介してリレーショナル データベースにアクセスすることもできます。
- Alembic のようなツールを ORM と組み合わせて使用すると、リレーショナル データベースのテーブル構造をコードで元に戻すことができます。
- Redis などのキー/バリュー ストレージ システムは、高速なメモリ ベースのデータ アクセスを提供します。
- MongoDB は、リレーショナル データベースよりも柔軟な構造を持つスケーラブルなデータ ストレージ ソリューションを提供します。