Задача Проработать раздел Транспорт
Проработать раздел Транспорт
Сейчас в базе данных есть почти 1500 старых записей маршрутов. Но данные лежал плоские вот в таком виде:
{
"id": 4,
"city": "ho-chi-minh",
"city2": "mui-ne",
"time": "07:30",
"time2": "12:30",
"price": "120000",
"company": "Tam Hanh Cafe",
"type": "bus",
"gps_link": "https://goo.gl/maps/86122wbjUQ62",
"gps_link2": "https://goo.gl/maps/1Sabdd9TVy42",
"address": "199 Phạm Ngũ Lão, Quận 1, Hồ Chí Minh",
"address2": "135 Nguyễn Đình Chiểu, Phường Hàm Tiến, Thành phố Phan Thiết, Bình Thuận",
"phone": "+84 283 920 5653",
"note": ""
}
Проблема тут в том, что нет отдельного справочника как минимум компаний.
Сейчас, если сделать выборку компаний и типов перевозок с группировкой, то получается такая картина:
| count(*) | company | type |
|---|---|---|
| 772 | Futa Bus | bus |
| 175 | Hanh Cafe | bus |
| 41 | Tam Hanh Cafe | bus |
| 79 | The Sinh Tourist | bus |
| 1 | LC3 | train |
| 1 | LC4 | train |
| 1 | MR1 | train |
| 1 | NH1 | train |
| 1 | NH2 | train |
| 34 | SE1 | train |
| 2 | SE1 (Livitrans Express) | train |
| 7 | SE1 (Violette Train) | train |
| 6 | SE17 | train |
| 8 | SE18 | train |
| 9 | SE19 | train |
| 29 | SE2 | train |
| 2 | SE2 (Livitrans Express) | train |
| 2 | SE2 (Violette Train) | train |
| 10 | SE20 | train |
| 2 | SE21 | train |
| 2 | SE22 | train |
| 1 | SE22 (Livitrans Express) | train |
| 35 | SE3 | train |
| 9 | SE3 (Violette Train) | train |
| 29 | SE4 | train |
| 2 | SE4 (Violette Train) | train |
| 34 | SE5 | train |
| 29 | SE6 | train |
| 34 | SE7 | train |
| 29 | SE8 | train |
| 1 | SNT1 | train |
| 1 | SNT2 | train |
| 1 | SNT2 (Livitrans Express) | train |
| 1 | SP1 | train |
| 1 | SP2 | train |
| 1 | SP3 | train |
| 1 | SP4 | train |
| 1 | SP7 | train |
| 1 | SP8 | train |
| 1 | SPT1 | train |
| 1 | SPT2 | train |
| 8 | Boat Company | boat |
| 4 | Greenlines DP | boat |
| 8 | Ka Long | boat |
| 14 | Phu Quoc Express | boat |
| 16 | Superdong | boat |
| 10 | The Sinh Tourist | boat |
Тут как минимум SP1, SP2 и т.п. - это не компании вообще, а маршруты поездов. А вот SNT2 (Livitrans Express) - это отдельные вагоры компании Livitrans Express в поезде SNT2. Так что текущяя структура вообще ни к черту.
Но есть еще проблема: есть дубли записей.
| count(*) | company | city | city2 | time | address | address2 |
|---|---|---|---|---|---|---|
| 4 | Hanh Cafe | hue | ho-chi-minh | 08:30 | 28 Chu Văn An, Phú Hội, Thành phố Huế, Thừa Thiên ... | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... |
| 4 | Hanh Cafe | hue | ho-chi-minh | 13:30 | 28 Chu Văn An, Phú Hội, Thành phố Huế, Thừa Thiên ... | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... |
| 4 | Hanh Cafe | hoi-an | ho-chi-minh | 17:30 | 12 Nguyễn Tất Thành, Phường Cẩm Phổ, tp. Hội An, Q... | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... |
| 2 | Futa Bus | ho-chi-minh | rach-gia | 18:15 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 260A Nguyễn Bỉnh Khiêm, Vĩnh Thanh, Rạch Giá, tỉnh... |
| 2 | Hanh Cafe | nha-trang | ho-chi-minh | 07:30 | 10 Hùng Vương, Lộc Thọ, Thành phố Nha Trang, Khánh... | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... |
| 2 | Hanh Cafe | nha-trang | ho-chi-minh | 13:00 | 10 Hùng Vương, Lộc Thọ, Thành phố Nha Trang, Khánh... | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... |
| 2 | Futa Bus | ho-chi-minh | soc-trang | 22:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | ấp ngãi hội 2 , thị trấn đại ngãi , huyện long phú... |
| 2 | Hanh Cafe | phan-thiet | ha-noi | 01:30 | 173 Tôn Đức Thắng, Phú Thuỷ, Thành phố Phan Thiết,... | Nguyễn Khoái, Bạch Đằng, Hai Bà Trưng, Hà Nội |
| 2 | Hanh Cafe | ho-chi-minh | vinh-long | 07:45 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá... |
| 2 | Hanh Cafe | phan-thiet | ha-noi | 13:30 | 173 Tôn Đức Thắng, Phú Thuỷ, Thành phố Phan Thiết,... | Nguyễn Khoái, Bạch Đằng, Hai Bà Trưng, Hà Nội |
| 2 | Hanh Cafe | ho-chi-minh | vinh-long | 09:30 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá... |
| 2 | Futa Bus | ho-chi-minh | chau-doc | 07:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi... |
| 2 | Hanh Cafe | ho-chi-minh | vinh-long | 13:15 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá... |
| 2 | Futa Bus | ho-chi-minh | chau-doc | 08:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi... |
| 2 | Hanh Cafe | ho-chi-minh | vinh-long | 16:30 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá... |
| 2 | Hanh Cafe | ho-chi-minh | vinh-long | 19:15 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá... |
| 2 | Futa Bus | ho-chi-minh | sa-dec | 16:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 149/8 khóm Hòa Khánh, Phường 2, Sa Đéc, Đồng Tháp,... |
| 2 | Hanh Cafe | ho-chi-minh | vinh-long | 21:30 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Lê Qúy Đôn, Khu 4, Thị Trấn Cái Bè, TT. Cái Bè, Cá... |
| 2 | Futa Bus | ho-chi-minh | sa-dec | 17:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 149/8 khóm Hòa Khánh, Phường 2, Sa Đéc, Đồng Tháp,... |
| 2 | Futa Bus | ho-chi-minh | chau-doc | 12:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi... |
| 2 | Hanh Cafe | ho-chi-minh | can-tho | 07:45 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Mỹ Thuận, Bình Minh, Vinh Long |
| 2 | Futa Bus | ho-chi-minh | sa-dec | 18:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 149/8 khóm Hòa Khánh, Phường 2, Sa Đéc, Đồng Tháp,... |
| 2 | Hanh Cafe | ho-chi-minh | can-tho | 09:30 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Mỹ Thuận, Bình Minh, Vinh Long |
| 2 | Hanh Cafe | ho-chi-minh | can-tho | 13:15 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Mỹ Thuận, Bình Minh, Vinh Long |
| 2 | Hanh Cafe | ho-chi-minh | can-tho | 16:30 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Mỹ Thuận, Bình Minh, Vinh Long |
| 2 | Futa Bus | ho-chi-minh | chau-doc | 16:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi... |
| 2 | Hanh Cafe | ho-chi-minh | can-tho | 19:15 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Mỹ Thuận, Bình Minh, Vinh Long |
| 2 | Hanh Cafe | ho-chi-minh | can-tho | 21:30 | 229 Phạm Ngũ Lão, Phường Phạm Ngũ Lão, Quận 1, Hồ ... | Mỹ Thuận, Bình Minh, Vinh Long |
| 2 | Futa Bus | ho-chi-minh | chau-doc | 18:00 | 272 Đường Đề Thám, Phường Phạm Ngũ Lão, Quận 1, Hồ... | 69 Phan Văn Vàng, Châu Phú A, An Phú, An Giang, Vi... |
| 1 | Tam Hanh Cafe | mui-ne | ho-chi-minh | 05:00 | 135 Nguyễn Đình Chiểu, Phường Hàm Tiến, Thành phố ... | 199 Phạm Ngũ Lão, Quận 1, Hồ Chí Minh |
От дублей надо избавиться еще на уровне импорта. Благо отдельных страниц для каждого маршрута в отдельности не было. Кстати, надо будет их сделать.
Ворклоги
Кстати, в некоторых маршрунах еще и данные битые.
"Can not get city2: \"cat-ba-island\"",
"Can not get city2: \"cat-ba-island\"",
"Can not get city2: \"cat-ba-island\"",
"Can not get city: \"cat-ba-island\"",
"Can not get city: \"cat-ba-island\"",
"Can not get city: \"cat-ba-island\"",
"Can not get city2: \"phong-nha-ke-bang\"",
"Can not get city2: \"nam-du-island\"",
"Can not get city2: \"nam-du-island\"",
"Can not get city2: \"nam-du-island\"",
"Can not get city: \"nam-du-island\"",
"Can not get city: \"nam-du-island\"",
Недо попутно завести.
Кстати, вот что чатгпт говорит по поводу нашей структуры базы знаний:
Самое сильное здесь — не отдельные модели, а то, как они складываются вместе.
Что здесь реально мощного
KBConcept фактически может быть универсальной сущностью сайта:
- страна;
- регион;
- город;
- район;
- пляж;
- храм;
- аэропорт;
- отель;
- маршрут;
- событие;
- транспортный узел.
У концепта уже есть:
- иерархия
Parent / Children; - корень дерева;
- координаты
lat / lng / alt; - мультиязычные названия через
KBLabel; - файлы и изображения;
- факты;
- привязка к URL через
SiteRoute; - произвольные структурированные данные через
Json.
То есть город, достопримечательность и маршрут — не просто статьи в CMS, а узлы единого графа знаний.
И это идеально совпадает с VietnamGuru.
Например:
Дананг → район Сон Тра → пагода Линь Унг → координаты → часы работы → стоимость → сезонность → транспорт → объекты рядом → статья → карта → маршрут.
Все это можно хранить не в одном огромном тексте, а как связанные знания.
Самая перспективная часть — факты не привязаны жестко к одной сущности
KBFact вместе с KBFactParticipation поддерживает n-арные связи: один факт может связывать сразу несколько концептов с разными ролями.
Для туристического проекта это очень сильная модель.
Например, утверждение:
Автобус №5 идет из Дананга в Хойан, останавливается возле Marble Mountains, билет стоит 30 000 донгов.
Можно представить одним фактом, где участвуют:
- Дананг —
origin; - Хойан —
destination; - Marble Mountains —
stop; - автобус №5 —
transport; - 30 000 VND — значение;
- период актуальности;
- источник;
- confidence;
- статус проверки.
И если цена или маршрут поменяются, старый факт не уничтожается. Добавляется новый, с новой датой актуальности. Для путешествий это критически важно: визовые правила, цены, расписания, входные билеты и транспорт постоянно меняются.
Тут заложена полноценная эпистемическая модель
Особенно нравится, что база не притворяется абсолютной истиной.
У фактов есть:
confidence;verified / tentative / disputed / deprecated;- источник;
- период действия;
- дата, когда факт стал известен;
- raw или derived;
- происхождение из других фактов.
Плюс противоречия являются самостоятельными объектами через KBConflict, а не просто перезаписываются.
Для туристического ИИ это огромный плюс.
Типичный реальный случай:
- Google Maps говорит, что место открыто до 18:00;
- официальный сайт говорит до 17:00;
- свежий отзыв говорит, что касса закрывается в 16:30.
Обычный RAG просто выдаст один из вариантов. Твоя модель позволяет агенту сказать:
«Источники расходятся. Официально указано 17:00, но посетители сообщают о более раннем закрытии кассы. Лучше приехать до 16:00».
Вот это уже не чат-бот над статьями, а нормальный интеллектуальный туристический помощник.
KBKnowledgeSpace открывает еще один уровень
Knowledge Spaces позволяют одному и тому же факту иметь разную:
- видимость;
- важность;
- степень доверия;
- интерпретацию.
Это можно использовать не только для приватности, но и для разных режимов продукта:
- база редакции;
- публичная база;
- персональное пространство пользователя;
- пространство конкретной поездки;
- знания агента;
- партнерский контент;
- непроверенные пользовательские данные.
Например, турист создает поездку «Вьетнам, август, семья с ребенком». Агент может построить отдельное пространство знаний, где выше приоритет у:
- коротких переездов;
- семейных пляжей;
- объектов с кондиционером;
- безопасной еды;
- мест без сложных подъемов.
Те же факты существуют глобально, но их важность меняется в контексте поездки.
SiteRoute делает структуру сайта продолжением knowledge graph
Связь SiteRoute ↔ KBConcept — очень правильная идея.
Это означает, что URL — не сама сущность, а представление сущности.
В результате можно:
- менять маршрут без потери концепта;
- строить хлебные крошки из дерева;
- генерировать страницы автоматически;
- создавать региональные разделы;
- поддерживать старые URL через redirects;
- находить сущности без публичной страницы;
- давать одному объекту разные представления.
Для SEO это особенно ценно. Контентная архитектура может рождаться из графа, а не поддерживаться вручную в нескольких несвязанных таблицах.
Карта здесь вообще может стать интерфейсом к базе знаний
Теперь твое пояснение про карту выглядит еще интереснее.
Поскольку координаты есть и у KBConcept, и у File, карта может показывать не просто точки из статей, а целую пространственную модель:
- города;
- достопримечательности;
- фотографии, привязанные к месту;
- маршруты;
- объекты рядом;
- факты с географическим контекстом;
- пользовательские сохранения;
- зоны интереса.
А агент может выполнять запросы уровня:
«Покажи интересные места в радиусе 15 км от Нячанга, куда можно доехать без байка и где есть смысл быть после 17:00».
Для такого запроса обычной статьи недостаточно. А эта схема потенциально позволяет собрать ответ из координат, фактов, связей, ограничений и предпочтений пользователя.