292 lines
11 KiB
Markdown
292 lines
11 KiB
Markdown
|
|
# 📊 Система статистики авторов
|
|||
|
|
|
|||
|
|
Полная документация по расчёту и использованию статистики авторов в Discours.
|
|||
|
|
|
|||
|
|
## 🎯 Обзор
|
|||
|
|
|
|||
|
|
Система статистики авторов предоставляет многомерную оценку активности, популярности и вовлечённости каждого автора на платформе. Все метрики рассчитываются в реальном времени и кешируются для производительности.
|
|||
|
|
|
|||
|
|
## 📈 Метрики AuthorStat
|
|||
|
|
|
|||
|
|
```graphql
|
|||
|
|
# Статистика автора - полная метрика активности и популярности
|
|||
|
|
type AuthorStat {
|
|||
|
|
# Контент автора
|
|||
|
|
shouts: Int # Количество опубликованных статей
|
|||
|
|
topics: Int # Количество уникальных тем, в которых участвовал
|
|||
|
|
comments: Int # Количество созданных комментариев и цитат
|
|||
|
|
|
|||
|
|
# Взаимодействие с другими авторами
|
|||
|
|
coauthors: Int # Количество уникальных соавторов
|
|||
|
|
followers: Int # Количество подписчиков
|
|||
|
|
|
|||
|
|
# Рейтинговая система
|
|||
|
|
rating: Int # Общий рейтинг (rating_shouts + rating_comments)
|
|||
|
|
rating_shouts: Int # Рейтинг публикаций (сумма реакций LIKE/AGREE/ACCEPT/PROOF/CREDIT минус DISLIKE/DISAGREE/REJECT/DISPROOF)
|
|||
|
|
rating_comments: Int # Рейтинг комментариев (реакции на комментарии автора)
|
|||
|
|
|
|||
|
|
# Метрики вовлечённости
|
|||
|
|
replies_count: Int # Количество ответов на контент автора (ответы на комментарии + комментарии на посты)
|
|||
|
|
viewed_shouts: Int # Общее количество просмотров всех публикаций автора
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 📝 Контент автора
|
|||
|
|
|
|||
|
|
#### `shouts: Int`
|
|||
|
|
**Количество опубликованных статей**
|
|||
|
|
- Учитывает только статьи со статусом `published_at IS NOT NULL`
|
|||
|
|
- Исключает удалённые статьи (`deleted_at IS NULL`)
|
|||
|
|
- Подсчитывается через таблицу `shout_author`
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT sa.author, COUNT(DISTINCT s.id) as shouts_count
|
|||
|
|
FROM shout_author sa
|
|||
|
|
JOIN shout s ON sa.shout = s.id
|
|||
|
|
WHERE s.deleted_at IS NULL AND s.published_at IS NOT NULL
|
|||
|
|
GROUP BY sa.author
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `topics: Int`
|
|||
|
|
**Количество уникальных тем, в которых участвовал автор**
|
|||
|
|
- Подсчитывает уникальные темы через связку статей автора
|
|||
|
|
- Основано на таблицах `shout_author` → `shout_topic`
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT sa.author, COUNT(DISTINCT st.topic) as topics_count
|
|||
|
|
FROM shout_author sa
|
|||
|
|
JOIN shout s ON sa.shout = s.id AND s.deleted_at IS NULL AND s.published_at IS NOT NULL
|
|||
|
|
JOIN shout_topic st ON s.id = st.shout
|
|||
|
|
GROUP BY sa.author
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `comments: Int`
|
|||
|
|
**Количество созданных комментариев и цитат**
|
|||
|
|
- Включает реакции типа `COMMENT` и `QUOTE`
|
|||
|
|
- Исключает удалённые комментарии
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT r.created_by, COUNT(DISTINCT r.id) as comments_count
|
|||
|
|
FROM reaction r
|
|||
|
|
JOIN shout s ON r.shout = s.id AND s.deleted_at IS NULL
|
|||
|
|
WHERE r.deleted_at IS NULL AND r.kind IN ('COMMENT', 'QUOTE')
|
|||
|
|
GROUP BY r.created_by
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 👥 Взаимодействие с другими авторами
|
|||
|
|
|
|||
|
|
#### `coauthors: Int`
|
|||
|
|
**Количество уникальных соавторов**
|
|||
|
|
- Подсчитывает авторов, с которыми автор публиковал совместные статьи
|
|||
|
|
- Исключает самого автора из подсчёта
|
|||
|
|
- Учитывает только опубликованные и неудалённые статьи
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT sa1.author, COUNT(DISTINCT sa2.author) as coauthors_count
|
|||
|
|
FROM shout_author sa1
|
|||
|
|
JOIN shout s ON sa1.shout = s.id
|
|||
|
|
AND s.deleted_at IS NULL
|
|||
|
|
AND s.published_at IS NOT NULL
|
|||
|
|
JOIN shout_author sa2 ON s.id = sa2.shout
|
|||
|
|
AND sa2.author != sa1.author -- исключаем самого автора
|
|||
|
|
GROUP BY sa1.author
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `followers: Int`
|
|||
|
|
**Количество подписчиков**
|
|||
|
|
- Прямой подсчёт из таблицы `author_follower`
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT following, COUNT(DISTINCT follower) as followers_count
|
|||
|
|
FROM author_follower
|
|||
|
|
GROUP BY following
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### ⭐ Рейтинговая система
|
|||
|
|
|
|||
|
|
#### `rating: Int`
|
|||
|
|
**Общий рейтинг автора**
|
|||
|
|
- Сумма `rating_shouts + rating_comments`
|
|||
|
|
- Агрегированная метрика популярности контента
|
|||
|
|
|
|||
|
|
#### `rating_shouts: Int`
|
|||
|
|
**Рейтинг публикаций автора**
|
|||
|
|
- Сумма всех реакций на статьи автора
|
|||
|
|
- Положительные реакции: `LIKE`, `AGREE`, `ACCEPT`, `PROOF`, `CREDIT` (+1)
|
|||
|
|
- Отрицательные реакции: `DISLIKE`, `DISAGREE`, `REJECT`, `DISPROOF` (-1)
|
|||
|
|
- Нейтральные реакции: остальные (0)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT sa.author,
|
|||
|
|
SUM(CASE
|
|||
|
|
WHEN r.kind IN ('LIKE', 'AGREE', 'ACCEPT', 'PROOF', 'CREDIT') THEN 1
|
|||
|
|
WHEN r.kind IN ('DISLIKE', 'DISAGREE', 'REJECT', 'DISPROOF') THEN -1
|
|||
|
|
ELSE 0
|
|||
|
|
END) as rating_shouts
|
|||
|
|
FROM shout_author sa
|
|||
|
|
JOIN shout s ON sa.shout = s.id AND s.deleted_at IS NULL AND s.published_at IS NOT NULL
|
|||
|
|
JOIN reaction r ON s.id = r.shout AND r.deleted_at IS NULL
|
|||
|
|
GROUP BY sa.author
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `rating_comments: Int`
|
|||
|
|
**Рейтинг комментариев автора**
|
|||
|
|
- Аналогичная система для реакций на комментарии автора
|
|||
|
|
- Подсчитывает реакции на комментарии через `reply_to`
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT r1.created_by,
|
|||
|
|
SUM(CASE
|
|||
|
|
WHEN r2.kind IN ('LIKE', 'AGREE', 'ACCEPT', 'PROOF', 'CREDIT') THEN 1
|
|||
|
|
WHEN r2.kind IN ('DISLIKE', 'DISAGREE', 'REJECT', 'DISPROOF') THEN -1
|
|||
|
|
ELSE 0
|
|||
|
|
END) as rating_comments
|
|||
|
|
FROM reaction r1
|
|||
|
|
JOIN reaction r2 ON r1.id = r2.reply_to AND r2.deleted_at IS NULL
|
|||
|
|
WHERE r1.deleted_at IS NULL AND r1.kind IN ('COMMENT', 'QUOTE')
|
|||
|
|
GROUP BY r1.created_by
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 🔄 Метрики вовлечённости
|
|||
|
|
|
|||
|
|
#### `replies_count: Int`
|
|||
|
|
**Количество ответов на контент автора**
|
|||
|
|
- **Комплексная метрика**, включающая:
|
|||
|
|
1. **Ответы на комментарии автора** (через `reply_to`)
|
|||
|
|
2. **Комментарии на посты автора** (прямые комментарии к статьям)
|
|||
|
|
|
|||
|
|
Логика расчёта:
|
|||
|
|
```python
|
|||
|
|
# Ответы на комментарии
|
|||
|
|
replies_to_comments = COUNT(r2) WHERE r1.created_by = author AND r2.reply_to = r1.id
|
|||
|
|
|
|||
|
|
# Комментарии на посты
|
|||
|
|
comments_on_posts = COUNT(r) WHERE sa.author = author AND r.shout = s.id
|
|||
|
|
|
|||
|
|
# Итого
|
|||
|
|
replies_count = replies_to_comments + comments_on_posts
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `viewed_shouts: Int`
|
|||
|
|
**Общее количество просмотров всех публикаций автора**
|
|||
|
|
- Интеграция с `ViewedStorage` (Google Analytics)
|
|||
|
|
- Суммирует просмотры всех статей автора
|
|||
|
|
- Обновляется асинхронно из внешних источников
|
|||
|
|
|
|||
|
|
## 🔍 API использования
|
|||
|
|
|
|||
|
|
### GraphQL запрос
|
|||
|
|
|
|||
|
|
```graphql
|
|||
|
|
query LoadAuthors($by: AuthorsBy, $limit: Int, $offset: Int) {
|
|||
|
|
load_authors_by(by: $by, limit: $limit, offset: $offset) {
|
|||
|
|
id
|
|||
|
|
slug
|
|||
|
|
name
|
|||
|
|
bio
|
|||
|
|
pic
|
|||
|
|
stat {
|
|||
|
|
shouts
|
|||
|
|
topics
|
|||
|
|
coauthors
|
|||
|
|
followers
|
|||
|
|
rating
|
|||
|
|
rating_shouts
|
|||
|
|
rating_comments
|
|||
|
|
comments
|
|||
|
|
replies_count
|
|||
|
|
viewed_shouts
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Параметры сортировки
|
|||
|
|
|
|||
|
|
```graphql
|
|||
|
|
# Сортировка по количеству публикаций
|
|||
|
|
{ "order": "shouts" }
|
|||
|
|
|
|||
|
|
# Сортировка по общему рейтингу
|
|||
|
|
{ "order": "rating" }
|
|||
|
|
|
|||
|
|
# Сортировка по вовлечённости
|
|||
|
|
{ "order": "replies_count" }
|
|||
|
|
|
|||
|
|
# Сортировка по просмотрам
|
|||
|
|
{ "order": "viewed_shouts" }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## ⚡ Производительность
|
|||
|
|
|
|||
|
|
### Кеширование
|
|||
|
|
- **Redis кеш** для результатов запросов
|
|||
|
|
- **Ключи кеша**: `authors:stats:limit={limit}:offset={offset}:order={order}`
|
|||
|
|
- **TTL**: Настраивается в `cache.py`
|
|||
|
|
|
|||
|
|
### Оптимизации SQL
|
|||
|
|
- **Batch запросы** для получения статистики всех авторов одновременно
|
|||
|
|
- **Подготовленные параметры** для защиты от SQL-инъекций
|
|||
|
|
- **Индексы** на ключевых полях (`author_id`, `shout_id`, `reaction.kind`)
|
|||
|
|
|
|||
|
|
### Сортировка
|
|||
|
|
- **SQL-уровень сортировки** для метрик статистики
|
|||
|
|
- **Подзапросы с JOIN** для производительности
|
|||
|
|
- **COALESCE** для обработки NULL значений
|
|||
|
|
|
|||
|
|
## 🧪 Тестирование
|
|||
|
|
|
|||
|
|
### Unit тесты
|
|||
|
|
```python
|
|||
|
|
# Тестирование расчёта статистики
|
|||
|
|
async def test_author_stats_calculation():
|
|||
|
|
# Создаём тестовые данные
|
|||
|
|
# Проверяем корректность расчёта каждой метрики
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# Тестирование сортировки
|
|||
|
|
async def test_author_sorting():
|
|||
|
|
# Проверяем сортировку по разным полям
|
|||
|
|
pass
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Интеграционные тесты
|
|||
|
|
- Тестирование с реальными данными
|
|||
|
|
- Проверка производительности на больших объёмах
|
|||
|
|
- Валидация кеширования
|
|||
|
|
|
|||
|
|
## 🔧 Конфигурация
|
|||
|
|
|
|||
|
|
### Переменные окружения
|
|||
|
|
```bash
|
|||
|
|
# Google Analytics для просмотров
|
|||
|
|
GOOGLE_KEYFILE_PATH=/path/to/service-account.json
|
|||
|
|
GOOGLE_PROPERTY_ID=your-property-id
|
|||
|
|
|
|||
|
|
# Redis для кеширования
|
|||
|
|
REDIS_URL=redis://localhost:6379
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Настройки реакций
|
|||
|
|
Типы реакций определены в `orm/reaction.py`:
|
|||
|
|
```python
|
|||
|
|
# Положительные (+1)
|
|||
|
|
POSITIVE_REACTIONS = ["LIKE", "AGREE", "ACCEPT", "PROOF", "CREDIT"]
|
|||
|
|
|
|||
|
|
# Отрицательные (-1)
|
|||
|
|
NEGATIVE_REACTIONS = ["DISLIKE", "DISAGREE", "REJECT", "DISPROOF"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🚀 Развитие
|
|||
|
|
|
|||
|
|
### Планируемые улучшения
|
|||
|
|
- [ ] Исторические тренды статистики
|
|||
|
|
- [ ] Сегментация по периодам времени
|
|||
|
|
- [ ] Дополнительные метрики вовлечённости
|
|||
|
|
- [ ] Персонализированные рекомендации на основе статистики
|
|||
|
|
|
|||
|
|
### Известные ограничения
|
|||
|
|
- Просмотры обновляются с задержкой (Google Analytics API)
|
|||
|
|
- Большие объёмы данных могут замедлять запросы без кеша
|
|||
|
|
- Сложные запросы сортировки требуют больше ресурсов
|