Получение рейтинга слов по дате на основе частоты в PostgreSQL

#sql #postgresql #count #greatest-n-per-group #lateral-join

#sql #postgresql #количество #наибольшее число слов на группу #боковое соединение

Вопрос:

У меня есть база данных, в которой хранятся данные Twitter:

         Create Table tweet(
            ID BIGINT UNIQUE,
            user_ID BIGINT,
            created_at TIMESTAMPTZ,
            tweet TEXT;
 

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

Пример:

 ("word1":[1,20,22,23,24,25,26,27,28,29,30,29,28,27,26,25,26,27,28,29,30,29,28,29,28,27,28,29,30,30,...],
'word2' [...])
 

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

Текущий запрос:

     SELECT word, count(*)
    FROM (
        SELECT regexp_split_to_table(
            regexp_replace(tweet_clean, 'y(rt|co|https|amp|f)y', '', 'g'), 's ')
        AS word
    FROM tweet
    ) t
    GROUP BY word
    ORDER BY count(*) DESC
    LIMIT 10;
 

Который возвращает:

 [('vaccine', 286669),
 ('covid', 213857),
 ('yum', 141345),
 ('pfizer', 39532),
 ('people', 28960),
 ('beer', 27117),
 ('say', 24569),
 ('virus', 23682),
 ('want', 21988),
 ('foo', 19823)]
 

Комментарии:

1. вы можете использовать rank() или dense_rank() , чтобы получить рейтинг.

Ответ №1:

Если вы хотите получать 10 лучших слов в день, вы можете сделать:

 select *
from (
    select date_trunc('day', created_at) as created_day, word, count(*) as cnt,
        rank() over(partition by date_trunc('day', created_at) order by count(*) desc) rn
    from tweet t
    cross join lateral regexp_split_to_table(
        regexp_replace(tweet_clean, 'y(rt|co|https|amp|f)y', '', 'g'),
        's '
    ) w(word)
    group by created_day, word
) t
where rn <= 10
order by created_day, rn desc
 

Ответ №2:

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

 select wd.word,
       array_agg(day_rank) over (order by created_day) as ranks
from (select date_trunc('day', t.created_at) as created_day, w.word,
             sum(count(*)) as total_cnt,
             rank() over(partition by date_trunc('day', created_at) order by count(*) desc) as day_rank
      from tweet t cross join lateral
           regexp_split_to_table(regexp_replace(tweet_clean, 'y(rt|co|https|amp|f)y', '', 'g'
                                               ), 's '
                                ) w(word)
      group by created_day, word
     ) wd
order by total_cnt desc
limit 10;
 

Проблема здесь в том, что массивы могут быть разной длины. В Postgres вы можете добавить дополнительные значения, но не совсем ясно, что должно быть размещено там для ранжирования.

Проблема в том, что ранжирование производится за день. Итак, рассмотрим два дня, один из которых содержит 100 слов, а другой — 10 слов. Во-первых, рейтинг «10» — это очень высокий рейтинг. Рейтинг 10 во втором очень низкий.

Я мог бы предложить вам подумать об этой проблеме и задать новый вопрос, если вам нужна помощь в ее решении.

Комментарии:

1. Спасибо за ваш ответ. Я получил сообщение об ошибке при выполнении вашего запроса: psycopg2.errors. Синтаксическая ошибка: синтаксическая ошибка в СТРОКЕ 3 «over» или рядом с ней: array_agg(day_rank по порядку на created_day) в качестве ранга…

2. @mehsheenman . . . Упс, некоторые круглые скобки отсутствовали.