Подсчет уникальных с помощью Redis и MongoDB (HyperLogLog)

У меня есть коллекция в 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 в соответствующую структуру Hyperloglog в Redis.

Логика выглядит так -

var stream = Model.find({}, {ip: 1, class: 1}).stream();
stream.on('data', function (doc) {
    var hash = "HLL/" + doc.class;
    client.pfadd(hash, doc.ip);
});

Я пытался запустить это для миллиона с лишним точек данных. Размер передаваемых данных составлял около 1 ГБ при скорости соединения 1 Гбит/с между Mongo и сервером Node. Я ожидал, что этот код будет работать достаточно быстро. Однако это было довольно медленно (медленнее, чем подсчет в MongoDB).

Еще одна вещь, о которой я подумал, но не реализовал, заключалась в том, чтобы предварительно создавать сегменты для каждого класса и увеличивать их в реальном времени по мере поступления данных. Но память, необходимая для поддержки любой произвольной группировки, была огромной, поэтому от этой идеи пришлось отказаться.

Пожалуйста, предложите, что я могу делать неправильно или что я мог бы улучшить здесь, чтобы я мог в полной мере использовать гиперлоглог (я не ограничен Redis и открыт для любой реализации)


person hyades    schedule 17.11.2016    source источник
comment
Каковы ваши индексы в этой коллекции?   -  person dyouberg    schedule 17.11.2016
comment
Ваш вопрос должен был понять, а заголовок вводит в заблуждение.   -  person styvane    schedule 17.11.2016
comment
Индексы @dyouberg указаны по дню, имени, классу, если это имеет значение.   -  person hyades    schedule 17.11.2016
comment
Если вы хотите использовать Hyperloglog для подсчета, вам следует вызывать PFADD каждый раз, когда вы вставляете элемент в MongoDB. Текущее решение не будет быстрее, так как вам все равно придется читать данные из MongoDB.   -  person for_stack    schedule 18.11.2016
comment
@for_stack Если я правильно понял, я бы предварительно вычислил количество для каждого возможного значения по всем возможным вещам для группировки. Стоимость памяти здесь оказалась очень высокой.   -  person hyades    schedule 18.11.2016


Ответы (1)


Отказ от ответственности: я использовал Redis только из C++ и Python, так что это может не помочь, но...

PFADD поддерживает несколько аргументов; В системе, где я использовал Redis HLL для подсчета уникальных записей, я обнаружил, что их пакетная обработка и отправка одного PFADD со многими (порядка 100) элементами за один раз привели к значительному ускорению — предположительно из-за того, что не используется клиент Redis. поездка в оба конца.

person codedstructure    schedule 21.11.2016
comment
Да, это, безусловно, одна оптимизация. Тем не менее, я использую Redis на том же компьютере, поэтому время кругового обхода не будет потрачено впустую. Хотите знать, будет ли хорошей идеей потоковая передача всех данных в Redis? - person hyades; 21.11.2016
comment
Я также использовал Redis на том же компьютере (локальный хост TCP, не пробовал сокеты unix), и ускорение от PFADD, о котором я упоминал выше, было в этой настройке. - person codedstructure; 21.11.2016