Skip to content

Модель данных

Andrei Malykh edited this page Oct 30, 2024 · 49 revisions

Нереляционная модель

Графическое представление модели

Neo4j

Описание

User

  • name - название (String, до 50 байтов)
  • email - адрес электронной почты (String, до 129 байтов)
  • password - пароль (String - до 64 байтов)
  • created_at - Дата и время регистрации (Datetime - 8 байт)

Route

  • name - название (String, до 50 байтов)
  • description - описание (String, до 2000 байт)
  • length - длина в метрах (Float, 4 байта)
  • duration - продолжительность в минутах (Integer, 4 байта)
  • created_at - дата создания (Datetime, 8 байт)

PointOfInterest

  • name - название (String, до 50 байтов)
  • description - описание (String, до 2000 байт)

Walk

  • start_datetime - дата и время начала (Datetime, 8 байтов)
  • end_datetime - дата и время окончания (Datetime, 8 байтов)
  • length - длина в метрах (Float, 4 байта)

Dot

  • location - местоположение (Point, 16 байтов)
  • time - дата и время (Datetime, 8 байтов)

Intersection

  • street_count - количество улиц (Integer, 4 байта)
  • location - местоположение (Point, 16 байтов)

RoadSegment

  • length - длина сегмента в метрах (Float, 4 байта)

Image

  • name - название изображения (String, до 50 байтов)
  • uri - uri изображения (String, до 100 байтов)

Оценка объема информации, хранимой в модели

Возьмём средний объём текста в полях без чёткого объёма как 2/3 с округлением в верх от максимального. При расчетах подразумевается, что каждому узлу и связи нужен идентификатор типа Integer размером 4 байт.

  • User - 4 + 34 + 86 +43 + 8 =  175 байт на объект
  • Route - 4 + 34 + 1334 + 4 + 4 + 8 = 1388 байт на объект
  • PointOfInterest - 4 + 34 + 1334 = 1372 байт на объект
  • Walk - 4 + 8 + 8 + 4 = 24 байт на объект
  • Dot - 4 +  16 + 8 = 28 байт на объект
  • Intersection - 4 + 4 + 16 = 24 байт на объект
  • Image - 4 + 34 + 66 = 104 байт на объект

Также необходимо учесть связи между узлами:

  • User-CREATED->Route - 4 + 4 + 4 = 12 байт на объект
  • Walk-CREATED_BY->User - 4 + 4 + 4 = 12 байт на объект
  • Walk_ALONG_THE->Route - 4 + 4 + 4 = 12 байт на объект
  • Walk-CONSISTS_OF->Dot - 4 + 4 + 4 = 12 байт на объект
  • Route-INCLUDE->PointOfInterest - 4 + 4 + 4 + 4 (order: Integer 4 байт) = 16 байт на объект
  • PointOfInterest-CLOSE_TO_THE->Intersection - 4 + 4 + 4 = 12 байт на объект
  • PointOfInterest-DEPICTED_ON->Image - 4 + 4 + 4 = 12 байт на объект
  • Intersection-ROAD_SEGMENT->Intersection - 4 + 4 + 4 + 4 (length: Float 4 байт) = 16 байт на объект

В конечной формуле оценки будем отталкиваться от количества пользователей со следующими предположениями:

  • в среднем на человека приходится 15 маршрутов
  • в среднем маршрут состоит из 12 точек интереса
  • в среднем 30000 точек интереса
  • в среднем каждый пользовател прошёл 30 маршрутов
  • в среднем на точку интереса приходится 9 фотографий и 9 связей DEPICTED_ON
  • в среднем на отслеживание одной прогулки по маршруту требуется 35 точек отслеживания
  • для количества пересечений и сегментов дорог возьмём данные по Аптекарскому острову и умножим на 30 (1842 и 9978). Это в итоге 55260 пересечений и 299340 сегментов дорог

В итоге получаем следующую зависимость объема данных в байтах от количества пользователей:
x ⋅ (175 + 15 ⋅ (1388 + 12) + 15 ⋅ 12 ⋅ 12 + 30 ⋅ (12 + 12 + 24) + 30 ⋅ 35 ⋅ (28 + 12)) + 30000 ⋅ (1372 + 9 ⋅ (104 + 12)) + 55260 ⋅ 24 + 299340 ⋅ 16 =66775x + 78595680

Избыточность модели

Следующие данные можно отнести к избыточным:

  • Связь User-CREATED->Route - 12 байт
  • Walk-CREATED_BY->User - 12 байт
  • Walk_ALONG_THE->Route - 12 байт
  • Walk-CONSISTS_OF->Dot - 12 байт
  • Route-INCLUDE->PointOfInterest - 12 байт (все поля кроме order)
  • PointOfInterest-CLOSE_TO_THE->Intersection - 12 байт
  • PointOfInterest-DEPICTED_ON->Image - 12 байт
  • Intersection-ROAD_SEGMENT->Intersection - 12 байт (все поля кроме length)
  • Walk - 20 байт
  • Intersection - атрибут street_count - 4 бйта
  • RoadSegment - атрибут length - 4 байт

В итоге получаем излишки x⋅(15 ⋅ 12 + 15 ⋅ 12 ⋅ 12 + 30 ⋅ (12 + 12 + 20 + 12)) + 30000 ⋅ 9 ⋅ 12 + 55260 ⋅ 4 + 299340 ⋅ 4 = 4020x + 4658400

Объём чистых данных соответственно 66775x + 78835680 − 4020x - 4658400 = 62755x + 74177280

В итоге получаем следующее соотношение  $\frac{V(x)}{V_{pure}(x)}$. При 1000 пользователей получается избыточность в ≈1.063

Направление роста модели при увеличении количества объектов каждой сущности

  • При добавлении пользователь не возникает дополнительных сущностей. Рост линейный (175 байт на объект)
  • При добавлении маршрута возникает связь CREATED с пользователем, связт INCLUDE с точками интереса (среднем это 12 связей). Рост линейный (1416 байт на объект)
  • При добавлении точки интереса необходимо добавить его фотографии и добавить связи DEPICTED_ON (В среднем это 9 фото). Также требуется сопоставить ближайший перекресток, т.е. добавить связь CLOSE_TO_THE. Рост линейный (1404 байт на объект)
  • При добавлении нового изображения к точке интереса также возникает одна связь DEPICTED_ON. Рост линейный (116 байт на объект)
  • При отслеживании нового маршрута возникает новые точки отслеживания. В среднем 35, также добавляются связи ALONG_THE, CONSISTS_OF, CREATED_BY. Рост линейный (1444 байт на объект)
  • При добавлении точки OSM необходимо добавить новые сегменты дорог. В среднем на одну точку приходится 5 сегментов. Рост линейный (104 байт на объект)

В итоги для модели наблюдается только линейный рост при увеличении количества объектов.

Примеры данных

User

{
  "identity": 13,
  "labels": [
    "User"
  ],
  "properties": {
    "password": "12345678",
    "name": "Иван Рур",
    "created_at": "2024-10-30T18:46:51.927000000Z",
    "email": "[email protected]"
  },
  "elementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:13"
}

Route

{
  "identity": 16,
  "labels": [
    "Route"
  ],
  "properties": {
    "durarion": 130,
    "length": 13.5,
    "name": "По следам Пушкина",
    "created_at": "2024-10-30T18:59:28.346000000Z",
    "description": "Лучший маршрут, связанный с Пушкиным"
  },
  "elementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:16"
}

PointOfInterest

{
  "identity": 17,
  "labels": [
    "PointOfInterest"
  ],
  "properties": {
    "name": "Петропавловская крепость",
    "created_at": "2024-10-30T19:09:06.678000000Z",
    "description": "Первая крепость города",
    "location": "point({srid:4326, x:56.21, y:13.43})"
  },
  "elementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:17"
}

Image

{
  "identity": 18,
  "labels": [
    "Image"
  ],
  "properties": {
    "name": "default image",
    "uri": "[https://uri_1](https://uri_1/)"
  },
  "elementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:18"
}

Walk

{
  "identity": 19,
  "labels": [
    "Walk"
  ],
  "properties": {
    "length": 0.3,
    "end_time": "2024-10-30T19:21:47.217000000Z",
    "start_date": "2024-10-30T00:00:00Z"
  },
  "elementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:19"
}

Dot

{
  "identity": 20,
  "labels": [
    "Dot"
  ],
  "properties": {
    "location": "point({srid:4326, x:-34.2, y:32.43})",
    "time": "2024-10-30T19:26:11.220000000Z"
  },
  "elementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:20"
}

Walk-CREATED_BY->User

{
  "identity": 7,
  "start": 19,
  "end": 13,
  "type": "CREATED_BY",
  "properties": {

  },
  "elementId": "5:8029c3ee-3cb0-4f9f-9549-21a0282727a1:7",
  "startNodeElementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:19",
  "endNodeElementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:13"
}

Intersection

{
  "identity": 21,
  "labels": [
    "Intersection"
  ],
  "properties": {
    "location": "point({srid:4326, x:-34.2, y:32.43})",
    "street_count": 4
  },
  "elementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:21"
}

Intersection-ROAD_SEGMENT->Intersection

{
  "identity": 8,
  "start": 21,
  "end": 22,
  "type": "ROAD_SEGMENT",
  "properties": {
    "length": 0.2
  },
  "elementId": "5:8029c3ee-3cb0-4f9f-9549-21a0282727a1:8",
  "startNodeElementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:21",
  "endNodeElementId": "4:8029c3ee-3cb0-4f9f-9549-21a0282727a1:22"
}

Примеры запросов

Регистрация

MATCH (u: User) WHERE u.email="[email protected]"
CREATE (u: User {
	email: '[email protected]', 
	name: 'Иван Рур',
	password: '12345678', 
	created_at: datetime()
})

Итого: 1 запрос для проверки существует ли пользователь с таким email; 1 запрос для создания пользователя

Затрагивается только одна коллекция

Вход

MATCH (u: User) WHERE u.email="[email protected]" AND u.password="12345678"

Итого: 1 запрос.

Затрагивается только одна коллекция.

Поиск кратчайшего пути между точками

MATCH (source:Intersection)  
WHERE ID(source) = 45 
MATCH (dest:Intersection)  
WHERE ID(dest) = 14  
CALL apoc.algo.aStarConfig(source, dest, "ROAD_SEGMENT",  
{pointPropName: "location", weight: "length"})  
YIELD weight, path  
RETURN *

Итого: 3 запроса Затронуты две коллекции

Поиск Точек

MATCH (p: PointOfInterest) WHERE n.name =~ '(?i).*Петропавлав.*' RETURN p;

Итого: 1 запрос.

Затрагивается только одна коллекция.

Реляционная модель

Графическое представление модели

SQL

Описание отношений

User

  • user_id - целочисленный идентификатор (serial, 4 байта)
  • name - название (varchar(50), до 50 байтов)
  • email - адрес электронной почты (varchar(129), до 129 байтов)
  • password - пароль (varchar(64) - до 64 байтов)
  • created_at - дата регистрации (date - 4 байта)

Route

  • route_id - целочисленный идентификатор (serial, 4 байта)
  • name - название (varchar(50), до 50 байтов)
  • user_id - целочисленный идентификатор создателя (integer, 4 байта)
  • description - описание (varchar(2000), до 2 кб)
  • point_num - количество точек интереса (intager, 4 байта)
  • length - длина в метрах (intager, 4 байта)
  • duration - продолжительность в минутах (intager, 4 байта)
  • created_at - дата создания (date, 4 байта)

PointOfInterest

  • point_id - целочисленный идентификатор (serial, 4 байта)
  • name - название (varchar(50), до 50 байтов)
  • location - местоположение (point, 16 байтов)
  • description - описание (varchar(1000), до 2 кб)
  • intersection_id - идентификатор OSM точки (bigint, 8 байтов)

Walk

  • walk_id - целочисленный идентификатор (serial, 4 байта)
  • user_id - идентификатор пользователя (integer, 4 байта)
  • route_id - идентификатор маршрута (integer, 4 байта)
  • start_datetime - дата и время начала (timestamp, 8 байтов)
  • end_datetime - дата и время окончания (timestamp, 8 байтов)
  • dot_count - количество точек отслеживания (integer, 4 байта)
  • length - длина в метрах (integer, 4 байта)

Dot

  • dot_id - целочисленный идентификатор (serial, 4 байта)
  • walk_id - идентификатор прогулки (integer, 4 байта)
  • location - местоположение (point, 16 байтов)
  • datetime - дата и время (timestamp, 8 байтов)

Intersection

  • intersection_id - целочисленный идентификатор точки OSM (bigint, 8 байтов)
  • street_count - количество улиц (integer, 4 байта)
  • location - местоположение (point, 16 байтов)

RoadSegment

  • roadseg_id - целочисленный идентификатор (serial, 4 байта)
  • from_intersection_id - идентификатор OSM начальной точки (bigint, 8 байтов)
  • in_intersection_id - идентификатор OSM конечной точки (bigint, 8 байтов)
  • length - длина сегмента в метрах (integer, 4 байта)

Image

  • image_id - целочисленный идентификатор (serial, 4 байта)
  • name - название изображения (varchar(50), до 50 байтов)
  • uri - uri изображения (varchar(50), до 100 байтов)

Оценка объема информации, хранимой в модели

Возьмём средний объём текста в полях без чёткого объёма как 2/3 с округлением в верх от максимального. Аналогичное сделано и при оценке для нереляционной модели.

  • User - $4+34+86+43+4=171$ байт на объект
  • Route - $4+34+4+1334+4+4+4+4=1392$ байт на объект
  • PointOfInterest - $4+34+16+1334+8+4=1400$ байт на объект
  • Walk - $4+4+4+8+8+4+4=36$ байт на объект
  • Dot - $4+4+16+8=32$ байт на объект
  • Intersection - $8+4+16=28$ байт на объект
  • RoadSegment - $4+8+8+4=24$ байт на объект
  • Image - $4+34+67=105$ байт на объект

Также связь между рядом отношений поражает другие отношения:

  • Route-PointOfInterest - $4+4+4=12$ байт на связь (третье поле - нумерация для установления порядка)
  • PointOfInterest-Image - $4+4=8$ байт на связь

В конечной формуле оценки будем отталкиваться от количества пользователей со следующими предположениями:

  • в среднем на человека приходится 15 маршрутов
  • в среднем маршрут состоит из 12 точек интереса
  • в среднем каждый клиент прошёл 30 маршрутов
  • в среднем на отслеживание одной прогулки по маршруту требуется 35 точек отслеживания
  • для количества пересечений и сегментов дорог возьмём данные по Аптекарскому острову и умножим на 25 (4519 и 20720). Это в итоге 112975 пересечений и 518000 сегментов дорог
  • точек интереса 30000
  • в среднем на точку интереса приходится 9 фотографий

В итоге получаем $$x\cdot(171 + 15 \cdot 1392+15 \cdot 12 \cdot 12+30 \cdot 36+30 \cdot 35 \cdot 32) + 112975 \cdot 28 + 518000 \cdot 24 + 30000 \cdot (1400+(105+8)\cdot9) = 57891x + 88105300$$

Избыточность модели

Следующие можно посчитать избыточностью:

  • Route - атрибут user_id, point_num, length, duration - 16 байт на объект
  • PointOfInterest - атрибут intersection_id - 8 байт на объект
  • Walk - атрибуты user_id, route_id, start_datetime, end_datetime, dot_count и length - 32 байт на объект
  • Dot - атрибут walk_id - 4 байта на объект
  • RoadSegment - атрибуты from_intersection, in_intersection, length - 20 байт
  • Intersection - атрибут street_count - 4 байта
  • Route-PointOfIntest - атрибуты route_id и point_id - 8 байт
  • PointOfIntest-Image полностью - 8 байт

В итоге получаем излишки $$x\cdot(15 \cdot 16+15 \cdot 12 \cdot 8+30 \cdot 32+30 \cdot 35 \cdot 4) + 112975 \cdot 4+ 518000 \cdot 20 + 30000 \cdot (8+8\cdot9) = 6840x+13211900$$

Объём чистых данных соответственно $$57891x + 88105300 - 6840x - 13211900 = 51051x + 74893400$$

В итоге получаем следующее соотношение $$\frac{V(x)}{V_{pure}(x)}$$. При 1000 пользователей получается избыточность в $\approx 1.159$

Направление роста модели при увеличении количества объектов каждой сущности

  • При добавлении пользователь не возникает дополнительных сущностей. Рост линейный (171 байт на объект)
  • При добавлении маршрута возникает новое количество связей между маршрутом и точкой интереса. В среднем это 12 связей. Рост линейный (1536 байт на объект)
  • При добавлении точки интереса необходимо добавить его фотографии и связать их с ним. В среднем это 9 фото. Рост линейный (2417 байт на объект)
  • При добавлении нового изображения к точке интереса также возникает одно дополнительная связь. Рост линейный (113 байт на объект)
  • При отслеживании нового маршрута возникает новые точки отслеживания. В среднем 35. Рост линейный (1156 байт на объект)
  • При добавлении точки OSM необходимо добавить новые сегменты дорог. В среднем на одну точку приходится 5 сегментов. Рост линейный (148 байт на объект)

В итоге для модели наблюдается только линейный рост при увеличении количества объектов.

Примеры данных

User

user_id name email password created_at
1 Иван Рур [email protected] 12345678 2023-01-01
2 Саша Саша [email protected] 87654321 2023-01-02

Route

route_id name user_id description point_num length duration created_at
1 По следам Пушкина 1 Лучший маршрут связный с Пушкиным 2 2001 130 02.02.2023
2 Петроградка 2 Маршрут по Петроградском острову 2 1000 67 03.02.2023

PointOfInterest

point_id name location description intersection_id created_at
1 Петропавловская крепость point(x:30.3024903, y:59.9713101) Первая крепость города 1234 01.01.2023
2 Памятник Пушкину point(x:30.2924903, y:59.9113101) Отлит из бронзы 2341 01.01.2023
3 Аврора point(x:20.9924903, y:60.0013101) Корабль революции 3412 01.01.2023
4 Место дуэли Пушкина point(x:20.8124903, y:60.3413101) Здесь стрелялся Пушкин 4123 01.01.2023

Route-PointOfInterest

route_id point_id position
1 2 1
1 4 2
2 1 1
2 3 2

Image

image_id name uri
1 img1 https://uri_1
2 img2 https://uri_2
3 img3 https://uri_3
4 img4 https://uri_4

PointOfInterest-Image

user_id image_id
1 1
2 2
3 3
4 4

Walks

walk_id user_id route_id start_datetime end_datetime dot_count length
1 1 2 2023-01-01 00:00:00 2023-01-01 01:07:00 2 1002
2 2 1 2023-01-01 00:00:00 2023-01-01 02:10:00 2 2000

Dots

dot_id walk_id location time
1 1 point(x:30.3024903, y:59.9713101) 2023-01-01 00:00:00
2 2 point(x:30.2924903, y:59.9113101) 2023-01-01 00:00:00
3 1 point(x:20.9924903, y:60.0013101) 2023-01-01 01:07:00
4 2 point(x:20.8124903, y:60.3413101) 2023-01-01 02:10:00

Intersection

intersection_id street_count location
1234 1 point(x:30.3024903, y:59.9713101)
2341 2 point(x:30.2924903, y:59.9113101)
3412 2 point(x:20.9924903, y:60.0013101)
4123 1 point(x:20.8124903, y:60.3413101)

RoadSegment

roadseg_id from_intersection_id in_intersection_id length
1 1234 2341 345
2 2341 3412 354
3 3412 4123 376

Примеры запросов

Регистрация

SELECT * FROM User WHERE email = '[email protected]';
INSERT INTO User (email, name, password, created_at) 
VALUES ('[email protected]', 'Иван Рур', '12345678', CURRENT_DATE);

Вход

SELECT * FROM User 
WHERE email = '[email protected]' AND password = '12345678';

Поиск Точек

SELECT * FROM PointOfIntest
WHERE LOWER(name) ILIKE 'аврора' OR LOWER(description) ILIKE 'аврора';

Поиск кратчайшего пути между точками

pgr_astar('SELECT
        rs.roadseg_id AS source,
        rs.in_intersection_id AS target,
        rs.length AS cost,
        i1.location[0] AS x1,
        i1.location[1] AS y1,
        i2.location[0] AS x2,
        i2.location[1] AS y2
    FROM 
        RoadSegment rs
        JOIN Intersection i1 ON rs.from_intersection_id = i1.intersection_id
        JOIN Intersection i2 ON rs.in_intersection_id = i2.intersection_id
', start, end, false, false)

Сравнение моделей

Удельный объем информации

Реляционная модель демонстрирует больший удельный объём информации. При этом нереляционная модель имеет меньшую избыточность информации.

Сравнение веса по моделям:

Описываемый объект Neo4j SQL
User 175 байт 171 байт
Route 1388 байт 1392 байта
PointOfInterest 1372 байта 1400 байт
CurrentTrack 24 байта 36 байт
CurrentLocationPoint 28 байт 32 байта
RoadPoint 24 байта 28 байт
Image 104 байта 105 байт
Избыточность 1.063 1.159

Запросы по отдельным юзкейсам

Use Case Neo4j SQL
Регистрация 2 операции, 1 коллекция
Вход 1 операция, 1 коллекция
Поиск Точек 1 операция, 1 коллекция
Поиск кратчайшего пути между точками 1 операция, 3 коллекции

Вывод

В отличие от реляционной, нереляционная модель данных лучше масштабируется. Модели данных с множественными связями (например, Route и PointOfInterest) удобнее и эффективнее моделировать при помощи графов и базирующихся на них базах данных, таких как, например, neo4j. Реляционная модель лучше справляется с линейными структурами и стандартными операциями, такими как фильтрация данных и операции с большими таблицами, но может быть менее удобна для сложных связей между сущностями. Выбор между SQL и noSQL базами данных зависит от особенностей данных и задач.

Clone this wiki locally