February 2017

Volume 32 Number 2

データ ポイント - Azure Search の概要 — ハンドヘルド チュートリアル

Julie Lerman | February 2017

Julie LermanAzure Search については、Entity Framework と OData を作った開発者の 1 人である Pablo Castro から初めて聞いて以来ずっと気になっていました。Pablo Castro は現在、マイクロソフトでエンジニアリング部門のディレクターを務めています。彼は本物の革新者であり、トップクラスのデータ オタクです。Azure Search がマイクロソフトの新規プロジェクトとして誕生した背景について Pablo Castro が執筆した Medium の 記事が読み物として最高です (bit.ly/2gzVFTQ)。

Azure Search は、マイクロソフトが検索に使用しているプロセスやインテリジェンスを取り込み、独自のデータに対して洗練された検索機能を実現できるようにするサービスです。このサービスは、データから独自の検索インデックスを構築し、データの「コピー」を独自に保持して、そのデータに対して検索を実行できるようにします。また、データの変更に合わせてインデックスを更新する Azure Search のプロセスは、自動化できます。データ ソースが DocumentDB などの Azure データ ストアの場合、この自動化はいっそう簡単になります。

実際に使用してみると、Azure Search の基礎を理解しやすくなることがわかりました。そこで、今回は単に説明するだけでなく、実際に使用する形にしています。サービスとインデックスは、REST や、.NET クライアントなどの API を使用してコードで作成できます。ただし、Azure ポータルで表示を確認しながら設定することもできます。今回は、このポータルを出発点にします。Azure ポータルでサンプル データ ストアを使用して無料の Search サービスを作成し、クエリを実行します。Azure Search を初めて取り上げる今回は、全体をていねいに説明しながら、個人的に見つけたことをいくつか紹介します。始めの 1 歩となる今回の内容を理解したら、このサービスの機能をさらに掘り下げ、REST API や .NET クライアント API を使って Azure Search に着手する準備が整います。

MSDN サブスクリプション会員であれば、以降の手順に使用できる Azure サブスクリプションを既に持っています。今回は、残高を気にしなくて済むように、無料のサービスを使用します。Azure サブスクリプションを現在お持ちではなくても、azure.com/free からすぐに無料試用版をセットアップできます。

新しい Search サービスの作成

Azure ポータルで新しいリソースの追加を選択すると、[Web + モバイル] カテゴリに [Azure Search] が表示されます。ただし、最も簡単なのは、単純に検索ボックスに「search」と入力する方法です (非常にメタ的ではありませんか)。 サービスを設定するには、サービス名を指定する必要があります。このサービス名が URL の最初の部分になります。ここでは thedatafarm を使用します。これにより、URL は thedatafarm.search.windows.net になります。どのリソースでも同じですが、これを既存のリソース グループに追加するか、新しいリソース グループを作成するかを選ばなければなりません。サービスに関連付けるものはまだ何もありません。そのため、新しいリソース グループを米国東部のリージョンで作成し、「datafarmsearchgroup」という名前を付けました。リソースを設定するための最後の情報として価格レベルを選択します。Azure Search には無料の価格レベルが用意されているため、サービスを試すにはこれが最適です。無料価格レベルでは、10,000 個のドキュメント、3 つのインデックス、50 MB のストレージを利用できますが、スケール変換はできません。サブスクリプションでは無料の Search サービスを 1 つ設定できます。必ず、[FREE] レベルを選び、次に [選択] ボタンをクリックしてください。そうしなければ、既定の Standard を選んだことになります。そのようなミスに気付いたときの気持ちを想像してみてください。

[作成] をクリックしたら、Azure によって設定が確認されます。ここまですべてを行っても、わずか数分でサービスがライブになります。

これでサービスを用意できましたが、何を検索の対象にしましょう。 最初に Azure Search をひととおり確認したときは、検索する価値のあるデータ セットを見つけることと、次にそのデータを自分のサービスでも使えるようにする方法を把握するのに多くの時間を費やしました。面白くはありましたが、後から考えると、取っ掛かりにすることだけを目的に Azure Search で提供されているいずれかのサンプル データ セットを使って始めれば良かったと思っています。そのため、今回はそうします。

検索はデータに対して実行されるのではなく、データのインデックスに対して実行されます。また、インデックスはドキュメント形式になります。リレーショナル データベース ユーザーからすれば、インデックスは大ざっぱに言ってテーブルのようなものですが、ドキュメントはテーブル内の個々の行、つまりデータの 1 つの単位に似ています。そのため、最初の作業は検索するデータのインデックスを作成することです。データはさまざまなリソースから取得できます。別の Azure サービスに含まれるデータからインデックスを作成するのが最短コースですが、これは Azure Search と同じサブスクリプションのサービスを使用するのが最も簡単です。既存の Azure DocumentDB、Azure SQL Database、または Azure VM で実行されている SQL Server を指すことができます。本稿執筆時点では、Azure Table Storage と Blob Storage のサポートはプレビュー段階です。Azure Search では、一部の作成済みのサンプル データにアクセスできるようになっています。そのため、まず、[インデックスの追加] オプションをクリックするのではなく、[データのインポート] を選択します。これにより、最初のインデックスも作成されます。

図 1 に示すように、[データのインポート] ブレードで、[Samples] を選択し、次に [realestate-us-sample] データを選択します。本稿執筆時点ではこのオプションしか用意されていませんが、他のサンプルも今後提供される予定です。サンプルのアイコンから、これが Azure SQL Database であることがわかります。そのため、リレーショナル データからドキュメントのインデックスが作成されます。Azure Search は、このデータをインデックス作成に必要な構造に変換します。このプロセスは 3 つのステップで構成されます。まずデータ ソースを選択し、次にインデックスを定義して、最後にデータをインデックスにインポートします。

Azure に保存されたデータへの接続方法を把握する Azure Search
図 1 Azure に保存されたデータへの接続方法を把握する Azure Search

インデックスの定義

サンプルを選択すると、Azure ポータルにグリッドが表示され、サンプル データ ソース内で見つかったすべてのフィールドが一覧されます。これがインデックスを定義するステップになります。今回の場合、サービスのウィザードによってインデックスが事前定義されます (図 2 参照)。データをインポートする前にインデックスを微調整できるのはこの機会しかありません。インデックスを再定義すると、データをインポートし直すことになります。運用環境の場合、これは望ましいことではありません。

realestate-us-sample データから作成した既定のインデックスの最初の数行
図 2 realestate-us-sample データから作成した既定のインデックスの最初の数行

Azure SQL Database または SQL Server に対して作成されたインデックスがターゲットにできるのは、1 つのテーブルまたはビューのみです。リレーショナル データ ストア以外をソースとして使用する場合は、特定のドキュメントまたは BLOB 内に保存されたすべてのグラフが Search に含まれます。したがって、ここで示しているインデックスはデータベースの 1 つのテーブルが元になっています。26 個のフィールドが存在し、グリッドでは [取得可能]、[フィルター可能]、[ソート可能]、[ファセット可能]、および [検索可能] の各オプションを使用して、各フィールドを検索に使用する方法を定義できます。そのため、検索キーワードを入力するだけにとどまらない柔軟性が提供されます。グリッド全体に、検索でのフィールドの使用方法を定義する列が並んでいます。インデックス ウィザードによって、一部が既定で選択されています。

すべてのフィールドを検索可能にする必要はありません。たとえば、description フィールドは 7 つ存在します。1 つは英語用で、他の各フィールドはそれぞれ別の言語で使用されます。このリソースを使用するアプリケーションのユーザーがケベック州にしか存在せず、フランス語と英語での検索しかサポートする予定がなければ、他の 5 つの言語を検索インデックスから削除できます。ポータルでこれを行うには、目的のフィールドを右クリックして、[削除] を選択するだけです。

インデックスを定義する場合はなんらかの考察と計画が必要になりますが、今回はインポート ツールによって設定された選択肢を利用そのまま利用します。ただし、時間をかけてグリッドを調査し、何が定義されているかを把握してください。たとえば、description フィールドは検索も取得もできますが、フィルタリングや並べ替えはできません。一方、sqft (平方フィート) や price などの単純なスカラー フィールドは並べ替えもフィルタリングも可能です。

インデクサーを使用してデータをインポートする

インデックスを定義したら、次はデータを取り込みます。インデックスの定義は、データのインポート方法に非常に大きく影響します。重要なのは、インデックスがデータに適用されるのではなく、データがインデックスに取得されることです。この処理にかかる時間はデータのサイズ、構造、場所に加えて、インデックスの定義によっても異なります。たとえば、異なる description フィールドが 7 個あるインデックスは、フィールドが 2 個しかないインデックスよりも時間がかかります。

データ ソースのデータが変更されたらどうなるのかとお考えかもしれません。Azure Search には、インデックスを更新するメカニズムがいくつか用意されていて、多くの場合、Azure Search サービス定義の一部としてこれを自動化できます。この変更検出とデータ移動にまつわるルールとパラメーターは、データ ソースに応じて異なります。インデックスの更新の詳細については、ドキュメントを参照してください。

次に、ウィザードはインデクサーを作成するよう求めます。インデクサーは、データ ソースからデータを読み取ってターゲット インデックスを設定するクローラーです。このインデクサーこそが、最初のインデックス作成を実行します。さらに、定義されたスケジュールに基づいて、またはオンデマンドで、インデックスの更新も行います。今回は Azure SQL Database をデータ ソースに選んだため、Azure SQL Database をクロールできる特別に定義されたインデクサーがウィザードによって使用されます。どのリソースもそうですが、インデクサーには名前が必要です。  ここでは「defaultindexer」としました。命名のベスト プラクティスではないかもしれませんが、今回のデモ用としては十分です。

[OK] をクリックすると、インデックスの作成が開始されます。ポータルには通知が表示され、作成が始まったことが知らされます。また、[インデクサー] ブレードで進捗状況を確認できます。今回のインポートは非常に短時間だったので、進捗状況を確認するときには既に処理が完了していました。図 3 は、「thedatafarm」 Search サービスのブレード内でページを下にスクロールしたところです。ご覧のように、[インデクサー] ボックスが強調表示されます。また、そのボックスをクリックしたことで、[インデクサー] ブレードが右側に開かれ、「defaultindexer」のジョブが完了してデータ ソースから 4,959 個の検索ドキュメントが作成されたことが示されています。

Search サービスの [インデクサー] ブレードに示されたデータ インポートの状態
図 3 Search サービスの [インデクサー] ブレードに示されたデータ インポートの状態

検索可能ドキュメントを調査する

インデックスを検索する準備が整いました。Search エクスプローラーは、検索の感覚をつかむ方法として、またコードに実装する前に検索を直接テストする方法として優秀です。OData で作業した経験がある方は、フィルタリング、並べ替え、ページングを表す方法に OData の構文が使用されていることにお気付きかもしれません。検索自体は 2 つのクエリ構文のどちらかを使用して実行できます。既定の構文は「シンプルな構文」と呼ばれ、もう一方の構文は Lucene クエリ構文と呼ばれます。

最初の検索では、[クエリ文字列] フィールドに何も入力せずに [検索] ボタンをクリックすることをお勧めします。これにより、すべてのデータが取得されますが、一度に 50 ページが表示されることになります。よく知らないデータ ソースを使用しているため、確認しておく価値はあります。また、データが構造化されるしくみも感じがつかめます。

この結果の先頭には、インデックスを説明するヘッダーが付いています。ドキュメントの配列全体は「value」タグにラップされ、各ドキュメントの最初には検索スコアの値が添えられます。次に、それぞれの値が設定された各フィールドが一覧されます。

Search を OData フィルターや count と組み合わせる

2 回目の検索では、純粋な検索を忠実に実行してみましょう。[クエリ文字列] フィールドに「condominium」と入力し、[検索] を選択します。URI の末尾が &search=condominium になっているのがわかります。

既定では、Azure Search は 50 個ずつドキュメントがページングされたデータを一度に返します。ただし、ここで何が取得されているかを確認するのは非常に困難です。OData パラメーターを追加して、count を要求してみます。複数のパラメーターを使用することになるので、「condominium」が検索部であることを指定する必要があります。クエリ文字列は次のようになります。

$count=true&search=condominium

図 4 に示すように、インデックスの説明の後、最初の value が示される手前で、count の結果が 399 個のドキュメントになっているのがわかります。Search は、インデックスで検索対象として定義したすべてのフィールドを確認し、文字列「condominium」が見つかったすべてのドキュメントの数を返し、一致したその 399 個のドキュメントのうちの最初の 50 個を返します。一番下までスクロールすると、次の 50 個のドキュメントを取得するための URI があるのがわかります。OData で作業をした経験があれば、このパターンには見覚えがあるでしょう。

要求に OData $count を使ったクエリの結果セットの先頭 (count は結果のルートの一部)
図 4 要求に OData $count を使ったクエリの結果セットの先頭 (count は結果のルートの一部)

[結果] ウィンドウを検索するには、まずカーソルが結果の上に置かれていることを確認し、ブラウザーの検索コマンド (Ctrl+F など) を使用します。ブラウザーの検索ボックスとは明らかに異なる特別な検索ボックスが表示されます。「condominium」と入力し、検索結果をクリックしていくと、用語が description フィールドと tags フィールドにポップアップ表示されるのがわかります。他のフィールドにも表示される可能性はありますが、一部しか確認していません。

インデックスの一部のフィールドをフィルタリング可能と定義したことを思い出してください。クエリを変更し、寝室が 3 部屋のリストになるようフィルタリングを追加します。つまり、beds フィールドの値を 3 に設定します。フィルターは OData パラメーターなので、先頭にドル記号が必要です。フィルタリングに OData 構文を使った新しいクエリ文字列は次のようになります。

$count=true&search=condominium&$filter=beds eq 3

count に表示されるドキュメントの数は 73 まで減りました。

Azure Search をさらに掘り下げる

この時点で、インデックスを定義する方法についてもっと良い考えが浮かびました。インデックスの定義方法は、アプリで実現しようとしていることによって大きく変わります。同じデータ ストアにアクセスしても、結果では別の機能や別のデータが必要になるさまざまなアプリを開発する場合があります。Azure Search では、このようなさまざまなニーズを満たすため、個別のインデックスを構築できます。また、各インデックスはデータ セットを独自に持つため、アプリがリソースを求めて互いに競合することはありません。競合が発生すると、パフォーマンスが低下する恐れがあります。

取り組んでいる内容を視覚化できればと考えていました。Azure Search の解説を始めるにあたって、Azure ポータルを使ったことで、インデックスを目で確認きるようになり、さらに結果を表示することも可能になりました。また、クエリもテストできました。こうした経験を得たことで、アプリ内で Azure Search を試す際に、.Net クライアントを使ったり、REST を使ってクエリを直接実行したりすることもできるだろうという確信も強くなっています。独自のデータベースも、他のサンプル データも使えます。既に 1 つ試してみたのは、クーパーヒューイット国立デザイン博物館が bit.ly/2hrOCej (英語) で共有している公開データ セットからデータをインポートすることです。そのオブジェクト データ セットの一連の JSON ドキュメントを Azure DocumentDB にアップロードし、そこから Search サービスとインデックスを構築しました。このプロジェクトを行った後に、Azure チームが提供しているサンプル アプリケーションの 1 つが似たような方針で作成されており、テートギャラリーが一般公開しているデータを利用していることに気が付きました。Azure チームのデモは bit.ly/2gxoHQL (英語) で使ってみることができます。このデモでは、ファセット ナビゲーションを使用するなど、Azure Search の他の機能も確認できます (ファセットは、インデックス定義時に設定するもう 1 つのオプションです)。 このサンプルでは JavaScript を使用し、URI を通じて Azure Search を直接操作しています。そのため、GitHub のコード (bit.ly/2gI1ej9) を確認することは勉強になるだけではなく、ロジックがどれほどシンプルになるかという点で、感心するような視点も得られます。これは、Azure Search が開発者に代わって複雑な処理すべてに対応するためです。

Azure Search を初めて取り上げた今回のコラムをお読みいただいたことで、先進的な Azure 専門家向けの、この大規模で圧倒されるようなサービスに対する最初の恐怖感が取り除かれたとしたらさいわいです。Azure は、厄介な作業を開発者が行わなくて済むように、そうした処理を引き受けるために存在しています。検索機能をアプリに組み込むという難しい作業を引き受けてくれる Azure Search はその好例といえるでしょう。


Julie Lerman は、バーモント ヒルズ在住の Microsoft MVP、.NET の指導者、およびコンサルタントです。世界中のユーザー グループやカンファレンスで、データ アクセスなどの .NET トピックについてプレゼンテーションを行っています。彼女のブログは thedatafarm.com/blog (英語) で、彼女は O'Reilly Media から出版されている『Programming Entity Framework』(2010 年) および『Code First』版 (2011 年)、『DbContext』版 (2012 年) を執筆しています。彼女の Twitter (@julielerman、英語) をフォローして、juliel.me/PS-Videos (英語) で彼女の Pluralsight コースをご覧ください。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの Pablo Castro に心より感謝いたします。
Pablo は、マイクロソフトのデータ グループのソフトウェア アーキテクトです。現在は、Azure Search のエンジニアリング部門のディレクターを務めています。Azure Search は、Azure クラウド プラットフォームの一部として提供されている、グローバル規模の Search-as-a-service (サービスとしての検索) 製品です。