Skip to content

Commit 949330e

Browse files
committed
Расширено количество таблиц для индивидуального ЛК. без индексов
1 parent 31a1a4e commit 949330e

4 files changed

Lines changed: 142 additions & 10 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ copy .env.example .env
7070

7171
#### запустить код
7272
```bash
73-
python main.py --keyword your_key_word --category your_category --limit your_articles_limit --page_size your_page_size
73+
python main.py --keyword your_key_word --limit your_articles_limit --page_size your_page_size
7474
```
7575

7676
### пример .env

config/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ class Settings:
2929
db_admin_db: str = os.getenv("DB_ADMIN_DB", "postgres")
3030

3131
db_news: str = os.getenv("DB_NEWS","news_db")
32+
db_app_users: str = os.getenv("DB_APP_USERS", "db_app_users")
33+
db_search_requests: str = os.getenv("DB_SEARCH_REQUESTS", "DB_SEARCH_REQUESTS")
34+
db_articles: str = os.getenv("DB_ARTICLES", "db_articles")
35+
db_user_news: str = os.getenv("DB_USER_NEWS", "db_user_news")
36+
db_request_stats: str = os.getenv("DB_REQUEST_STATS", "db_request_stats")
37+
3238

3339
KEY_API: str = os.getenv("NEWSAPI_KEY", "NO")
3440
NEWS_URL = "https://newsapi.org/v2/everything"

notebooks/01_eda.ipynb

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
"outputs": [],
1313
"source": [
1414
"import json\n",
15-
"import os\n",
1615
"from pathlib import Path \n",
1716
"import pandas as pd \n",
18-
"import mathplotlib.pyplot as plt \n"
17+
"import matplotlib.pyplot as plt \n",
18+
"import sqlalchemy\n"
1919
]
2020
},
2121
{
@@ -24,17 +24,57 @@
2424
"metadata": {},
2525
"source": [
2626
"В чем поинт происходящего. Помимо очевидного сбора новостей, мне захотелось собрать некую статистику. \n",
27-
"Как много статей от общего числа не проходят фильтр?\n",
28-
"По каким критериям они не проходят?\n",
29-
"Что является первичной причиной отброса?\n",
30-
"Как часто по каждому ключевому слову попадаются одинаковые ссылки?\n",
27+
"- Как много статей от общего числа не проходят фильтр?\n",
28+
"- По каким критериям они не проходят?\n",
29+
"- Что является первичной причиной отброса?\n",
30+
"- Как часто по выбранному ключевому слову попадаются одинаковые ссылки?\n",
31+
"- Какие ключевые слава имеют меньше всего повторов?\n",
32+
"- Какие ключевые слова имеют меньший разры между Published и Fetched?\n",
33+
"- Размер самого длинного и короткого заголовка и описания \n",
3134
"и главный вопрос, кто такой E_nota?\n",
3235
"\n",
3336
"Что будет происходить у меня далее?\n",
3437
"Я буду считывать статистику из data/clean/stats скорее всего я буду после этого чистить папки data/clean и data/raw чтобы избегать использования лишней памяти. После чего я буду строить графики на тему:\n",
35-
"А что является чаще всего причиной отброса в целом?\n",
36-
"А что явяется чаще всего причиной по каждой теме?\n",
37-
"А какое ключивое слово имеет больше всего одинаковых ссылок?"
38+
"- А что является чаще всего причиной отброса в целом?\n",
39+
"- А что явяется чаще всего причиной по выбранной теме?\n",
40+
"- А какое ключивое слово имеет меньше всего одинаковых ссылок?\n",
41+
"- У каких слов получается меньше разрыв между публикацией и стягиванием ланных?\n",
42+
"- минимальная максимальная длинна заголовка и описания "
43+
]
44+
},
45+
{
46+
"cell_type": "code",
47+
"execution_count": null,
48+
"id": "ff607dfe",
49+
"metadata": {
50+
"vscode": {
51+
"languageId": "plaintext"
52+
}
53+
},
54+
"outputs": [],
55+
"source": [
56+
"stats = {\n",
57+
"}\n",
58+
"BASE_DIR = Path(__file__).resolve().parent.parent\n",
59+
"stats_dir = BASE_DIR / \"data\" / \"clean\" / \"stats\"\n",
60+
"\n",
61+
"total_data = []\n",
62+
"\n",
63+
"for file in stats_dir.glob(\"stats_*.json\"):\n",
64+
" keyword = file.stem.split('_')[1]\n",
65+
" with open(file, \"r\", encoding='utf-8') as f:\n",
66+
" data.json.load(f)\n",
67+
" data_frame = pd.DataFrame(data)\n",
68+
" data_frame['key_word'] = keyword\n",
69+
" total_data.append(data_frame)"
70+
]
71+
},
72+
{
73+
"cell_type": "markdown",
74+
"id": "2e5e1a9d",
75+
"metadata": {},
76+
"source": [
77+
"Собственно выше мы стягиваем и обновляем данные. теперь будем их \n"
3878
]
3979
}
4080
],

src/db.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,92 @@ def create_database_if_not_exists(db_name: str) -> None:
7070
def init_database() -> None:
7171
create_database_if_not_exists(settings.db_news)
7272

73+
def create_search_requests_table() -> None:
74+
query = """
75+
CEATE TABLE IF NOT EXISTS search_requests (
76+
id BIGSERIAL PRIMARY KEY,
77+
user_id BIGINT NOT NULL REFERENCES app_users(id) ON DELETE CASCADE,
78+
keyword TEXT NOT NULL,
79+
language VARCHAR(10) NOT NULL DEFAULT 'ru',
80+
limit_count INTEGER NOT NULL CHECK (limit_count > 0),
81+
page_size INTEGER NOT NULL CHECK (page_size > 0),
82+
status VARCHAR(20) NOT NULL, CHECK (status IN ('queued', 'running', 'success', 'failed')),
83+
error_text TEXT,
84+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
85+
stated_at TIMESTAMP,
86+
finished_at TIMESTAMP
87+
);
88+
"""
89+
with get_cursor(settings.db_search_requests) as (conn, cur):
90+
cur.execute(query)
91+
conn.commit()
92+
93+
def create_articles_table() -> None:
94+
query = """
95+
CEATE TABLE IF NOT EXISTS articles (
96+
id BIGSERIAL PRIMARY KEY,
97+
url TEXT NOT NULL UNIQUE,
98+
source_name TEXT,
99+
author TEXT,
100+
title TEXT NOT NULL,
101+
description TEXT,
102+
published_at TIMESTAMP NOT NULL,
103+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
104+
);
105+
"""
106+
with get_cursor(settings.db_articles) as (conn, cur):
107+
cur.execute(query)
108+
conn.commit()
109+
110+
def create_user_news_table() -> None:
111+
query = """
112+
CEATE TABLE IF NOT EXISTS user_news (
113+
id BIGSERIAL PRIMARY KEY,
114+
user_id BIGINT NOT NULL REFERENCES app_users(id) ON DELETE CASCADE,
115+
search_request_id BIGINT NOT NULL REFERENCES search_requests(id) ON DELETE CASCADE,
116+
article_id BIGINT NOT NULL REFERENCES articles(id) ON DELETE CASCADE,
117+
keyword TEXT NOT NULL,
118+
fetched_at TIMESTAMP NOT NULL DEFAULT NOW(),
119+
UNIQUE (user_id, article_id, search_request_id)
120+
);
121+
"""
122+
with get_cursor(settings.db_user_news) as (conn, cur):
123+
cur.execute(query)
124+
conn.commit()
125+
126+
def create_request_stats_table() -> None:
127+
query = """
128+
CEATE TABLE IF NOT EXISTS request_stats (
129+
id BIGSERIAL PRIMARY KEY,
130+
search_request_id BIGINT NOT NULL REFERENCES search_requests(id) ON DELETE CASCADE,
131+
income_articles INTEGER NOT NULL DEFAULT 0,
132+
accepted_articles INTEGER NOT NULL DEFAULT 0,
133+
rejected_articles INTEGER NOT NULL DEFAULT 0,
134+
reasons_counts JSONB NOUT NULL DEFAULT '{}'::jsonb,
135+
prime_reasons JSONB NOUT NULL DEFAULT '{}'::jsonb,
136+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
137+
);
138+
"""
139+
with get_cursor(settings.db_request_stats) as (conn, cur):
140+
cur.execute(query)
141+
conn.commit()
142+
143+
def create_app_users_table() -> None:
144+
query = """
145+
CEATE TABLE IF NOT EXISTS app_users (
146+
id BIGSERIAL PRIMARY KEY,
147+
google_sub TEXT NOT NULL UNIQOE,
148+
email TEXT NOT NULL UNIQUE,
149+
name TEXT,
150+
image_url TEXT,
151+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
152+
last_login_at TIMESTAMP NOT NULL DEFAULT NOW()
153+
);
154+
"""
155+
with get_cursor(settings.db_app_users) as (conn, cur):
156+
cur.execute(query)
157+
conn.commit()
158+
73159
def create_news_tables() -> None:
74160
query = """
75161
CREATE TABLE IF NOT EXISTS bad_news_bears (

0 commit comments

Comments
 (0)