Серебряный значок за _каждые_ 5 бронзовых значков

Мы создали бронзовый значок Пользователи помогают пользователям для тех, кто пытается помочь другим участникам. Он выдаётся вручную (чтобы отличать искренние попытки помочь от сообщений в стиле «тоже мне»).

За каждые 5 бронзовых значков мы хотим вручать серебряный значок Неоценимый вклад.

Составленный мной SQL-запрос находит двух нужных пользователей, но выдаёт результат только по одному разу для каждого:

SELECT user_id, current_timestamp AS granted_at 
FROM user_badges
WHERE badge_id = 110 -- Пользователи помогают пользователям
    AND (:backfill OR user_id IN (:user_ids))
GROUP BY user_id
HAVING COUNT(*) >= 5

Не хватает ли мне какой-то :magic_wand: магии в SQL, или множитель применяется вне его?

Также мне совершенно непонятно, как именно работает логика подсчёта, чтобы мои два пользователя не получали новые значки каждый день (этот запрос выполняется по ночному триггеру), даже если они не заработали 5 новых бронзовых значков.

Есть ли какое-то руководство по этому вопросу, которое я не смог найти в поиске?

Хорошо, более глубокий поиск привёл меня к теме, которая ведёт к руководству

Вопрос с backfill всё ещё немного запутанный, но я решил (очевидно!) протестировать это на нашем тестовом экземпляре. Думаю, backfill выполняется ночью, так что завтра я узнаю больше.

Если вы не установите галочку «Можно выдавать несколько раз», то значок не будет присвоен более одного раза, даже если пользователь снова (или несколько раз) соответствует критериям. :+1:


Хорошо, я перечитал ваш пост более внимательно и думаю, что теперь лучше понимаю, к чему вы стремитесь.

Исходя из текущего SQL, эти пользователи получат серебряный значок только один раз, даже если разрешить выдавать его несколько раз:

  • Я создал соответствующие значки на своём тестовом сайте (включив возможность многократной выдачи)
  • Выдал 5 бронзовых значков и запустил фоновую задачу для выдачи значка (серебряный значок успешно выдан :partying_face:)
  • Затем я снова запустил задачу BadgeGrant, и второй раз серебряный значок не был выдан
  • После этого я увеличил количество бронзовых значков до 11 и снова запустил задачу выдачи значков
  • Второй серебряный значок не был выдан

Я проверил это «несколько раз»

но награда была выдана только один раз, хотя должно было быть два раза

Итак… что мне нужно сделать, чтобы пользователь с 12 бронзовыми значками получил заслуженные им 2 серебряных?

Хороший вопрос, и я пока не знаю точного ответа. :slight_smile:

Пока думаю над вариантом с использованием RANK, но, возможно, я просто хватаюсь за соломинку… :thinking:


Примерный прототип...
WITH badge_count AS (

    SELECT 
        user_id,
        granted_at,
        RANK() OVER (PARTITION BY user_id ORDER BY granted_at ASC) AS rank
    FROM user_badges
    WHERE badge_id = 110

)

SELECT user_id, granted_at
FROM badge_count
WHERE rank IN (5,10,15,20,25,30,35,40,45,50)

Хорошо, вторая попытка — теперь с использованием ROW_NUMBER:

WITH badge_count AS (

    SELECT 
        user_id,
        granted_at,
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY granted_at ASC) AS row
    FROM user_badges
    WHERE badge_id = 110

)

SELECT user_id, granted_at
FROM badge_count
WHERE row % 5 = 0

Однако, после дополнительных тестов, это работает корректно в предпросмотре, но не срабатывает многократно при фактическом запуске задачи badge grant. Пока не совсем понимаю, почему. :thinking:

Я сам запутался. Сейчас заварю чай и попробую собраться с мыслями. :slight_smile:

Что ж… Я дал своему пользователю ещё 4 бронзовых значка вчера, чтобы проверить, добавит ли ночной запуск хотя бы новый значок, который он только что «заработал». (Я подумал, что если придётся догонять остальных вручную, я смогу это сделать.) Но даже это не сработало.

Я не могу помочь вам с этим запросом, но рекомендую обратиться за помощью к боту Discourse AI — выберите значок бота в верхней части
image —> GPT-4 —> SQL Helper.

Я обнаружил, что он отлично справляется с созданием запросов для Data Explorer, достаточно просто описать, что нужно, и, полагаю, он сможет помочь и с запросами по значкам.

У Toni не у всех это есть :shushing_face: Вы заставите людей позавидовать. :slight_smile: (хотя у @ganncamp это есть, так что это вариант)

Но… Я почти уверен, что мой запрос корректен. В предпросмотре он выбирает правильные записи, но при использовании триггера «Обновлять ежедневно» награждает только одну запись.

Я настроил ещё один, почти такой же, для теста, основанный на бейдже «каждые 5 сообщений в конкретной теме», используя триггер «когда пользователь создаёт или редактирует сообщение» — и тот работает идеально. Я уточняю, в чём может быть разница…

Вот SQL для этого тестового бейджа, чтобы сравнить, если кто-то сможет что-то заметить:

WITH post_count AS (

    SELECT 
        user_id,
        id,
        created_at,
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at ASC) AS row
    FROM posts
    WHERE topic_id = 864

)

SELECT user_id, created_at granted_at, id post_id
FROM post_count
WHERE row % 5 = 0
  AND (:backfill OR id IN (:post_ids))

У меня есть к нему доступ, @tpetrov, но мои попытки его использовать были… не слишком успешными. Или, может, я просто отлично умею задавать сложные вопросы? :laughing:

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

Кажется, в подобных случаях хорошо работают «эскалирующие» значки (как, например, значки «Решено»). Например, серебряный за 30 и золотой за 100, если это может быть жизнеспособной альтернативой?

Так что… даже если бронзовые значки выдаются на основе постов… это не считается, верно?

Не знаю. Не думаю, что я понял вопрос. :laughing:

Полагаю, предложение заключается не в том, чтобы найти 5 значков, а 5 постов, в которых был присвоен значок? Я могу это сделать. Я уже более или менее сделал это в своём отчёте «Найти новые посты для выдачи значков».

Хм. :thinking: Кажется, я понимаю, к чему вы клоните. Попробую ещё раз…


@ganncamp — думаю, у нас могут получиться успехи… :slight_smile:

Исходя из того, что значок Bronze Badge A выдаётся либо через гаечный ключ в посте, либо при указании причины на странице /admin/users/{user_id}/{username}/badges:

Тогда, думаю, это действительно возможно. :partying_face:

WITH badge_count AS (

    SELECT 
        user_id,
        granted_at,
        post_id,
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY granted_at DESC) AS row
    FROM user_badges
    WHERE badge_id = 110
      AND post_id IS NOT NULL
)

SELECT user_id, granted_at, post_id
FROM badge_count
WHERE row % 5 = 0
  AND (:backfill OR post_id IN (:post_ids))

(Добавление условия AND post_id IS NOT NULL защищает от ситуации, когда значок выдаётся без указания причины; иначе запрос сломается)

Я только что протестировал это, ускорил процесс, запустив фоновую задачу GrantBadge, и мой тестовый пользователь наконец получил полный зачёт, который заслуживает. :slight_smile:

Затем я вручил ему ещё 5 значков Badge A за 5 разных постов и запустил запрос снова: :tada:

Спасибо @JammyDodger! :tada: :tada: :tada:

Я настроил это на тестовом экземпляре (не то чтобы я не доверял тебе :joy:) и надеюсь внедрить это в продакшн на этой неделе! :star_struck:

И… не слишком ли рано спрашивать, чтобы руководство было обновлено с учётом того, что ты узнал в ходе этого квеста? :smiley:

Конечно. «Доверяй, но проверяй» — действительно разумный подход. :slight_smile:

Я посмотрю, не удастся ли добавить кое-что от себя. :slight_smile: :+1:

Ну… когда задача запускалась ночью, мой пользователь с 6 бронзовыми значками получил 1 серебряный :white_check_mark:, а мой пользователь с 13 бронзовыми значками получил… тоже 1 серебряный :slightly_frowning_face:.

Этот раздел в руководстве [Creating triggered custom badge queries] заставил меня подумать, что отдельная явная задача для заполнения данных не требуется.

Поскольку ежедневно выполняется полное заполнение данных, вы должны это учитывать и предусмотреть обработку параметра :backfill.

Как мне получить награды для пользователей, которые уже заработали более одного серебряного значка? Мне нужно сделать это вручную?

Backfill — это ежедневная задача. Триггер «Обновлять ежедневно» по сути выполняет именно это, тогда как другие триггеры срабатывают практически мгновенно (например, если значок использует условие «когда пользователь создаёт или редактирует пост», не нужно ждать до утра, чтобы его вручить).

Можешь прислать скриншот своего значка, чтобы я мог увидеть, в чём может быть разница?

Вот что получилось:

Кстати, некоторые из этих пунктов я проверил, потому что… не знаю, что делаю :joy:

И у вашего пользователя с 13 значками «Badge A» заполнены причины, когда вы просматриваете страницу /admin/users/{user_id}/{username}/badges?

У вас совпадают важные части. :slight_smile: Остальные также корректны, но являются необязательными.

Вы запускаете это на своём тестовом окружении (staging) или на собственном хостинге для тестирования?

Ого! Загадка разгадана!

Я предполагал, что задача выполняется в ранние утренние часы (по моему времени).

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

Кстати, это происходит на моём тестовом сайте.

Полагаю, второй бейдж будет выдан через несколько часов, но мне бы хотелось видеть выдачу нескольких бейджей одновременно. Произойдёт ли это, если я отзову серебряный бейдж? Получит ли он два новых серебряных бейджа через… 2 часа?