### 👥 Author Statistics Enhancement - **📊 Полная статистика авторов**: Добавлены все недостающие счётчики в AuthorStat - `topics`: Количество уникальных тем, в которых участвовал автор - `coauthors`: Количество соавторов - `replies_count`: Количество вызванных комментариев - `rating_shouts`: Рейтинг публикаций автора (сумма реакций LIKE/AGREE/ACCEPT/PROOF/CREDIT минус DISLIKE/DISAGREE/REJECT/DISPROOF) - `rating_comments`: Рейтинг комментариев автора (реакции на его комментарии) - `replies_count`: Количество вызванных комментариев - `comments`: Количество созданных комментариев и цитат - `viewed_shouts`: Общее количество просмотров всех публикаций автора - **🔄 Улучшенная сортировка**: Поддержка сортировки по всем новым полям статистики - **⚡ Оптимизированные запросы**: Batch-запросы для получения всей статистики одним вызовом - **🧪 Подробное логирование**: Эмодзи-маркеры для каждого типа статистики ### 🔧 Technical Implementation - **Resolvers**: Обновлён `load_authors_by` для включения всех счётчиков - **Database**: Оптимизированные SQL-запросы с JOIN для статистики - **Caching**: Интеграция с ViewedStorage для подсчёта просмотров - **GraphQL Schema**: Обновлён тип AuthorStat с новыми полями
This commit is contained in:
291
docs/author-statistics.md
Normal file
291
docs/author-statistics.md
Normal file
@@ -0,0 +1,291 @@
|
||||
# 📊 Система статистики авторов
|
||||
|
||||
Полная документация по расчёту и использованию статистики авторов в 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)
|
||||
- Большие объёмы данных могут замедлять запросы без кеша
|
||||
- Сложные запросы сортировки требуют больше ресурсов
|
||||
Reference in New Issue
Block a user