antimoda1 commited on
Commit
2aaeb1b
·
1 Parent(s): 8199364

remove copy-paste

Browse files
lemmatizer.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Общий модуль для лемматизации на русском языке с поддержкой пользовательских терминов.
4
+ Используется в retrieval.py и test_lemmatization.py
5
+ """
6
+ from pathlib import Path
7
+ import spacy
8
+ from vocabulary.parse_vocabulary import parse_vocabulary
9
+
10
+
11
+ class RussianLemmatizer:
12
+ """
13
+ Русский лемматизатор на основе spaCy с поддержкой топонимов.
14
+ Содержит общую логику для всех компонентов системы.
15
+ """
16
+
17
+ def __init__(self, load_toponyms: bool = True):
18
+ """
19
+ Инициализация лемматизатора.
20
+
21
+ Args:
22
+ load_toponyms: загружать ли топонимы из файла при инициализации
23
+ """
24
+ print(" Загрузка русской модели spaCy...")
25
+ try:
26
+ self.nlp = spacy.load("ru_core_news_sm")
27
+ except OSError:
28
+ print(" ⚠️ Модель ru_core_news_sm не найдена, скачиваю...")
29
+ import subprocess
30
+ subprocess.check_call(["python", "-m", "spacy", "download", "ru_core_news_sm"])
31
+ self.nlp = spacy.load("ru_core_news_sm")
32
+
33
+ self.toponims = {}
34
+
35
+ if load_toponyms:
36
+ self._register_terms()
37
+
38
+ def _register_terms(self):
39
+ """
40
+ Загружает термины из vocabulary/vocabulary.md и регистрирует их в spaCy
41
+ как custom component для исправления лемм.
42
+ """
43
+ # Находим файл vocabulary относительно этого модуля
44
+ vocab_file = Path(__file__).parent / "vocabulary" / "vocabulary.md"
45
+
46
+ if not vocab_file.exists():
47
+ print(f" ⚠️ Файл {vocab_file} не найден, управление терминами пропущено")
48
+ return
49
+
50
+ # Парсим словарь термин -> описание
51
+ vocab_dict = parse_vocabulary(str(vocab_file))
52
+
53
+ # Создаём словарь для быстрого поиска (приводим к нижнему регистру)
54
+ self.toponims = {term.lower(): term.lower() for term in vocab_dict.keys()}
55
+
56
+ print(f" Загружено {len(self.toponims)} терминов из vocabulary.md")
57
+
58
+ # Добавляем custom component для обработки терминов после лемматизации
59
+ @self.nlp.component("fix_terms")
60
+ def fix_terms(doc):
61
+ """Компонент для исправления лемм терминов и их форм"""
62
+ for token in doc:
63
+ lemma_lower = token.lemma_.lower()
64
+
65
+ # Проверяем прямое совпадение
66
+ if lemma_lower in self.toponims:
67
+ token.lemma_ = self.toponims[lemma_lower]
68
+ return doc
69
+
70
+ # Добавляем компонент после лемматизатора
71
+ if "fix_terms" not in self.nlp.pipe_names:
72
+ self.nlp.add_pipe("fix_terms", after="lemmatizer")
73
+
74
+ def tokenize_text(self, text: str) -> list[str]:
75
+ """
76
+ Лемматизация текста для русского языка (spaCy).
77
+
78
+ Args:
79
+ text: текст для лемматизации
80
+
81
+ Returns:
82
+ list: список лемм, исключая пунктуацию
83
+ """
84
+ doc = self.nlp(text.lower())
85
+
86
+ # Извлекаем леммы, пропускаем пунктуацию
87
+ lemmas = []
88
+ for token in doc:
89
+ if not token.is_punct and token.lemma_.strip(): # Пропускаем пунктуацию и пробелы
90
+ lemmas.append(token.lemma_)
91
+
92
+ return lemmas
retrieval.py CHANGED
@@ -6,10 +6,9 @@ from rank_bm25 import BM25Okapi
6
  import warnings
7
  warnings.filterwarnings('ignore')
8
 
9
- import spacy
10
-
11
  from _1_get_documents import load_and_process_data
12
- from _2_splitting import Splitter, parse_year_metadata, years_overlap, YEAR_OLD, YEAR_NEW
 
13
  # from _3_chunking import RussianEmbedder
14
 
15
  from sentence_transformers import CrossEncoder
@@ -23,18 +22,9 @@ class Retrieval:
23
  print("Инициализация RAG системы...")
24
  self.device = "cuda" if use_gpu and torch.cuda.is_available() else "cpu"
25
 
26
- # Инициализация лемматизатора для русского языка (spaCy)
27
- print(" Загрузка русской модели spaCy...")
28
- try:
29
- self.nlp = spacy.load("ru_core_news_sm")
30
- except OSError:
31
- print(" ⚠️ Модель ru_core_news_sm не найдена, скачиваю...")
32
- import subprocess
33
- subprocess.check_call(["python", "-m", "spacy", "download", "ru_core_news_sm"])
34
- self.nlp = spacy.load("ru_core_news_sm")
35
-
36
- # Загружаем топонимы и регистрируем их как исключения для лемматизации
37
- self._register_toponyms()
38
 
39
  # Загружаем и обрабатываем данные
40
  print("1. Загрузка данных из JSON...")
@@ -60,7 +50,6 @@ class Retrieval:
60
  tuple: (chunks, docs_metadata, paragraph_metadata, chunk_dates)
61
  где chunk_dates - список ((start_year, end_year), ...) для каждого чанка
62
  """
63
- splitter = Splitter()
64
  chunks = []
65
  docs_metadata = []
66
  paragraph_metadata = []
@@ -107,68 +96,11 @@ class Retrieval:
107
  print(f" Из {len(set(paragraph_metadata))} абзацев в {doc_id + 1} документах")
108
  return chunks, docs_metadata, paragraph_metadata, chunk_dates
109
 
110
- def get_all_chunks(self, doc_id):
111
- return [chunk for chunk, x in zip(self.chunks, self.docs_metadata, strict=True) if x == doc_id]
112
-
113
- def _register_toponyms(self):
114
- """
115
- Загружает топонимы из vocabulary/toponims.txt и регистрирует их в spaCy
116
- как custom component для исправления лемм.
117
- """
118
- toponims_file = Path(__file__).parent / "vocabulary" / "toponims.txt"
119
-
120
- if not toponims_file.exists():
121
- print(f" ⚠️ Файл {toponims_file} не найден, управление топонимами пропущено")
122
- return
123
-
124
- # Читаем топонимы
125
- with open(toponims_file, 'r', encoding='utf-8') as f:
126
- self.toponims = {line.strip().lower(): line.strip().lower() for line in f if line.strip()}
127
-
128
- print(f" Загружено {len(self.toponims)} топонимов")
129
-
130
- # Добавляем custom component для обработки топонимов после лемматизации
131
- @self.nlp.component("fix_toponyms")
132
- def fix_toponyms(doc):
133
- """Компонент для исправления лемм топонимов и их форм"""
134
- for token in doc:
135
- lemma_lower = token.lemma_.lower()
136
-
137
- # Проверяем прямое совпадение
138
- if lemma_lower in self.toponims:
139
- token.lemma_ = self.toponims[lemma_lower]
140
- else:
141
- # Проверяем, может ли это быть формой топонима
142
- # Для каждого топонима проверяем, совпадает ли начало слова
143
- for toponim in self.toponims:
144
- if lemma_lower.startswith(toponim[:len(lemma_lower)-2]) and len(lemma_lower) > len(toponim) - 3:
145
- # Похоже, это форма топонима (например, "дягилев" -> "дягилево")
146
- token.lemma_ = toponim
147
- break
148
- return doc
149
-
150
- # Добавляем компонент после лемматизатора
151
- if "fix_toponyms" not in self.nlp.pipe_names:
152
- self.nlp.add_pipe("fix_toponyms", after="lemmatizer")
153
-
154
  def _prepare_bm25(self):
155
  """Подготавливаем BM25 индекс для ключевого поиска"""
156
  # Токенизация для BM25
157
- tokenized_chunks = [self._tokenize_text(chunk) for chunk in self.chunks]
158
  return BM25Okapi(tokenized_chunks)
159
-
160
- def _tokenize_text(self, text: str) -> list[str]:
161
- """Лемматизация текста для русского языка (spaCy)"""
162
- # Используем spaCy для обработки текста и получения лемм
163
- doc = self.nlp(text.lower())
164
-
165
- # Извлекаем леммы, пропускаем пунктуацию
166
- lemmas = []
167
- for token in doc:
168
- if not token.is_punct and token.lemma_.strip(): # Пропускаем пунктуацию и пробелы
169
- lemmas.append(token.lemma_)
170
-
171
- return lemmas
172
 
173
  def rerank_search(self, query: str) -> list[dict]:
174
  """
@@ -188,7 +120,7 @@ class Retrieval:
188
 
189
  def bm25_search(self, query: str) -> list:
190
  # 2. Ключевой поиск (BM25)
191
- tokenized_query = self._tokenize_text(query)
192
  return self.bm25.get_scores(tokenized_query)
193
 
194
  def filter_by_year_range(self, indices: list[int], year_range: tuple[int, int]) -> list[int]:
 
6
  import warnings
7
  warnings.filterwarnings('ignore')
8
 
 
 
9
  from _1_get_documents import load_and_process_data
10
+ from _2_splitting import parse_year_metadata, years_overlap, YEAR_OLD, YEAR_NEW
11
+ from lemmatizer import RussianLemmatizer
12
  # from _3_chunking import RussianEmbedder
13
 
14
  from sentence_transformers import CrossEncoder
 
22
  print("Инициализация RAG системы...")
23
  self.device = "cuda" if use_gpu and torch.cuda.is_available() else "cpu"
24
 
25
+ # Инициализация лемматизатора для русского языка
26
+ print(" Инициализация лемматизатора...")
27
+ self.lemmatizer = RussianLemmatizer(load_toponyms=True)
 
 
 
 
 
 
 
 
 
28
 
29
  # Загружаем и обрабатываем данные
30
  print("1. Загрузка данных из JSON...")
 
50
  tuple: (chunks, docs_metadata, paragraph_metadata, chunk_dates)
51
  где chunk_dates - список ((start_year, end_year), ...) для каждого чанка
52
  """
 
53
  chunks = []
54
  docs_metadata = []
55
  paragraph_metadata = []
 
96
  print(f" Из {len(set(paragraph_metadata))} абзацев в {doc_id + 1} документах")
97
  return chunks, docs_metadata, paragraph_metadata, chunk_dates
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  def _prepare_bm25(self):
100
  """Подготавливаем BM25 индекс для ключевого поиска"""
101
  # Токенизация для BM25
102
+ tokenized_chunks = [self.lemmatizer.tokenize_text(chunk) for chunk in self.chunks]
103
  return BM25Okapi(tokenized_chunks)
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
  def rerank_search(self, query: str) -> list[dict]:
106
  """
 
120
 
121
  def bm25_search(self, query: str) -> list:
122
  # 2. Ключевой поиск (BM25)
123
+ tokenized_query = self.lemmatizer.tokenize_text(query)
124
  return self.bm25.get_scores(tokenized_query)
125
 
126
  def filter_by_year_range(self, indices: list[int], year_range: tuple[int, int]) -> list[int]:
tests/test_lemmatization.py CHANGED
@@ -6,7 +6,6 @@
6
  2. Лемматизацию обычных слов (включая беглые гласные)
7
  3. Обработку букв Е и Ё
8
  """
9
- import re
10
  import sys
11
  from pathlib import Path
12
  from dataclasses import dataclass
@@ -14,8 +13,8 @@ from dataclasses import dataclass
14
  # Добавляем родительскую директорию в path
15
  sys.path.insert(0, str(Path(__file__).parent.parent))
16
 
17
- import spacy
18
  from rank_bm25 import BM25Okapi
 
19
 
20
 
21
  # ============================================================================
@@ -40,6 +39,7 @@ TESTS_TOPONIMS = [
40
  # TestSearch(word='Дягилева', sentence='Примерно в 1969 году запускаются поезда от станции Рязани-1 до Дягилева и Леска - пара рейсов в день, но всё же.'),
41
  TestSearch(word='Леске', sentence='Примерно в 1969 году запускаются поезда от станции Рязани-1 до Дягилева и Леска - пара рейсов в день, но всё же.'),
42
  TestSearch(word="Дашково-Песочню", sentence="31 маршрутка ходила из Дашково-Песочни в Дягилево."),
 
43
  #TestSearch(word="Песочни", sentence="31 маршрутка ходила из Дашково-Песочни в Дягилево."),
44
  #TestSearch(word='Дашково-Песочня', sentence='То есть его продлили дальше в Песочню, и он стал охватывать так называемый основной транспортный коридор города.'),
45
  ]
@@ -47,7 +47,7 @@ TESTS_TOPONIMS = [
47
  # тесты для лемматизации обычных слов. Стемминг здесь сломается!
48
  TESTS_LEMMATIZATION = [
49
  TestSearch(word='хорошая', sentence='И там в лучшем случае было 20-23 машины где-то так.'),
50
- TestSearch(word='петли', sentence='И вместо трёх петель осталась одна маленькая в Горроще.') # беглая Е - чередование в корне
51
  ]
52
 
53
  # буквы Е и Ё в топонимах и не только
@@ -64,79 +64,21 @@ class RussianBM25:
64
  """BM25 с лемматизацией для русского языка (spaCy с топонимами)"""
65
 
66
  def __init__(self, documents: list[str]):
67
- # Загружаем русскую модель spaCy
68
- try:
69
- self.nlp = spacy.load("ru_core_news_sm")
70
- except OSError:
71
- print("Модель ru_core_news_sm не найдена, скачиваю...")
72
- import subprocess
73
- subprocess.check_call(["python", "-m", "spacy", "download", "ru_core_news_sm"])
74
- self.nlp = spacy.load("ru_core_news_sm")
75
 
76
- # Загружаем и регистрируем топонимы
77
- self._register_toponyms()
78
-
79
- tokenized_docs = [self._tokenize_text(doc) for doc in documents]
80
  self.bm25 = BM25Okapi(tokenized_docs)
81
  self.documents = documents
82
-
83
- def _register_toponyms(self):
84
- """Загружает топонимы из vocabulary/toponims.txt и регистрирует их в spaCy"""
85
- toponims_file = Path(__file__).parent.parent / "vocabulary" / "toponims.txt"
86
-
87
- if not toponims_file.exists():
88
- print(f" Файл {toponims_file} не найден, управление топонимами пропущено")
89
- return
90
-
91
- # Читаем топонимы
92
- with open(toponims_file, 'r', encoding='utf-8') as f:
93
- self.toponims = {line.strip().lower(): line.strip().lower() for line in f if line.strip()}
94
-
95
- print(f" Загружено {len(self.toponims)} топонимов из {toponims_file.name}")
96
-
97
- # Добавляем custom component для обработки топонимов после лемматизации
98
- @self.nlp.component("fix_toponyms")
99
- def fix_toponyms(doc):
100
- """Компонент для исправления лемм топо��имов и их форм"""
101
- for token in doc:
102
- lemma_lower = token.lemma_.lower()
103
-
104
- # Проверяем прямое совпадение
105
- if lemma_lower in self.toponims:
106
- token.lemma_ = self.toponims[lemma_lower]
107
- else:
108
- # Проверяем, может ли это быть формой топонима
109
- # Для каждого топонима проверяем, совпадает ли начало слова
110
- for toponim in self.toponims:
111
- if lemma_lower.startswith(toponim[:len(lemma_lower)-2]) and len(lemma_lower) > len(toponim) - 3:
112
- # Похоже, это форма топонима (например, "дягилев" -> "дягилево")
113
- token.lemma_ = toponim
114
- break
115
- return doc
116
-
117
- # Добавляем компонент после лемматизатора
118
- if "fix_toponyms" not in self.nlp.pipe_names:
119
- self.nlp.add_pipe("fix_toponyms", after="lemmatizer")
120
-
121
- def _tokenize_text(self, text: str) -> list[str]:
122
- """Лемматизация текста для русского языка (spaCy)"""
123
- # Используем spaCy для обработки текста и получения лемм
124
- doc = self.nlp(text.lower())
125
-
126
- # Извлекаем леммы, пропускаем пунктуацию
127
- lemmas = []
128
- for token in doc:
129
- if not token.is_punct and token.lemma_.strip(): # Пропускаем пунктуацию и пробелы
130
- lemmas.append(token.lemma_)
131
-
132
- return lemmas
133
 
134
  def search(self, query: str) -> list[tuple[int, float]]:
135
  """
136
  Поиск по запросу.
137
  Returns: список (индекс_документа, релевантность_score)
138
  """
139
- tokenized_query = self._tokenize_text(query)
140
  scores = self.bm25.get_scores(tokenized_query)
141
 
142
  # Возвращаем индексы документов, отсортированные по релевантности
 
6
  2. Лемматизацию обычных слов (включая беглые гласные)
7
  3. Обработку букв Е и Ё
8
  """
 
9
  import sys
10
  from pathlib import Path
11
  from dataclasses import dataclass
 
13
  # Добавляем родительскую директорию в path
14
  sys.path.insert(0, str(Path(__file__).parent.parent))
15
 
 
16
  from rank_bm25 import BM25Okapi
17
+ from lemmatizer import RussianLemmatizer
18
 
19
 
20
  # ============================================================================
 
39
  # TestSearch(word='Дягилева', sentence='Примерно в 1969 году запускаются поезда от станции Рязани-1 до Дягилева и Леска - пара рейсов в день, но всё же.'),
40
  TestSearch(word='Леске', sentence='Примерно в 1969 году запускаются поезда от станции Рязани-1 до Дягилева и Леска - пара рейсов в день, но всё же.'),
41
  TestSearch(word="Дашково-Песочню", sentence="31 маршрутка ходила из Дашково-Песочни в Дягилево."),
42
+ TestSearch(word='Канищева', sentence='А тут нас извечная проблема, связи Ворошиловки с районом, точнее сказать с Приокским, Канищево, где находятся важные объекты, причем часть расположена в Приокском, часть в Канищево.')
43
  #TestSearch(word="Песочни", sentence="31 маршрутка ходила из Дашково-Песочни в Дягилево."),
44
  #TestSearch(word='Дашково-Песочня', sentence='То есть его продлили дальше в Песочню, и он стал охватывать так называемый основной транспортный коридор города.'),
45
  ]
 
47
  # тесты для лемматизации обычных слов. Стемминг здесь сломается!
48
  TESTS_LEMMATIZATION = [
49
  TestSearch(word='хорошая', sentence='И там в лучшем случае было 20-23 машины где-то так.'),
50
+ TestSearch(word='Петли', sentence='И вместо трёх петель осталась одна маленькая в Горроще.') # беглая Е - чередование в корне
51
  ]
52
 
53
  # буквы Е и Ё в топонимах и не только
 
64
  """BM25 с лемматизацией для русского языка (spaCy с топонимами)"""
65
 
66
  def __init__(self, documents: list[str]):
67
+ # Инициализируем лемматизатор
68
+ self.lemmatizer = RussianLemmatizer(load_toponyms=True)
 
 
 
 
 
 
69
 
70
+ tokenized_docs = [self.lemmatizer.tokenize_text(doc) for doc in documents]
 
 
 
71
  self.bm25 = BM25Okapi(tokenized_docs)
72
  self.documents = documents
73
+ # Для обратной совместимости с тестами
74
+ self.nlp = self.lemmatizer.nlp
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
  def search(self, query: str) -> list[tuple[int, float]]:
77
  """
78
  Поиск по запросу.
79
  Returns: список (индекс_документа, релевантность_score)
80
  """
81
+ tokenized_query = self.lemmatizer.tokenize_text(query)
82
  scores = self.bm25.get_scores(tokenized_query)
83
 
84
  # Возвращаем индексы документов, отсортированные по релевантности
texts/реформа2012.md CHANGED
@@ -64,7 +64,7 @@
64
 
65
  Но транспортная реформа 2011 года это предполагал не только отмены, но еще и изменения маршрутов. Теперь мы перейдем к ним и надо заметить, что часть изменений была действительно воплощена в жизнь. К сожалению, я нашел только лишь изменения, которые касаются маршрутов автоколонны 1310. И большая часть их была действительно выполнена. Например, шестой автобус был продлен с завода Центролит до Братиславского, а значительная часть маршрутов была перенаправлена с Круиза на Глобус. При этом четвертый автобус планировали перенаправить с Глобуса до Новоселов, 60. И это единственный пункт изменения маршрутов автобуса в автоколонне, который выполнен так и не был. Но зато вместо четвертого автобуса до Новоселов, 60 стал ездить 16-й. По маршрутным же такси я нашел лишь список этих самых маршрутов, которые планировалось изменить. А вот как - я так и не нашел никакой информации.
66
 
67
- Ну и также, помимо отмен изменений, в реформе 2011 года планировались и новые маршруты. Один маршрут предполагалось отдать автоколонне 1310, а три остальных планировались отдать коммерческим переводчикам. Теперь же мы их также рассмотрим. Начну с автобусного номер 25. Должен был пройти от октябрьского городка по улице Чкалова, Московскому шоссе через Приокск и Канищево в Недостоево. Довольно странный маршрут, но в целом и сам по себе интересный. Единственное, что мне непонятно, как он должен был пройти из Приокского в Канищево: по улице Молодцова, по улице Станкозаводской или же вообще через троллейбусное депо номер 2. Так что тут тоже непонятно. Что ж до маршрутов, кто тут все три варианта довольно интересны. Начну с маршрута от поселка Божатково до площади Победы. Во-первых, где развернутся на площади Победы, а во-вторых, это же, по сути, сокращенный 13 автобус. Да, я понимаю, что Михайловского шоссе до площади Победы максимальный пассажиропоток, а потому там в идеале нужна какая-то дублирующая, скажем так, вспомогательная даже маршрутка. Но, зная Оризанские реалии, мне что-то подсказывает, что эта маршрутка ехала бы, не помогая автобусу, а перед ним, собирая всех пассажиров. Следующий маршрут вообще имеет какую-то странную схему, потому что тут он едет сначала по северной окружной, потом возвращается на улицу Каширина и Солнечную, потом опять едет на северную окружную дорогу в поселок Борки. Какой у него точный маршрут? Непонятно. Возможно, это не так хотели показать, что в одну сторону поедет по Солнечной, а в другую по Каширина, но лично мне это показалось непонятно. И третий маршрут с поселка Ворошиловки до завода ТКПО. Этот маршрут все-таки через некоторое время попытались ввести под номером 46, но проходил ли он в таком виде, непонятно. Скорее всего, он так ни разу и не вышел на линию. Так что в плане новых маршрутов было сделано целое ничего, поскольку реформу официально все-таки отменили.
68
 
69
  Я думаю, вы заметили, что практически ничего я до этого не говорил про троллейбус. И в том, что показали людям в конце 2011 года, действительно так же не было упоминаний про троллейбус. Но фактически в реформе его упоминания было. А именно как раз-таки была открыта новая троллейбусная линия по проезду Шабулина, улицам Бирюзовой и Интернациональной, по которой пустили два новых маршрута: четвертый из Московского ваконящего и восемнадцатый из конечьего в центре. Если четвертый маршрут был пущен вполне себе логично, да, вы сейчас скажете, что у него такой пиковый пассажиропоток, и в итоге вне часа пик он часто ездит пустым, но все-таки этот маршрут более-менее востребован. Что же с восемнадцатым троллейбусом, то тут не все так однозначно. Я как человек из будущего считаю, что восемнадцатый троллейбус нужно было пускать не в центр, а в Горрощу до центрального парка или до улицы Строителей. В тех условиях, когда предполагалось обменить 36 автобус и 50 маршрутку, имевшие подобные трассировку, такой троллейбус был бы более разумен. И можно было эту отмену вполне себе протокнуть под предлогом, что маршрутка заменяется на вместительный троллейбус. Но не свершилось. В позднее это выйдет боком еще для восьмого маршрута, который потом начнут резко менять, а ведь начнется все с отмены того самого восемнадцатого маршрута.
70
 
 
64
 
65
  Но транспортная реформа 2011 года это предполагал не только отмены, но еще и изменения маршрутов. Теперь мы перейдем к ним и надо заметить, что часть изменений была действительно воплощена в жизнь. К сожалению, я нашел только лишь изменения, которые касаются маршрутов автоколонны 1310. И большая часть их была действительно выполнена. Например, шестой автобус был продлен с завода Центролит до Братиславского, а значительная часть маршрутов была перенаправлена с Круиза на Глобус. При этом четвертый автобус планировали перенаправить с Глобуса до Новоселов, 60. И это единственный пункт изменения маршрутов автобуса в автоколонне, который выполнен так и не был. Но зато вместо четвертого автобуса до Новоселов, 60 стал ездить 16-й. По маршрутным же такси я нашел лишь список этих самых маршрутов, которые планировалось изменить. А вот как - я так и не нашел никакой информации.
66
 
67
+ Ну и также, помимо отмен изменений, в реформе 2011 года планировались и новые маршруты. Один маршрут предполагалось отдать автоколонне 1310, а три остальных планировались отдать коммерческим переводчикам. Теперь же мы их также рассмотрим. Начну с автобусного номер 25. Должен был пройти от октябрьского городка по улице Чкалова, Московскому шоссе через Приокский и Канищево в Недостоево. Довольно странный маршрут, но в целом и сам по себе интересный. Единственное, что мне непонятно, как он должен был пройти из Приокского в Канищево: по улице Молодцова, по улице Станкозаводской или же вообще через троллейбусное депо номер 2. Так что тут тоже непонятно. Что ж до маршрутов, кто тут все три варианта довольно интересны. Начну с маршрута от поселка Божатково до площади Победы. Во-первых, где развернутся на площади Победы, а во-вторых, это же, по сути, сокращенный 13 автобус. Да, я понимаю, что Михайловского шоссе до площади Победы максимальный пассажиропоток, а потому там в идеале нужна какая-то дублирующая, скажем так, вспомогательная даже маршрутка. Но, зная Оризанские реалии, мне что-то подсказывает, что эта маршрутка ехала бы, не помогая автобусу, а перед ним, собирая всех пассажиров. Следующий маршрут вообще имеет какую-то странную схему, потому что тут он едет сначала по северной окружной, потом возвращается на улицу Каширина и Солнечную, потом опять едет на северную окружную дорогу в поселок Борки. Какой у него точный маршрут? Непонятно. Возможно, это не так хотели показать, что в одну сторону поедет по Солнечной, а в другую по Каширина, но лично мне это показалось непонятно. И третий маршрут с поселка Ворошиловки до завода ТКПО. Этот маршрут все-таки через некоторое время попытались ввести под номером 46, но проходил ли он в таком виде, непонятно. Скорее всего, он так ни разу и не вышел на линию. Так что в плане новых маршрутов было сделано целое ничего, поскольку реформу официально все-таки отменили.
68
 
69
  Я думаю, вы заметили, что практически ничего я до этого не говорил про троллейбус. И в том, что показали людям в конце 2011 года, действительно так же не было упоминаний про троллейбус. Но фактически в реформе его упоминания было. А именно как раз-таки была открыта новая троллейбусная линия по проезду Шабулина, улицам Бирюзовой и Интернациональной, по которой пустили два новых маршрута: четвертый из Московского ваконящего и восемнадцатый из конечьего в центре. Если четвертый маршрут был пущен вполне себе логично, да, вы сейчас скажете, что у него такой пиковый пассажиропоток, и в итоге вне часа пик он часто ездит пустым, но все-таки этот маршрут более-менее востребован. Что же с восемнадцатым троллейбусом, то тут не все так однозначно. Я как человек из будущего считаю, что восемнадцатый троллейбус нужно было пускать не в центр, а в Горрощу до центрального парка или до улицы Строителей. В тех условиях, когда предполагалось обменить 36 автобус и 50 маршрутку, имевшие подобные трассировку, такой троллейбус был бы более разумен. И можно было эту отмену вполне себе протокнуть под предлогом, что маршрутка заменяется на вместительный троллейбус. Но не свершилось. В позднее это выйдет боком еще для восьмого маршрута, который потом начнут резко менять, а ведь начнется все с отмены того самого восемнадцатого маршрута.
70