antimoda1 commited on
Commit ·
4dd2f1d
1
Parent(s): 47eee0e
refactor
Browse files- _2_splitting.py +72 -0
- retrieval.py +9 -195
- texts/реформа Мозера.md +1 -1
- texts/реформа2012.md +1 -1
_2_splitting.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Конфиги для парсинга дат
|
| 2 |
YEARS = {
|
| 3 |
'O': 1918,
|
|
@@ -121,3 +125,71 @@ def years_overlap(range1: tuple[int, int], range2: tuple[int, int]) -> bool:
|
|
| 121 |
start1, end1 = range1
|
| 122 |
start2, end2 = range2
|
| 123 |
return start1 <= end2 and end1 >= start2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import re
|
| 3 |
+
|
| 4 |
+
|
| 5 |
# Конфиги для парсинга дат
|
| 6 |
YEARS = {
|
| 7 |
'O': 1918,
|
|
|
|
| 125 |
start1, end1 = range1
|
| 126 |
start2, end2 = range2
|
| 127 |
return start1 <= end2 and end1 >= start2
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def process_documents(documents) -> tuple[pd.DataFrame, pd.DataFrame]:
|
| 131 |
+
"""
|
| 132 |
+
Обрабатывает документы с парсингом дат и создает два датафрейма.
|
| 133 |
+
|
| 134 |
+
Returns:
|
| 135 |
+
tuple: (paragraphs_df, chunks_df)
|
| 136 |
+
|
| 137 |
+
paragraphs_df:
|
| 138 |
+
- paragraph_id: уникальный идентификатор абзаца
|
| 139 |
+
- summary: название документа/раздела
|
| 140 |
+
- start_year: год начала периода
|
| 141 |
+
- end_year: год окончания периода
|
| 142 |
+
- text: текст абзаца
|
| 143 |
+
- document_id: ссылка на исходный документ
|
| 144 |
+
|
| 145 |
+
chunks_df:
|
| 146 |
+
- chunk_id: уникальный идентификатор чанка
|
| 147 |
+
- paragraph_id: ссылка на абзац (foreign key)
|
| 148 |
+
- text: текст чанка
|
| 149 |
+
- lemmatized_text: лемматизированный текст (добавляется позже)
|
| 150 |
+
"""
|
| 151 |
+
paragraphs_data = []
|
| 152 |
+
chunks_data = []
|
| 153 |
+
|
| 154 |
+
paragraph_id_counter = 0
|
| 155 |
+
chunk_id_counter = 0
|
| 156 |
+
|
| 157 |
+
for doc_id, document in enumerate(documents):
|
| 158 |
+
dated_chunks = parse_metadata_from_document(document)
|
| 159 |
+
|
| 160 |
+
for chunk_text, year_range, summary in dated_chunks:
|
| 161 |
+
paragraphs = chunk_text.split('\n')
|
| 162 |
+
|
| 163 |
+
for paragraph in paragraphs:
|
| 164 |
+
paragraph = paragraph.strip()
|
| 165 |
+
|
| 166 |
+
# Добавляем информацию о параграфе в датафрейм параграфов
|
| 167 |
+
paragraphs_data.append({
|
| 168 |
+
'paragraph_id': paragraph_id_counter,
|
| 169 |
+
'summary': summary,
|
| 170 |
+
'start_year': year_range[0],
|
| 171 |
+
'end_year': year_range[1],
|
| 172 |
+
'text': paragraph,
|
| 173 |
+
'document_id': doc_id
|
| 174 |
+
})
|
| 175 |
+
|
| 176 |
+
# Разбиваем параграф на предложения и создаем чанки
|
| 177 |
+
sentences = re.split(r'(?<=[.!?])\s+', paragraph)
|
| 178 |
+
for sent in sentences:
|
| 179 |
+
chunks_data.append({
|
| 180 |
+
'chunk_id': chunk_id_counter,
|
| 181 |
+
'paragraph_id': paragraph_id_counter,
|
| 182 |
+
'text': sent.strip()
|
| 183 |
+
})
|
| 184 |
+
chunk_id_counter += 1
|
| 185 |
+
|
| 186 |
+
paragraph_id_counter += 1
|
| 187 |
+
|
| 188 |
+
# Создаем датафреймы
|
| 189 |
+
paragraphs_df = pd.DataFrame(paragraphs_data)
|
| 190 |
+
chunks_df = pd.DataFrame(chunks_data)
|
| 191 |
+
|
| 192 |
+
print(f"Создано {len(chunks_df)} чанков")
|
| 193 |
+
print(f"Из {len(paragraphs_df)} абзацев в {len(set(paragraphs_df['document_id']))} документах")
|
| 194 |
+
|
| 195 |
+
return paragraphs_df, chunks_df
|
retrieval.py
CHANGED
|
@@ -1,18 +1,16 @@
|
|
| 1 |
-
import re
|
| 2 |
import hashlib
|
| 3 |
import pickle
|
| 4 |
from pathlib import Path
|
| 5 |
|
| 6 |
import numpy as np
|
| 7 |
import torch
|
| 8 |
-
import pandas as pd
|
| 9 |
from rank_bm25 import BM25Okapi
|
| 10 |
from sentence_transformers import SentenceTransformer
|
| 11 |
import warnings
|
| 12 |
warnings.filterwarnings('ignore')
|
| 13 |
|
| 14 |
from _1_get_documents import load_and_process_data
|
| 15 |
-
from _2_splitting import
|
| 16 |
from lemmatizer import RussianLemmatizer
|
| 17 |
|
| 18 |
|
|
@@ -77,101 +75,22 @@ class Retrieval:
|
|
| 77 |
print(f" Загружено {len(self.documents)} сообщений")
|
| 78 |
|
| 79 |
# Парсим даты из документов и создаем датафреймы
|
| 80 |
-
self.paragraphs_df, self.chunks_df = self.
|
| 81 |
|
| 82 |
# Добавляем лемматизированный текст в датафрейм чанков с кэшем
|
| 83 |
print("2. Лемматизация текстов (с кэшированием)...")
|
| 84 |
-
self.chunks_df['lemmatized_text'] = self._lemmatize_with_cache(self.chunks_df['text']
|
| 85 |
|
| 86 |
# Инициализируем CrossEncoder
|
| 87 |
# self.cross_encoder = CrossEncoder('DiTy/cross-encoder-russian-msmarco')
|
| 88 |
self.embedder = SentenceTransformer('cointegrated/rubert-tiny2')
|
| 89 |
-
self.embeddings_of_summary = self.embedder.encode(self.paragraphs_df['summary']
|
| 90 |
|
| 91 |
print("✅ RAG система готова к использованию")
|
| 92 |
|
| 93 |
-
def _process_documents_with_dates(self):
|
| 94 |
-
"""
|
| 95 |
-
Обрабатывает документы с парсингом дат и создает два датафрейма.
|
| 96 |
-
|
| 97 |
-
Returns:
|
| 98 |
-
tuple: (paragraphs_df, chunks_df)
|
| 99 |
-
|
| 100 |
-
paragraphs_df:
|
| 101 |
-
- paragraph_id: уникальный идентификатор абзаца
|
| 102 |
-
- summary: название документа/раздела
|
| 103 |
-
- start_year: год начала периода
|
| 104 |
-
- end_year: год окончания периода
|
| 105 |
-
- text: текст абзаца
|
| 106 |
-
- document_id: ссылка на исходный документ
|
| 107 |
-
|
| 108 |
-
chunks_df:
|
| 109 |
-
- chunk_id: уникальный идентификатор чанка
|
| 110 |
-
- paragraph_id: ссылка на абзац (foreign key)
|
| 111 |
-
- text: текст чанка
|
| 112 |
-
- lemmatized_text: лемматизированный текст (добавляется позже)
|
| 113 |
-
"""
|
| 114 |
-
paragraphs_data = []
|
| 115 |
-
chunks_data = []
|
| 116 |
-
|
| 117 |
-
paragraph_id_counter = 0
|
| 118 |
-
chunk_id_counter = 0
|
| 119 |
-
|
| 120 |
-
for doc_id, document in enumerate(self.documents):
|
| 121 |
-
dated_chunks = parse_metadata_from_document(document)
|
| 122 |
-
|
| 123 |
-
for chunk_text, year_range, summary in dated_chunks:
|
| 124 |
-
paragraphs = chunk_text.split('\n')
|
| 125 |
-
|
| 126 |
-
for paragraph in paragraphs:
|
| 127 |
-
paragraph = paragraph.strip()
|
| 128 |
-
|
| 129 |
-
# Добавляем информацию о параграфе в датафрейм параграфов
|
| 130 |
-
paragraphs_data.append({
|
| 131 |
-
'paragraph_id': paragraph_id_counter,
|
| 132 |
-
'summary': summary,
|
| 133 |
-
'start_year': year_range[0],
|
| 134 |
-
'end_year': year_range[1],
|
| 135 |
-
'text': paragraph,
|
| 136 |
-
'document_id': doc_id
|
| 137 |
-
})
|
| 138 |
-
|
| 139 |
-
# Разбиваем параграф на предложения и создаем чанки
|
| 140 |
-
sentences = re.split(r'(?<=[.!?])\s+', paragraph)
|
| 141 |
-
for sent in sentences:
|
| 142 |
-
chunks_data.append({
|
| 143 |
-
'chunk_id': chunk_id_counter,
|
| 144 |
-
'paragraph_id': paragraph_id_counter,
|
| 145 |
-
'text': sent.strip()
|
| 146 |
-
})
|
| 147 |
-
chunk_id_counter += 1
|
| 148 |
-
|
| 149 |
-
paragraph_id_counter += 1
|
| 150 |
-
|
| 151 |
-
# Создаем датафреймы
|
| 152 |
-
paragraphs_df = pd.DataFrame(paragraphs_data)
|
| 153 |
-
chunks_df = pd.DataFrame(chunks_data)
|
| 154 |
-
|
| 155 |
-
print(f"Создано {len(chunks_df)} чанков")
|
| 156 |
-
print(f"Из {len(paragraphs_df)} абзацев в {len(set(paragraphs_df['document_id']))} документах")
|
| 157 |
-
|
| 158 |
-
return paragraphs_df, chunks_df
|
| 159 |
|
| 160 |
# ============ Методы кэширования лемматизации ============
|
| 161 |
-
|
| 162 |
-
@staticmethod
|
| 163 |
-
def _compute_text_hash(text: str) -> str:
|
| 164 |
-
"""
|
| 165 |
-
Вычисляет SHA256 хэш текста.
|
| 166 |
-
|
| 167 |
-
Args:
|
| 168 |
-
text: Текст для хэширования
|
| 169 |
-
|
| 170 |
-
Returns:
|
| 171 |
-
str: Хэш в hex формате
|
| 172 |
-
"""
|
| 173 |
-
return hashlib.sha256(text.encode('utf-8')).hexdigest()
|
| 174 |
-
|
| 175 |
def _load_cache(self) -> dict:
|
| 176 |
"""
|
| 177 |
Загружает кэш лемматизации из файловой системы.
|
|
@@ -192,22 +111,6 @@ class Retrieval:
|
|
| 192 |
return {}
|
| 193 |
return {}
|
| 194 |
|
| 195 |
-
def _save_cache(self, cache: dict) -> None:
|
| 196 |
-
"""
|
| 197 |
-
Сохраняет кэш лемматизации в файловую систему.
|
| 198 |
-
|
| 199 |
-
Args:
|
| 200 |
-
cache: {text_hash -> lemmatized_tokens}
|
| 201 |
-
"""
|
| 202 |
-
cache_file = self.cache_dir / 'lemmatization_cache.pkl'
|
| 203 |
-
|
| 204 |
-
try:
|
| 205 |
-
with open(cache_file, 'wb') as f:
|
| 206 |
-
pickle.dump(cache, f)
|
| 207 |
-
print(f" ✓ Кэш сохранён ({len(cache)} записей)")
|
| 208 |
-
except Exception as e:
|
| 209 |
-
print(f" ⚠ Ошибка при сохранении кэша: {e}")
|
| 210 |
-
|
| 211 |
def _lemmatize_with_cache(self, texts: list[str]) -> list:
|
| 212 |
"""
|
| 213 |
Лемматизирует тексты с использованием кэша.
|
|
@@ -231,7 +134,7 @@ class Retrieval:
|
|
| 231 |
needs_save = False
|
| 232 |
|
| 233 |
for text in texts:
|
| 234 |
-
text_hash =
|
| 235 |
text_hashes[text] = text_hash
|
| 236 |
|
| 237 |
if text_hash in cache:
|
|
@@ -246,101 +149,12 @@ class Retrieval:
|
|
| 246 |
|
| 247 |
# Сохраняем кэш если были новые записи
|
| 248 |
if needs_save:
|
| 249 |
-
|
|
|
|
|
|
|
| 250 |
|
| 251 |
return results
|
| 252 |
|
| 253 |
-
def clear_cache(self) -> None:
|
| 254 |
-
"""
|
| 255 |
-
Очищает кэш лемматизации.
|
| 256 |
-
"""
|
| 257 |
-
cache_file = self.cache_dir / 'lemmatization_cache.pkl'
|
| 258 |
-
|
| 259 |
-
try:
|
| 260 |
-
if cache_file.exists():
|
| 261 |
-
cache_file.unlink()
|
| 262 |
-
print("✓ Кэш очищен")
|
| 263 |
-
else:
|
| 264 |
-
print("⚠ Файл кэша не найден")
|
| 265 |
-
except Exception as e:
|
| 266 |
-
print(f"⚠ Ошибка при очистке кэша: {e}")
|
| 267 |
-
|
| 268 |
-
def get_cache_stats(self) -> dict:
|
| 269 |
-
"""
|
| 270 |
-
Возвращает статистику кэша.
|
| 271 |
-
|
| 272 |
-
Returns:
|
| 273 |
-
dict: Информация о кэше
|
| 274 |
-
"""
|
| 275 |
-
cache_file = self.cache_dir / 'lemmatization_cache.pkl'
|
| 276 |
-
|
| 277 |
-
if cache_file.exists():
|
| 278 |
-
cache = self._load_cache() if self.use_cache else {}
|
| 279 |
-
file_size_mb = cache_file.stat().st_size / (1024 * 1024)
|
| 280 |
-
|
| 281 |
-
return {
|
| 282 |
-
'cache_enabled': self.use_cache,
|
| 283 |
-
'cache_file': str(cache_file),
|
| 284 |
-
'cached_entries': len(cache),
|
| 285 |
-
'file_size_mb': round(file_size_mb, 2),
|
| 286 |
-
'exists': True
|
| 287 |
-
}
|
| 288 |
-
else:
|
| 289 |
-
return {
|
| 290 |
-
'cache_enabled': self.use_cache,
|
| 291 |
-
'cache_file': str(cache_file),
|
| 292 |
-
'cached_entries': 0,
|
| 293 |
-
'file_size_mb': 0,
|
| 294 |
-
'exists': False
|
| 295 |
-
}
|
| 296 |
-
|
| 297 |
-
# ============ Вспомогательные методы для работы с датафреймами ============
|
| 298 |
-
|
| 299 |
-
def get_merged_data(self):
|
| 300 |
-
"""Возвращает объединённый датафрейм чанков с метаданными параграфов.
|
| 301 |
-
|
| 302 |
-
Returns:
|
| 303 |
-
pd.DataFrame: Датафрейм с полями:
|
| 304 |
-
chunk_id, paragraph_id, text, lemmatized_text,
|
| 305 |
-
summary, start_year, end_year, document_id
|
| 306 |
-
"""
|
| 307 |
-
return self.chunks_df.merge(
|
| 308 |
-
self.paragraphs_df,
|
| 309 |
-
on='paragraph_id',
|
| 310 |
-
how='left'
|
| 311 |
-
)
|
| 312 |
-
|
| 313 |
-
def filter_by_year_range(self, year_range: tuple[int, int]) -> pd.DataFrame:
|
| 314 |
-
"""Возвращает чанки, которые пересекаются с заданным диапазоном лет.
|
| 315 |
-
|
| 316 |
-
Args:
|
| 317 |
-
year_range: (start_year, end_year)
|
| 318 |
-
|
| 319 |
-
Returns:
|
| 320 |
-
pd.DataFrame: Отфильтрованные чанки с метаданными
|
| 321 |
-
"""
|
| 322 |
-
merged = self.get_merged_data()
|
| 323 |
-
|
| 324 |
-
# Проверяем пересечение диапазонов
|
| 325 |
-
return merged[
|
| 326 |
-
(merged['start_year'] <= year_range[1]) &
|
| 327 |
-
(merged['end_year'] >= year_range[0])
|
| 328 |
-
]
|
| 329 |
-
|
| 330 |
-
# def rerank_search(self, query: str) -> list[dict]:
|
| 331 |
-
# """Ранжирует все чанки используя CrossEncoder модель.
|
| 332 |
-
|
| 333 |
-
# Args:
|
| 334 |
-
# query: Текст запроса
|
| 335 |
-
|
| 336 |
-
# Returns:
|
| 337 |
-
# list: Отсортированный список результатов с scores
|
| 338 |
-
# """
|
| 339 |
-
# pairs = [[query, text] for text in self.paragraphs_df['summary'].tolist()]
|
| 340 |
-
# scores = self.cross_encoder.predict(pairs)
|
| 341 |
-
# sorted_scores = dict(sorted(scores.items(), key=lambda item: item[0]))
|
| 342 |
-
|
| 343 |
-
|
| 344 |
def semantic_search(self, query: str) -> torch.Tensor:
|
| 345 |
# 1. Семантический поиск
|
| 346 |
query_embedding = torch.tensor(self.embedder.encode_query(query))
|
|
|
|
|
|
|
| 1 |
import hashlib
|
| 2 |
import pickle
|
| 3 |
from pathlib import Path
|
| 4 |
|
| 5 |
import numpy as np
|
| 6 |
import torch
|
|
|
|
| 7 |
from rank_bm25 import BM25Okapi
|
| 8 |
from sentence_transformers import SentenceTransformer
|
| 9 |
import warnings
|
| 10 |
warnings.filterwarnings('ignore')
|
| 11 |
|
| 12 |
from _1_get_documents import load_and_process_data
|
| 13 |
+
from _2_splitting import process_documents
|
| 14 |
from lemmatizer import RussianLemmatizer
|
| 15 |
|
| 16 |
|
|
|
|
| 75 |
print(f" Загружено {len(self.documents)} сообщений")
|
| 76 |
|
| 77 |
# Парсим даты из документов и создаем датафреймы
|
| 78 |
+
self.paragraphs_df, self.chunks_df = process_documents(self.documents)
|
| 79 |
|
| 80 |
# Добавляем лемматизированный текст в датафрейм чанков с кэшем
|
| 81 |
print("2. Лемматизация текстов (с кэшированием)...")
|
| 82 |
+
self.chunks_df['lemmatized_text'] = self._lemmatize_with_cache(self.chunks_df['text'])
|
| 83 |
|
| 84 |
# Инициализируем CrossEncoder
|
| 85 |
# self.cross_encoder = CrossEncoder('DiTy/cross-encoder-russian-msmarco')
|
| 86 |
self.embedder = SentenceTransformer('cointegrated/rubert-tiny2')
|
| 87 |
+
self.embeddings_of_summary = self.embedder.encode(self.paragraphs_df['summary'], convert_to_tensor=True)
|
| 88 |
|
| 89 |
print("✅ RAG система готова к использованию")
|
| 90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
# ============ Методы кэширования лемматизации ============
|
| 93 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
def _load_cache(self) -> dict:
|
| 95 |
"""
|
| 96 |
Загружает кэш лемматизации из файловой системы.
|
|
|
|
| 111 |
return {}
|
| 112 |
return {}
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
def _lemmatize_with_cache(self, texts: list[str]) -> list:
|
| 115 |
"""
|
| 116 |
Лемматизирует тексты с использованием кэша.
|
|
|
|
| 134 |
needs_save = False
|
| 135 |
|
| 136 |
for text in texts:
|
| 137 |
+
text_hash = hashlib.sha256(text.encode('utf-8')).hexdigest()
|
| 138 |
text_hashes[text] = text_hash
|
| 139 |
|
| 140 |
if text_hash in cache:
|
|
|
|
| 149 |
|
| 150 |
# Сохраняем кэш если были новые записи
|
| 151 |
if needs_save:
|
| 152 |
+
with open(cache, 'wb') as f:
|
| 153 |
+
pickle.dump(cache, f)
|
| 154 |
+
print(f" ✓ Кэш сохранён ({len(cache)} записей)")
|
| 155 |
|
| 156 |
return results
|
| 157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
def semantic_search(self, query: str) -> torch.Tensor:
|
| 159 |
# 1. Семантический поиск
|
| 160 |
query_embedding = torch.tensor(self.embedder.encode_query(query))
|
texts/реформа Мозера.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
| 9 |
|
| 10 |
С автоколонной 1310 ситуация была ещё более комичной. То есть с конца девяностых и до 2002 года они постоянно получали большими партиями автобусы из Германии практически на халяву. То есть у них был транспорт, он был достаточно вместительным, под него была хорошая ремонтная база. Они даже на маршруточный бум отреагировали, запустив несколько коммерческих рейсов, которые от обычных льготных отличались тем, что в них просто не было льгот. Но через несколько лет им эту деятельность запретили. И при всём при этом именно автоколонна 1310 громче, чем УРТ, кричала о том, что вот-вот окажется на грани банкротства. А работники автоколонны чуть не устроили забастовку из-за того, что им не выплачивают зарплату и вообще из-за состояния предприятия. Короче, проблем была масса, их нужно было решать.
|
| 11 |
|
| 12 |
-
Вот таким образом начала думать команда специалистов во главе с советником губернатора Сергеем Мозером. Собственно, в честь него в узких кругах данную реформу называют реформой Мозера, потому что он её был проводником, он про неё постоянно рассказывал. Задумка состояла в следующем. Создавалось ОАО «Рязанский транспортный комплекс», которое по большей части управлялось областью, при этом являясь открытым акционерным обществом, напомню. Постепенно оно должно было взять на себя весь общественный транспорт Рязани. По другим данным — весь общественный транспорт области. Вначале вобрав в себя муниципальные предприятия, а затем
|
| 13 |
|
| 14 |
Под это дело в 2005 году предполагалось закупить 510 единиц общественного транспорта. По другим данным — 400. Из них 200 автобусов и 200 троллейбусов. То есть это примерно то количество, которым располагали городские транспортные предприятия для обслуживания маршрутов общественного транспорта в начале девяностых. Естественно, у вас возник вопрос: предполагалось вин-вин стратегия? Потому что ЛиАЗ на тот момент простаивал без работы, а тут приходит большой заказ, ЛиАЗ начинает работать. Город получает новый транспорт. Ну а эти все автобусы и троллейбусы планировалось взять в лизинг.
|
| 15 |
|
|
|
|
| 9 |
|
| 10 |
С автоколонной 1310 ситуация была ещё более комичной. То есть с конца девяностых и до 2002 года они постоянно получали большими партиями автобусы из Германии практически на халяву. То есть у них был транспорт, он был достаточно вместительным, под него была хорошая ремонтная база. Они даже на маршруточный бум отреагировали, запустив несколько коммерческих рейсов, которые от обычных льготных отличались тем, что в них просто не было льгот. Но через несколько лет им эту деятельность запретили. И при всём при этом именно автоколонна 1310 громче, чем УРТ, кричала о том, что вот-вот окажется на грани банкротства. А работники автоколонны чуть не устроили забастовку из-за того, что им не выплачивают зарплату и вообще из-за состояния предприятия. Короче, проблем была масса, их нужно было решать.
|
| 11 |
|
| 12 |
+
Вот таким образом начала думать команда специалистов во главе с советником губернатора Сергеем Мозером. Собственно, в честь него в узких кругах данную реформу называют реформой Мозера, потому что он её был проводником, он про неё постоянно рассказывал. Задумка состояла в следующем. Создавалось ОАО «Рязанский транспортный комплекс», которое по большей части управлялось областью, при этом являясь открытым акционерным обществом, напомню. Постепенно оно должно было взять на себя весь общественный транспорт Рязани. По другим данным — весь общественный транспорт области. Вначале вобрав в себя муниципальные предприятия, а затем в течение года весь коммерческий транспорт в Рязани. Очень амбициозно, да?
|
| 13 |
|
| 14 |
Под это дело в 2005 году предполагалось закупить 510 единиц общественного транспорта. По другим данным — 400. Из них 200 автобусов и 200 троллейбусов. То есть это примерно то количество, которым располагали городские транспортные предприятия для обслуживания маршрутов общественного транспорта в начале девяностых. Естественно, у вас возник вопрос: предполагалось вин-вин стратегия? Потому что ЛиАЗ на тот момент простаивал без работы, а тут приходит большой заказ, ЛиАЗ начинает работать. Город получает новый транспорт. Ну а эти все автобусы и троллейбусы планировалось взять в лизинг.
|
| 15 |
|
texts/реформа2012.md
CHANGED
|
@@ -67,7 +67,7 @@
|
|
| 67 |
|
| 68 |
Ну и также, помимо отмен изменений, в реформе 2011 года планировались и новые маршруты. Один маршрут предполагалось отдать автоколонне 1310, а три остальных планировались отдать коммерческим переводчикам. Теперь же мы их также рассмотрим. Начну с автобусного номер 25. Должен был пройти от октябрьского городка по улице Чкалова, Московскому шоссе через Приокский и Канищево в Недостоево. Довольно странный маршрут, но в целом и сам по себе интересный. Единственное, что мне непонятно, как он должен был пройти из Приокского в Канищево: по улице Молодцова, по улице Станкозаводской или же вообще через троллейбусное депо номер 2. Так что тут тоже непонятно. Что ж до маршрутов, кто тут все три варианта довольно интересны. Начну с маршрута от поселка Божатково до площади Победы. Во-первых, где развернутся на площади Победы, а во-вторых, это же, по сути, сокращенный 13 автобус. Да, я понимаю, что Михайловского шоссе до площади Победы максимальный пассажиропоток, а потому там в идеале нужна какая-то дублирующая, скажем так, вспомогательная даже маршрутка. Но, зная рязанские реалии, мне что-то подсказывает, что эта маршрутка ехала бы, не помогая автобусу, а перед ним, собирая всех пассажиров. Следующий маршрут вообще имеет какую-то странную схему, потому что тут он едет сначала по северной окружной, потом возвращается на улицу Каширина и Солнечную, потом опять едет на северную окружную дорогу в поселок Борки. Какой у него точный маршрут? Непонятно. Возможно, это не так хотели показать, что в одну сторону поедет по Солнечной, а в другую по Каширина, но лично мне это показалось непонятно. И третий маршрут с поселка Ворошиловки до завода ТКПО. Этот маршрут все-таки через некоторое время попытались ввести под номером 46, но проходил ли он в таком виде, непонятно. Скорее всего, он так ни разу и не вышел на линию. Так что в плане новых маршрутов было сделано целое ничего, поскольку реформу официально все-таки отменили.
|
| 69 |
|
| 70 |
-
Я думаю, вы заметили, что практически ничего я до этого не говорил про троллейбус. И в том, что показали людям в конце 2011 года, действительно так же не было упоминаний про троллейбус. Но фактически в реформе его упоминания было. А именно как раз-таки была открыта новая троллейбусная линия по проезду Шабулина, улицам Бирюзовой и Интернациональной, по которой пустили два новых маршрута: четвертый из Московского ва
|
| 71 |
|
| 72 |
### 2011-N
|
| 73 |
А сейчас мне хотелось ответить на вопрос. Вот как думаете, нужно ли было проводить транспортную реформу 2011 года? И мой ответ – да! То есть, по сути, давайте признаем это. По большей части она была проведена, хотя ее отменили. И проведена она была по инициативе перевозчиков. То есть те маршруты, которые планировали закрыть, в основном были закрыты. Но те маршруты, которая предполагалась открыть из-за того, что реформа была отменена, их не открыли. И, скорее всего, тут два варианта. Либо разработчикам реформа просто повезло и они сумели предсказать будущее, либо же они действительно проводили какие-то расчеты, измеряли действительно пассажиропоток, измеряли его адекватно. И таким образом им удалось узнать какие-то тренды, которые тогда были в Рязанском транспорте. То есть, значит, были предпосылки к тому, что большинство маршрутов на ПАЗиках закроется. Хотя в 2011 году большинство рязанцев не могли этого предположить. ПАЗики ходили довольно хорошо и часто, и их состояние было вполне себе неплохим. Но уже буквально через считанные годы все это посыпалось. И да, получается так, что большинство людей, которые не имеют доступа к реальным цифрам, не имеют какого-то такого специализированного образования, не могут предсказать то, что произойдет через несколько лет. Да, в принципе, рязанский транспорт, о это штука непредсказуемая. Тут нельзя загадывать, что будет через два года, через три, через пять. Скажи человеку из 2011 года, что 10 лет спустя 17 автобус будет овслуживаться мелочью в виде пазиков и мазов, и они смогут выбить с этого направления 98 маршрутку почти подчистую. Я думаю, что человек из 2011 в это не поверит, но это произошло.
|
|
|
|
| 67 |
|
| 68 |
Ну и также, помимо отмен изменений, в реформе 2011 года планировались и новые маршруты. Один маршрут предполагалось отдать автоколонне 1310, а три остальных планировались отдать коммерческим переводчикам. Теперь же мы их также рассмотрим. Начну с автобусного номер 25. Должен был пройти от октябрьского городка по улице Чкалова, Московскому шоссе через Приокский и Канищево в Недостоево. Довольно странный маршрут, но в целом и сам по себе интересный. Единственное, что мне непонятно, как он должен был пройти из Приокского в Канищево: по улице Молодцова, по улице Станкозаводской или же вообще через троллейбусное депо номер 2. Так что тут тоже непонятно. Что ж до маршрутов, кто тут все три варианта довольно интересны. Начну с маршрута от поселка Божатково до площади Победы. Во-первых, где развернутся на площади Победы, а во-вторых, это же, по сути, сокращенный 13 автобус. Да, я понимаю, что Михайловского шоссе до площади Победы максимальный пассажиропоток, а потому там в идеале нужна какая-то дублирующая, скажем так, вспомогательная даже маршрутка. Но, зная рязанские реалии, мне что-то подсказывает, что эта маршрутка ехала бы, не помогая автобусу, а перед ним, собирая всех пассажиров. Следующий маршрут вообще имеет какую-то странную схему, потому что тут он едет сначала по северной окружной, потом возвращается на улицу Каширина и Солнечную, потом опять едет на северную окружную дорогу в поселок Борки. Какой у него точный маршрут? Непонятно. Возможно, это не так хотели показать, что в одну сторону поедет по Солнечной, а в другую по Каширина, но лично мне это показалось непонятно. И третий маршрут с поселка Ворошиловки до завода ТКПО. Этот маршрут все-таки через некоторое время попытались ввести под номером 46, но проходил ли он в таком виде, непонятно. Скорее всего, он так ни разу и не вышел на линию. Так что в плане новых маршрутов было сделано целое ничего, поскольку реформу официально все-таки отменили.
|
| 69 |
|
| 70 |
+
Я думаю, вы заметили, что практически ничего я до этого не говорил про троллейбус. И в том, что показали людям в конце 2011 года, действительно так же не было упоминаний про троллейбус. Но фактически в реформе его упоминания было. А именно как раз-таки была открыта новая троллейбусная линия по проезду Шабулина, улицам Бирюзовой и Интернациональной, по которой пустили два новых маршрута: четвертый из Московского в Канищево и восемнадцатый из Канищево в центр. Если четвертый маршрут был пущен вполне себе логично (вы сейчас скажете, что у него такой пиковый пассажиропоток, и в итоге вне часа пик он часто ездит пустым, но все-таки этот маршрут более-менее востребован). Что же с восемнадцатым троллейбусом, то тут не все так однозначно. Я как человек из будущего считаю, что восемнадцатый троллейбус нужно было пускать не в центр, а в Горрощу до центрального парка или до улицы Строителей. В тех условиях, когда предполагалось обменить 36 автобус и 50 маршрутку, имевшие подобные трассировку, такой троллейбус был бы более разумен. И можно было эту отмену вполне себе протокнуть под предлогом, что маршрутка заменяется на вместительный троллейбус. Но не свершилось. В позднее это выйдет боком еще для восьмого маршрута, который потом начнут резко менять, а ведь начнется все с отмены того самого восемнадцатого маршрута.
|
| 71 |
|
| 72 |
### 2011-N
|
| 73 |
А сейчас мне хотелось ответить на вопрос. Вот как думаете, нужно ли было проводить транспортную реформу 2011 года? И мой ответ – да! То есть, по сути, давайте признаем это. По большей части она была проведена, хотя ее отменили. И проведена она была по инициативе перевозчиков. То есть те маршруты, которые планировали закрыть, в основном были закрыты. Но те маршруты, которая предполагалась открыть из-за того, что реформа была отменена, их не открыли. И, скорее всего, тут два варианта. Либо разработчикам реформа просто повезло и они сумели предсказать будущее, либо же они действительно проводили какие-то расчеты, измеряли действительно пассажиропоток, измеряли его адекватно. И таким образом им удалось узнать какие-то тренды, которые тогда были в Рязанском транспорте. То есть, значит, были предпосылки к тому, что большинство маршрутов на ПАЗиках закроется. Хотя в 2011 году большинство рязанцев не могли этого предположить. ПАЗики ходили довольно хорошо и часто, и их состояние было вполне себе неплохим. Но уже буквально через считанные годы все это посыпалось. И да, получается так, что большинство людей, которые не имеют доступа к реальным цифрам, не имеют какого-то такого специализированного образования, не могут предсказать то, что произойдет через несколько лет. Да, в принципе, рязанский транспорт, о это штука непредсказуемая. Тут нельзя загадывать, что будет через два года, через три, через пять. Скажи человеку из 2011 года, что 10 лет спустя 17 автобус будет овслуживаться мелочью в виде пазиков и мазов, и они смогут выбить с этого направления 98 маршрутку почти подчистую. Я думаю, что человек из 2011 в это не поверит, но это произошло.
|