次のようなサンプルドキュメントを含むMongoDBのコレクションがあります-
{
"_id" : ObjectId("58114e5e43d6420b7db4e15c"),
"browser" : "Chrome",
"name": "hyades",
"country" : "in",
"day" : "16-10-21",
"ip" : "0.0.0.0",
"class" : "A123"
}
問題文
個別の数の IP をフェッチしながら、任意のフィールドをグループ化できるはずです。
集計クエリ -
[
{$group: {_id: '$class', ip_arr: {$addToSet: '$ip'}}},
{$project: {class: '$_id.class', ip: {$size: '$ip_arr'}}}
]
望ましい結果が得られますが、遅いです。同様にip
、別のものを使用してカウントするの$group
は遅いです。出力は -
[{class: "A123",ip: 42},{class: "B123", ip: 56}..]
私が試したこと
これにはHyperloglogの使用を検討しました。Redis 実装を使ってみました。データ全体をストリーミングして、グループ化したものだけを投影し、PFADD
それを対応する redis の hyperloglog 構造に変換しようとしました。
ロジックは次のようになります-
var stream = Model.find({}, {ip: 1, class: 1}).stream();
stream.on('data', function (doc) {
var hash = "HLL/" + doc.class;
client.pfadd(hash, doc.ip);
});
これを100万以上のデータポイントで実行しようとしました。ストリーミングされるデータのサイズは約 1GB で、Mongo と Node サーバー間の接続は 1 Gbps でした。このコードは十分に高速に実行されると予想していました。ただし、かなり遅かったです (MongoDB でのカウントよりも遅かった)。
私が考えたが実装しなかったもう 1 つのことは、各クラスのバケットを事前に作成し、流入するデータに合わせてリアルタイムでバケットをインクリメントすることでした。
私が間違っている可能性があること、またはここで改善できることを提案して、hyperloglog を最大限に活用できるようにします (私は Redis に制約されておらず、あらゆる実装にオープンです)。