Если это применимо в вашем случае, я бы рассмотрел использование alphaTokens в качестве более эффективного.
SELECT
category,
arrayJoin(arrayFilter(x -> NOT has(['a', 'the', 'but' /*.. exclude stopwords */], x), alphaTokens(text))) token,
count() count
FROM
(
/* test data */
SELECT data.1 AS rev_id, data.2 AS place_id, data.3 AS stars, data.4 AS category, data.5 AS text
FROM
(
SELECT arrayJoin([
(1, 12, 3, 'Food', 'Nice food but a bad dirty place.'),
(4, 12, 3, 'Food', ' the the the the good food ..'),
(2, 31, 4, 'Sport', 'Not bad,,, they have everything.'),
(3, 55, 1, 'Bar', 'Poor place,bad audience..')]) AS data
)
)
GROUP BY category, token
ORDER BY count DESC
LIMIT 5;
/*
┌─category─┬─token────┬─count─┐
│ Food │ food │ 2 │
│ Food │ bad │ 1 │
│ Bar │ audience │ 1 │
│ Food │ Nice │ 1 │
│ Bar │ Poor │ 1 │
└──────────┴──────────┴───────┘
*/
Пример использования topK :
SELECT
category,
arrayReduce('topK(3)',
arrayFilter(x -> (NOT has(['a', 'the', 'but' /*.. exclude stopwords */], x)), groupArrayArray(alphaTokens(text)))) AS result
FROM
(
/* test data */
SELECT data.1 AS rev_id, data.2 AS place_id, data.3 AS stars, data.4 AS category, data.5 AS text
FROM
(
SELECT arrayJoin([
(1, 12, 3, 'Food', 'Nice food but a bad dirty place.'),
(4, 12, 3, 'Food', ' the the the the good food ..'),
(2, 31, 4, 'Sport', 'Not bad,,, they have everything.'),
(3, 55, 1, 'Bar', 'Poor place,bad audience..')]) AS data
)
)
GROUP BY category;
/* result
┌─category─┬─result─────────────────┐
│ Bar │ ['Poor','place','bad'] │
│ Food │ ['food','Nice','bad'] │
│ Sport │ ['Not','bad','they'] │
└──────────┴────────────────────────┘
*/
ps: вероятно, имеет смысл понизить все строки / токены перед обработкой