GYAOのtsです。
我々のチームは、オールパブリッククラウドで、Microservice Architectureを採用した次期バックエンドを設計中です。
経緯
前回の投稿で、Eventhubs経由で登録することができたので、あとは検索機能を作らないとということで、SortとPagenationのついたsearchAPIをAzureFunctionsで実装してみた。
やりたいこと
下記のようなデータがCosmosDBに保存されている
{
"Contents": [
{
"ContentsId": "c0001",
"Time": 1500532318
},
{
"ContentsId": "c0006",
"Time": 1500535647
},
{
"ContentsId": "c0002",
"Time": 1500538621
}
],
"Pkey": "reserve",
"id": "user1"
}
このContents内をTime(unix timestamp)順にSortしたり、Pagenation(start, end)で絞ったりしたい。
AzureForumを見る限り、現時点ではTOPのサポートしかない模様・・・。これだとページネーションできない。
しかも今回は1ドキュメントのArrayになっているnestedオブジェクトのSortやPagenationなので、そもそも用途が違う気がする。。。
AzureCosmosDBのUDF(user defined functions)を利用して作ってみることにした。
udfで作成して、functionsで設定するSQLに埋め込むような形で行こうかと。
実装
UDF
function sort(contents, start, end, sort) {
function compareTime(a, b) {
if (sort == 'DESC') {
return b.Time - a.Time;
}
else{
return a.Time - b.Time;
}
}
return contents.sort(compareTime).slice(start, end);
}
SQL
SQLには下記のような形で埋め込み、更にFunctionsの統合のsqlに設定する。
udfを使用する際はudf.[ID]でアクセスできる。
SELECT c.id, c.Pkey, udf.sort(c.Contents, {start}, {end}, {order}) as Contents FROM c where c.id = {docId}
Functions
下記の通り。
http-inputのルートテンプレートで必要な引数をもらう設定
そのまま引数に設定する。
気をつけるポイントは、inDocumentsをIEnumerable 型にすること。
SQLで取得する場合はID指定であっても複数ドキュメント限定らしい。
#r "Newtonsoft.Json"
using System;
using System.Net;
using Newtonsoft.Json;
public class Input
{
public string docId { get; set; }
}
public static HttpResponseMessage Run(Input input, int start, int end, string order,
HttpRequestMessage req, IEnumerable<dynamic> inputDocuments, TraceWriter log)
{
var inputDocument = inputDocuments.First();
log.Info($"invoked. start:{start}. limit:{end}. order:{order}");
if (inputDocument != null)
{
var responseContent = JsonConvert.SerializeObject(inputDocument);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(responseContent, Encoding.UTF8, "application/json");
return response;
}
else
{
//not found. do nothing.
return req.CreateResponse(HttpStatusCode.NotFound);
}
}
以上。
Test
取得完了。さくっと行けた。startとendだけだと利便性が悪いかもなので、limitとoffsetにしたほうがいいかも。
とりあえずプロトタイプはできた。
所感
パフォーマンス面に懸念は残るが、現時点ではこうするか、Functions内C#でSortの二択になりそうな気がする。
チーム内で相談した上で、今後ストレステスト等を経て決断していきたいと思う。