はじめに
Aerospike Go Clientを利用している箇所で改修をする際につまづいたところがあるのでまとめます
問題
Aerospikeで日付でフィルタリングをしていたのですが、そこから別の条件をANDで検索したレコードすべてをほしいなと思ったのですが、なかなかできずに困りました
// クエリのステートメントを設定します。
stmt := as.NewStatement("namespace", "set")
// 時間範囲をUnixタイムスタンプに変換します。
fromTimestamp := time.Date(2023, 6, 1, 0, 0, 0, 0, time.UTC).Unix()
toTimestamp := time.Date(2023, 6, 30, 0, 0, 0, 0, time.UTC).Unix()
// タイムスタンプの範囲フィルタを設定します。
stmt.SetFilters(as.NewRangeFilter("timestamp", fromTimestamp, toTimestamp))
// ここで、別の条件も追加したい
// クエリを実行し、結果のレコードを取得します。
recordSet, err := client.Query(nil, stmt)
if err != nil {
stmt.SetFilters
をもう一つ用意しようとしましたが、上書きされてしまうので実現しませんでした
わかったこと
ChatGPTにきいたところ以下のことがわかりました
Aerospikeのクエリエンジンは、1つのインデックスに対して1つの範囲フィルターしか許容しないため、複数フィールドのAND条件を直接適用することはできません
そもそも複数条件で検索することが機能的にできませんでした
回避策1
AerospikeのUser-Defined Function (UDF) という機能を利用することで複数条件のようなことができます
filter_by_application.lua
function filter_by_application(rec)
if rec['application'] == 'app' then
return true
else
return false
end
end
このようなlua
を書いてサーバーに登録して使います
stmt.SetAggregateFunction("application_filter", "filter_by_application", nil, true)
サーバーに追加しないといけないので動いているサーバーに追加するというのは大変です
回避策2
Goで制御する
if appVal, exists := res.Record.Bins["application"]; exists {
if appVal == "app" {
fmt.Println(res.Record)
}
}
大規模なデータでは時間がかかるのがネックです
おわりに
今回はGo側に制御コードをいれることで回避しました
参考