このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

多品種少量データとMongoDB

MongoDBは、よく知られているように、ジョインもトランザクションもサポートしてません。これは確かに不便なこともありますが、欠点・弱点というよりは、最初からそのように設計されているもので、ひとつの設計判断です。パフォーマンス、スケーラビリティ、耐障害性、分散化の容易性などをより重要視した結果でしょう。

MongoDBの特徴を見ると、大規模なデータセットを高速にハンドリングするためにチューンされているように思えます。しかし、それとは違った場面で使える機能性も備えています。それは「ユニオン型を自由に扱える」ということなんですが、地味であまり言及されないし、ちょっと分かりにくいところもあります。でも、この特徴は、僕にとっては嬉しいものです。ちょっと説明してみます。

ジョインとユニオン

SQLDBはジョインができます。ジョインとは、“直積”と“等式的条件による絞り込み”の組み合わせです*1。等式的条件は珍しくはないので、SQLDB特有の機能性は直積でしょう*2

集合の操作として、直積の双対は直和です。データ型の文脈では、直和をユニオン型とかバリアント型と呼びます。直積が得意なSQLDBですが、直和はどうでしょう。2つのテーブルのユニオンが作れるのは、それらのテーブルが同じスキーマ(データ型)を持つときだけです。ユニオンは非常に制限されています。

MongoDBはどうでしょうか? もともとがスキーマレスなので、ユニオンだとか意識するまでもなく、異なる型のデータを混ぜて使えます。出来るのが当たり前過ぎて、「ユニオン型を自由に扱える」という言明がピンと来ないわけです。

データの種類と個数

具体例を出すと、「従業員データと製品データを同じテーブルに入れる」なんてことは、SQLDBでは言語道断だし、そんなことは誰も考えもしないですよね。MongoDBなら、やろうと思えばできるね、となります。とはいえ、さすがに「従業員データと製品データ」を混ぜるメリットはありません。では、製品としてオモチャと野菜を扱っているときはどうでしょう? オモチャ・テーブルと野菜テーブルに分けずに製品コレクションにできます。オモチャと野菜は違いすぎる? では、野菜と果物ならどうでしょうか?

今の例は、種別の境界線が曖昧な場合に、厳密な区分なしでも扱えるってことでした。別な状況として、種別をちゃんと区分すると、データレコードの個数が少なくなってしまう場合です。例えば、細かく製品を分けたら千種類になるが、個々の種類の在庫は10個以内とか。このとき、千個のテーブルを作りますか? もっと極端になると、各種類ごとのデータレコードは0個(ナシ)か1個とか。

多品種少量データをユニオン型として扱う

製品の種類が千種類ということは、データ型が千あることです。そして、それらのデータ型に対応する個々の集合の基数(cardinal)が小さい状況 -- 多品種少量データってことです。MongoDBなら、異なる千種のデータ型のレコードを単一のコレクションに入れても問題はありません。

ここで注意すべきは、MongoDBがスキーマレスなことは、アプリケーションがデータ型なしで成立することではないことです。アプリケーションの仕様が「データはなんでもいい」で済むはずがありません。データ型はきちんと決められているとして、異なる型を単一のコレクションに入れてもいい点で重宝するのです。

もうひとつ注意すべきは、ユニオン型における「もとの型」のエンコーディングです。野菜型と果物型を同じコレクションに入れるとして、取り出したレコードが野菜型か果物型かを瞬時に判断できる必要があります。よく使われる手法は、タイプタグとか型弁別子と呼ばれる目印です。例えば、"_tag" のようなフィールドに VEGETABLE, FRUIT のような識別値を入れておきます。つまり、ユニオン型データは、もとの型にタグを付加した形で保存します。タグの連鎖を使えば、大分類から詳細分類まで、データ型を順次判断して処理をディスパッチできます。

多品種少量データに関しては、その場限りに対処していて、あまり系統的に扱うことをしなかったように思います(少なくとも僕はそうでした)。MongoDBのような「ユニオン型を自由に扱える」データベースなら、多品種少量データをうまく処理できる可能性がありますね。

*1:圏論でいえばファイバー積(pullback)です。ファイバー積は、直積と等値核(イコライザー)の組み合わせです。

*2:MongoDBのデータモデルで、原理的に直積が作れないわけではありません。「関手的データモデル雑感: 正規形とかジョインとか」を参照。