設計文書の管理
IBM Cloudant のスケーラブルな JSON データ・ストアには複数の照会メカニズムがあります。どのメカニズムでも索引が生成されますが、索引はコア・データとは別個に作成および維持されます。
IBM Cloudant の Developer Advocate である Glynn Bird (glynn@cloudant.com) によって寄稿された記事。
索引の作成は、文書が保存されたときに即時に実行されるわけではありません。 そうではなく、 後で実行するように索引の作成をスケジュールすることで、 より高速で、ブロッキングしない書き込みスループットを実現しています。
- MapReduce ビューは、キーまたはキー範囲による効率的な 検索のために B ツリー内に保管されるキー/値ペアを持つデータ・セットの索引です。
- 検索索引は、フリー・テキスト検索、ファセット化、および複雑な随時照会を可能にするために、Apache Lucene を使用して作成されます。
IBM® Cloudant® for IBM Cloud® の検索索引と MapReduce ビューは、 設計文書をデータベースに追加して構成されます。 設計文書は、ビューまたは索引の作成方法に関する指示を含む JSON 文書です。 単純な例を見てみましょう。 以下の例のような、単純なデータ文書コレクションが あると仮定します。
単純なデータ文書の例を次に示します。
{
"_id": "23966717-5A6F-E581-AF79-BB55D6BBB613",
"_rev": "1-96daf2e7c7c0c277d0a63c49b57919bc",
"doc_name": "Markdown Reference",
"body": "Lorem Ipsum",
"ts": 1422358827
}
各データ文書には、名前、本文、およびタイム・スタンプが含まれています。 MapReduce ビューを作成すると、タイム・スタンプで文書をソートできます。
マップ関数を作成すると、タイム・スタンプで文書をソートできます。
文書のタイム・スタンプ・フィールド (ある場合) を返すマップ関数の例を次に示します。
function(doc) {
if (doc.ts) {
emit( doc.ts, null);
}
}
この関数は、索引のキーとして使用できるように文書のタイム・スタンプを排出します。 インデックスの値には興味がないので、
null が発行されます。 この結果として、時刻で順序付けされた索引が文書セットに提供されます。
このビューを by_ts と呼び、 fetch というデザイン・ドキュメントに入れます。
マップ関数を使用してビューを定義する設計文書の例を次に示します。
{
"_id": "_design/fetch",
"views": {
"by_ts": {
"map": "function(doc) {
if (doc.ts) {
emit( doc.ts, null);
}
}"
}
},
"language": "javascript"
}
この結果として、マップ・コードは JSON 準拠のストリングに変換され、設計文書に組み込まれます。
設計文書が保存されると、次のようになります。 IBM Cloudant は、fetch/by_tsビューを作成するためにサーバー・サイド・プロセスをトリガーします。 このビューの作成は、データベース内のすべての文書に対して反復処理を行い、それぞれを JavaScript のマップ関数に送信することによって行われます。 この関数は、排出された
key-value ペアを返します。 反復が継続されるにつれて、各
key-value ペアが B ツリー索引に保管されます。 初めて索引が作成された後、後続の再索引付けは、新規文書および更新された文書に対してのみ行われます。 削除された文書は、索引付けから除外されます。 以下の図に示すように、この時間節約プロセスは「増分 MapReduce」と呼ばれます。
以下の事項を覚えておくと有益です。
- 索引の作成は非同期で行われる。 IBM Cloudant は、設計文書が保存されたことを確認する。 索引作成の進行状況を確認するには、IBM Cloudant の
_active_tasksエンドポイントをポーリングする必要があります。 - データ量が多いほど、索引の準備ができるまでにかかる時間は長くなる。
- 初回の索引作成の進行中は、索引に対して行われた照会はすべてブロックされる。
- ビューを照会すると、増分で索引付けされていない文書の「マッピング」がトリガーされる。 この方法により、データの最新ビューを確実に取得できます。 この規則の例外については、以下の
staleパラメーターの 説明を参照してください。
同じ設計文書内の複数のビュー
同じ設計文書に複数のビューを定義すると、 それらは効率的に同時に作成されます。 各文書の読み取りは 1 回のみ行われ、各ビューのマップ関数を通じて渡されます。 この方法を使用する場合は、設計文書を変更すると、その文書で定義されているすべての既存の MapReduce ビューが無効化されることに注意してください。 このプロセスでは、未変更のビューが存在している場合でも、MapReduce ビューが無効化されます。
MapReduce ビューを互いに独立して変更する必要がある場合は、それらの定義を別々の設計文書に入れます。
この動作は、Lucene 検索索引には適用されません。 それらの索引は、同じ設計文書内の他の未変更の索引を無効化せずに、同じ文書内で変更できます。
設計文書に対する変更の管理
将来のある時点でビューの設計の変更を決断すると想像してください。 その時、 実際のタイム・スタンプ結果を返す代わりに、関心があるのは、 何個の文書が基準に一致するかというカウントだけです。 このカウントを作成するには、マップ関数は同じままで、
reduce の _count を使用します。
reduce 関数を使用する設計文書の例を次に示します。
{
"_id": "_design/fetch",
"_rev": "2-a2324c9e74a76d2a16179c56f5315dba",
"views": {
"by_ts": {
"map": "function(doc) {
if (doc.ts) {
emit( doc.ts, null);
}
}
}",
"reduce": "_count"
},
"language": "javascript"
}
この設計文書が保存されると、以下のようになります。 IBM Cloudant は、古い索引を完全に無効にし、新しい索引の作成を最初から開始して、すべての文書を順に繰り返します。 元の作成と同様に、かかる時間はデータベースに含まれている文書の数によって決まります。 また、作成が完了するまでは、そのビューでの着信照会はブロックされます。
ただし、問題があります。
このビューにリアルタイムでアクセスしているアプリケーションがある場合、次のようなデプロイメント・ジレンマに遭遇する可能性があります。
- 古いビューが無効化されているため、元の設計文書に依存しているバージョン 1 のコードはもう機能しない可能性があります。
- バージョン 2 のコードは新しい設計文書を使用します。 新しいビューの作成がまだ完了していないため、このバージョンをすぐにリリースすることはできません。 データベースに含まれている文書が多い場合は作成処理に時間がかかります。
- コードに影響を与えるより微妙な問題は、バージョン 1 と 2 ではビューとは異なる結果データが予期されることです。 バージョン 1 では一致する文書のリストが予期されていますが、バージョン 2 では結果の数が「減少」することが予期されています。
設計文書に対する変更の調整
この変更管理の問題を扱う方法は 2 つあります。
バージョン管理された設計文書
1 つの解決策は、以下のようにバージョン管理された設計文書名を使用することです。
- コードは、最初、
_design/fetchv1という名前のビューを使用するように作成されます。 - 新しいバージョンをリリースするときに、
_design/fetchv2という名前の新しいビューを作成し、そのビューを照会して確実に作成されるようにします。 - IBM Cloudant は、新しい索引の作成処理が完了するまで
_active_tasksをポーリングします。 - これで、2 番目のビューに依存するコードをリリースする準備ができました。
- もう必要ないことを確認したら
_design/fetchv1を削除します。
バージョン管理された設計文書を使用すると、設計文書での変更管理が簡潔ですが、後で古いバージョンを必ず削除してください。
Move and switch設計文書
もう 1 つの方法は、IBM Cloudant は同じ設計文書が 2 つある場合にそれを認識し、既にあるビューの再作成に時間とリソースを浪費しないという事実に依存します。 つまり、設計文書 _design/fetch を使用し、完全な重複である _design/fetch_OLD を作成すると、再索引付けはトリガーされずに、両方のエンドポイントが交換可能な状態で機能します。
新しいビューに切り替えるには、以下のステップに従います。
- 変更する設計文書の複製コピーを作成します。例えば、名前に
_OLDを追加します。_design/fetch_OLD. _NEWという接尾部を持つ名前 (_design/fetch_NEW) を使用して、新規または「後任」の設計文書をデータベースに入れます。fetch_NEWビューを照会して、 作成が開始されることを確認します。_active_tasksエンドポイントをポーリングし、索引の作成が終了するまで待ちます。- 新しい設計文書の重複コピーを
_design/fetchに入れます。 - 設計文書
_design/fetch_NEWを削除します。 - 設計文書
_design/fetch_OLDを削除します。
Move and switch ツール
Node.js のコマンド・ライン・スクリプト couchmigrate は、「Move and switch」の手順を自動化します。 次のコマンドを使用してこれをインストールできます。
npm install -g couchmigrate
couchmigrate 、 まず、 COUCH_URL という環境変数を設定して、 CouchDB/{{site. data.keyword.cloudant_short_notm }} インスタンスの URL を定義します。 IBM Cloudant インスタンスの URL を定義するには、次のコマンドを実行します。
export COUCH_URL=https://127.0.0.1:5984
URL は https:// で始まらなければならず、認証情報を含めることができる。 認証資格情報が含まれた IBM Cloudant インスタンスの URL を定義するには、次のコマンドを実行します。
export COUCH_URL="https://$ACCOUNT:$PASSWORD@$HOST.cloudant.com"
ファイルに保管されている、JSON フォーマットの設計文書があると仮定した場合、マイグレーション・コマンドを実行できます。
この例では、次のようになっています。
db は変更するデータベース名を指定します、 には変更するデータベースの名前を指定し、 dd にはデザイン・ドキュメント・ファイルへのパスを指定します。 couchmigrate コマンドを実行します。
couchmigrate --db mydb --dd /path/to/my/dd.json
このスクリプトは、「Move and switch」手順を調整し、ビューが作成されるまで待ってから戻ります。 後任の設計文書が、現在の文書と同じ場合、スクリプトはほぼすぐに戻ります。
スクリプトのソース・コードは、以下の場所にあります。
couchmigrate.
「stale」パラメーター
索引は完了したが、新しいレコードがデータベースに追加された場合、索引はバックグラウンドで更新するようスケジュールされます。 データベースの状態は以下の図のようになります。
ビューを照会するときには、次の選択肢があります。
- デフォルト動作は、応答を返す前に、索引が最新であり、データベース内に最新文書が含まれていることを確認します。 ビューを照会すると、以下のようになります。 IBM Cloudant は、最初に 250 個の新規文書に索引を付けてから、応答を返します。
- 代替方法は、API 呼び出しに
stale=okパラメーターを追加することです。 このパラメーターの意味は、return me the data that is already indexed. I don't care about the latest updates.つまり を使用してビューにクエリを実行すると、stale=ok、 IBM Cloudant は、追加の再索引付けを行わずに、即時に応答を返します。 - 2 番目の代替方法は、
stale=update_afterパラメーターを API 呼び出しに追加するというものです。 このパラメーターの意味は、return me the data that is already indexed, and then reindex any new documents.つまり を使用してビューにクエリを実行すると、stale=update_after、 IBM Cloudant は即時に応答を返し、新規データに索引を付けるためのバックグラウンド・タスクをスケジュールします。
stale=ok または stale=update_after を追加することは、ビューからより速く応答を得るための良い方法ではありますが、最新性は保証されなくなります。
デフォルト動作は、IBM Cloudant クラスター内のノードにロードを均等に分散します。 代替方法の stale=ok または stale=update_after オプションを使用すると、結果整合性セット全体から整合する結果を返すために、クラスター・ノードのいずれかのサブセットが優遇される可能性があります。 stale パラメーターは、すべてのユース・ケースに最適な解決策ではないということです。
ただし、失効した結果をアプリケーションが問題なく許容できるのであれば、変更が速いデータ・セットでタイムリーな応答を提供できます。 データの変更率が低い場合は、stale=ok または stale=update_after を追加してもパフォーマンス上のメリットはなく、大規模なクラスターではロードが不均等に分散される可能性があります。
デフォルトの動作では最新のデータが提供されてクラスター内でデータが分散されるので、できる限り stale=ok または stale=update_after は避けてください。 大規模なデータ処理タスク (例えば、定期的なデータの一括更新など) が進行中のときには、一時的に stale=ok に切り替えることで、クライアント・アプリに対応させることができます。 アプリは後でデフォルト動作に戻ることができます。
stale オプションはまだ使用可能ですが、より有用なオプションである stable および update が使用可能なため、それらを代わりに使用する必要があります。 詳しくは、失効したビューへのアクセスを参照してください。