この数日間、Azure Search をいろいろと触ってきましたが、実際のサービスっぽい場面で使うために真面目に Azure Search を使ったサービスを作りました。
http://jazugsearch.azurewebsites.net/
サービス自体は Twitter の検索 API を使って #jazug 付きのツイートを拾ってきて、それを Azure Search のインデックスに追加しているだけなのですが、サイドバーに絞り込み機能としてユーザー名でのファセットと、期間で絞り込む機能を実装してあります。
インデックスは以下のようなコードで作成しました。
var client = new IndexManagementClient(connection); await client.CreateIndexAsync(new Index("tweets") .WithStringField("id", p => p.IsKey().IsRetrievable()) .WithStringField("status", p => p.IsSearchable().IsRetrievable()) .WithStringField("name", p => p.IsRetrievable()) .WithStringField("screenName", p => p.IsFilterable().IsRetrievable().IsFacetable()) .WithStringField("profileImageUrl", p => p.IsRetrievable()) .WithDateTimeField("createdOn", p => p.IsFilterable().IsSortable().IsRetrievable()) );
検索に利用しないユーザー名とプロフィールアイコンの URL もインデックスに追加してあります。フィールドの定義時に IsRetrievable は最低でも付けておかないと、全く意味のないデータになるので注意。
絞り込みからユーザー名を選択すると、そのユーザーのツイートだけ絞り込んで表示されます。
ユーザー名は screenName フィールドに入っていて、インデックスを作るときに IsFilterable を追加しているので、SearchQuery の Filter メソッドで指定できるようになっています。
// No.1 のツイートだけ表示する query.Filter("screenName eq 'kamebuchi'");
Filter には OData のフィルター式が使えるようになっています。このあたり LINQ で何とかならないかなと思いますが、今はとりあえず手書きしました。
後はページングが必要だと思ったので、前後 1 ページずつしか移動できないページングを実装しました。
// 20 件目から 10 件だけ取得する var query = new SearchQuery(q) .Facet("screenName") .Skip(20) .Top(10);
これも OData の $skip と $top が REST API に実装されているので、SearchQuery の Skip と Top メソッドを使って簡単に書けます。
全体の件数を取りたい場合には SearchQuery の Count メソッドに true を渡すと返ってくるようになりますが、パフォーマンスに影響が出る点とあくまでも推定値でしかないことに注意する必要があります。
おまけ
Azure Search のバックエンドはオリジナルではなく、Elasticsearch を使っているようです。
新たな検索サービス「Azure Search」は基礎となるフルテキスト検索エンジンとして、オープンソースの分散検索技術「Elasticsearch」を使用している。Azure SearchサービスはElasticsearchの一部の機能を利用可能にしているものの、依然としてMicrosoftのマネージドサービスである。
MS、「Azure DocumentDB」「Azure Search」のプレビュー版を公開 - ZDNet Japan
Elasticsearch を使っていることは Azure のフォーラムでも言及されていました。
Azure Search Service = Hosted Elastic Search?
関係ないですが、一緒に登場した DocumentDB はオリジナルのエンジンを使っているらしいです。