-
Notifications
You must be signed in to change notification settings - Fork 0
Модель данных
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "House",
"type": "object",
"properties": {
"house_id": {
"type": "string",
"description": "Уникальный идентификатор дома"
},
"address": {
"type": "object",
"properties": {
"street_id": {
"type": "string",
"description": "ID улицы, к которой относится дом"
},
"number": {
"type": "string",
"description": "Номер дома"
}
},
"required": ["street_id", "number"]
},
"built_year": {
"type": "integer",
"description": "Год постройки дома"
},
"floors": {
"type": "integer",
"description": "Количество этажей"
},
"apartments": {
"type": "integer",
"description": "Количество квартир"
},
"condition": {
"type": "string",
"description": "Состояние дома"
},
"management_company": {
"type": "string",
"description": "Управляющая компания (УК)"
},
"series": {
"type": "string",
"description": "Серия или тип дома"
},
"district": {
"type": "string",
"description": "Район, в котором находится дом"
},
"image_url": {
"type": "array",
"items": {
"type": "string",
"format": "uri",
"description": "Ссылка на изображение дома"
},
"description": "Массив ссылок на изображения дома"
},
"coordinates": {
"type": "array",
"items": [
{ "type": "number", "description": "Широта" },
{ "type": "number", "description": "Долгота" }
],
"minItems": 2,
"maxItems": 2,
"description": "Координаты дома в формате [широта, долгота]"
}
},
"required": [
"house_id",
"address",
"built_year",
"floors",
"apartments",
"condition",
"management_company",
"district",
"coordinates"
]
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Street",
"type": "object",
"properties": {
"street_id": {
"type": "string",
"description": "Уникальный идентификатор улицы"
},
"name": {
"type": "string",
"description": "Название улицы"
},
"type": {
"type": "string",
"enum": ["переулок", "улица", "бульвар", "проезд", "тупик", "линия", "проспект", "шоссе", "набережная", "площадь", "аллея", "трасса"],
"description": "Тип улицы"
},
"district": {
"type": "string",
"description": "Район, в котором расположена улица"
},
"coordinates": {
"type": "array",
"items": {
"type": "array",
"items": [
{ "type": "number", "description": "Широта" },
{ "type": "number", "description": "Долгота" }
],
"minItems": 2,
"maxItems": 2,
"description": "Точка улицы в формате [широта, долгота]"
},
"description": "Координаты ломаной линии, задающей улицу"
}
},
"required": ["street_id", "name", "type", "district", "coordinates"]
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "District",
"type": "object",
"properties": {
"district_id": {
"type": "string",
"description": "Уникальный идентификатор района"
},
"name": {
"type": "string",
"description": "Название района"
},
"boundary": {
"type": "array",
"items": {
"type": "array",
"items": [
{ "type": "number", "description": "Широта" },
{ "type": "number", "description": "Долгота" }
],
"minItems": 2,
"maxItems": 2,
"description": "Точка границы в формате [широта, долгота]"
},
"description": "Границы района, заданные массивом точек ломаной"
}
},
"required": ["district_id", "name", "boundary"]
}
- Назначение: Хранение сведений о домах, предоставление информации для поиска и фильтрации по улице, району, году постройки, состоянию и другим параметрам.
- Тип данных: Объект с вложенными объектами.
-
Сущности:
-
house_id
(строка) — уникальный идентификатор дома. -
address
(объект) — содержитstreet_id
(ID улицы) иnumber
(номер дома). -
built_year
(целое число) — год постройки дома. -
floors
(целое число) — количество этажей. -
apartments
(целое число) — количество квартир. -
condition
(строка) — состояние дома. -
management_company
(строка) — управляющая компания дома. -
series
(строка) — серия или тип дома. -
district
(строка) — район, в котором расположен дом. -
image_url
(массив строк с форматом URI) — массив ссылок на фотографии дома. -
coordinates
(массив из двух чисел) — условная центральная точка дома в формате[широта, долгота]
.
-
- Назначение: Позволяет фильтровать дома по улицам и районам, поддерживает статистику улиц.
- Тип данных: Объект.
-
Сущности:
-
street_id
(строка) — уникальный идентификатор улицы. -
name
(строка) — название улицы. -
type
(строка) — тип улицы (например, переулок, улица, бульвар, проезд, тупик, линия, проспект, шоссе, набережная, площадь, аллея, трасса). -
district
(строка) — район, в котором расположена улица. -
coordinates
(массив массивов из двух чисел) — координаты ломаной линии, задающей улицу, в формате[широта, долгота]
.
-
- Назначение: Хранение информации о районах Санкт-Петербурга, включая их границы и возможность отображения на карте. Используется для фильтрации домов и улиц по районам.
- Тип данных: Объект с массивами.
-
Сущности:
-
district_id
(строка) — уникальный идентификатор района. -
name
(строка) — название района. -
boundary
(массив массивов из двух чисел) — границы района, заданные массивом точек в формате[широта, долгота]
.
-
Для оценки объема информации, хранимой в модели данных, рассмотрим каждый из типов объектов (домов и улиц) и оценим размер их хранения в памяти. Затем выразим общий объем через переменную, представляющую количество объектов одного типа.
-
Фактический объем хранения для одного объекта:
-
house_id
: 36 байт -
address
:-
street_id
: 24 байта -
number
: 10 байт
-
-
built_year
: 4 байта -
floors
: 4 байта -
apartments
: 4 байта -
condition
: 20 байт -
management_company
: 30 байт -
series
: 15 байт -
district
: 20 байт -
image_url
: 100 байт -
coordinates
: 16 байт (2 числа по 8 байт для широты и долготы)
-
Общий объем для одного объекта house
:
Чистый объем хранения для одного объекта house
(минимально необходимые поля):
-
house_id
: 36 байт -
address
(номер дома и ID улицы): 24 байта + 10 байт -
coordinates
: 16 байт
-
Фактический объем хранения для одного объекта:
-
street_id
: 36 байт -
name
: 30 байт -
type
: 10 байт -
district
: 20 байт -
coordinates
: 128 байт (напр., массив из 8 точек, каждая по 16 байт)
-
Общий объем для одного объекта street
:
Чистый объем хранения для одного объекта street
(минимально необходимые поля):
-
street_id
: 36 байт -
name
: 30 байт -
coordinates
: 128 байт
-
Фактический объем хранения для одного объекта:
-
district_id
: 36 байт -
name
: 30 байт -
coordinates
: 256 байт (напр., массив из 16 точек, каждая по 16 байт)
-
Общий объем для одного объекта district
:
Чистый объем хранения для одного объекта district
(минимально необходимые поля):
-
district_id
: 36 байт -
coordinates
: 256 байт
Пусть количество домов (houses
) — streets
) — districts
) —
Общий объем хранения данных:
Подставляя значения:
Для оценки избыточности модели взяли фактический объем хранимых данных и сравнили его с минимально необходимым («чистым») объемом данных для каждой коллекции, а затем вычислили общую избыточность модели.
Общая избыточность:
Подставляя значения:
Если количество домов (N_h
) намного превышает количество улиц (N_s
) и районов (N_d
), примем:
-
$$N_s = \frac{N_h}{K_s}$$ (где$$K_s$$ — среднее количество домов на одну улицу) -
$$N_d = \frac{N_h}{K_d}$$ (где$$K_d$$ — среднее количество домов на один район)
Подставляем
Подставляем
Для количественной оценки коэффициентов использована выборка данных из ресурса CityWalls:
- Среднее количество домов на одну улицу:
$$K_s \approx 25$$ . - Среднее количество домов на один район:
$$K_d \approx 500$$ .
Подставляем значения
- Общий объем данных:
- Общая избыточность:
Пусть:
-
$$N_h$$ — количество объектов в коллекцииhouses
, -
$$N_s$$ — количество объектов в коллекцииstreets
, -
$$N_d$$ — количество объектов в коллекцииdistricts
.
При увеличении количества объектов каждой сущности общий объем данных, требуемый для хранения, возрастает линейно. Формула для общего объема данных выглядит так:
где:
-
$$V_{\text{house}} = 283$$ байт — объем одного объектаhouse
, -
$$V_{\text{street}} = 224$$ байта — объем одного объектаstreet
, -
$$V_{\text{district}} = 322$$ байта — объем одного объектаdistrict
.
Таким образом:
- При увеличении количества объектов
house
объем$$V_{\text{total}}$$ увеличивается линейно, поскольку каждый новый объектhouse
добавляет$$V_{\text{house}}$$ байт к общему объему. - Аналогично, при увеличении количества объектов
street
объем$$V_{\text{total}}$$ увеличивается линейно, добавляя$$V_{\text{street}}$$ байт на каждый новый объектstreet
. - При увеличении количества объектов
district
объем$$V_{\text{total}}$$ также увеличивается линейно, добавляя$$V_{\text{district}}$$ байт на каждый новый объектdistrict
.
В результате общий объем данных модели зависит от числа объектов houses
, streets
и districts
, и рост модели происходит пропорционально этим параметрам.
{
"house_id": "h123",
"address": {
"street_id": "s456",
"number": "12"
},
"built_year": 1955,
"floors": 5,
"apartments": 50,
"condition": "удовлетворительное",
"management_company": "УК Жилсервис",
"series": "К-7",
"district": "Центральный",
"image_url": [
"http://example.com/images/house123_1.jpg",
"http://example.com/images/house123_2.jpg"
],
"coordinates": [59.935, 30.325]
},
{
"house_id": "h789",
"address": {
"street_id": "s321",
"number": "45A"
},
"built_year": 1978,
"floors": 9,
"apartments": 90,
"condition": "хорошее",
"management_company": "УК Комфорт",
"series": "П-44",
"district": "Фрунзенский",
"image_url": [
"http://example.com/images/house789_1.jpg",
"http://example.com/images/house789_2.jpg"
],
"coordinates": [59.85, 30.38]
}
{
"street_id": "s456",
"name": "Невский проспект",
"type": "улица",
"district": "Центральный",
"coordinates": [
[59.938, 30.315],
[59.940, 30.317],
[59.943, 30.320]
]
},
{
"street_id": "s321",
"name": "Ленинский проспект",
"type": "проспект",
"district": "Фрунзенский",
"coordinates": [
[59.84, 30.37],
[59.85, 30.38],
[59.86, 30.39]
]
}
{
"district_id": "d1",
"name": "Центральный",
"boundary": [
{"lat": 59.9343, "lon": 30.3351},
{"lat": 59.9344, "lon": 30.3352},
{"lat": 59.9345, "lon": 30.3353},
{"lat": 59.9346, "lon": 30.3354},
{"lat": 59.9347, "lon": 30.3355}
]
},
{
"district_id": "d2",
"name": "Фрунзенский",
"boundary": [
{"lat": 59.8778, "lon": 30.2943},
{"lat": 59.8780, "lon": 30.2945},
{"lat": 59.8782, "lon": 30.2947},
{"lat": 59.8784, "lon": 30.2949},
{"lat": 59.8786, "lon": 30.2951}
]
}
FOR house IN houses
RETURN house
INSERT {
house_id: @house_id,
address: @address,
built_year: @built_year,
floors: @floors,
apartments: @apartments,
condition: @condition,
management_company: @management_company,
series: @series,
district: @district,
image_url: @image_url
} INTO houses
FOR street IN streets
FILTER street.type == @type AND street.district == @district
RETURN street
FOR house IN houses
FILTER house.address.street_id == @street_id
RETURN house
FOR house IN houses
FILTER house.house_id == @house_id
RETURN {
"built_year": house.built_year,
"floors": house.floors,
"apartments": house.apartments,
"condition": house.condition,
"management_company": house.management_company,
"series": house.series,
"district": house.district,
"image_url": house.image_url
}
FOR house IN houses
FILTER house.built_year == @built_year
AND house.district == @district
AND house.floors == @floors
AND house.apartments == @apartments
AND house.address.street_id == @street_id
AND house.management_company == @management_company
AND house.condition == @condition
RETURN house
FOR house IN houses
FILTER house.built_year == @built_year
AND house.district == @district
AND house.floors == @floors
AND house.apartments == @apartments
AND house.address.street_id == @street_id
AND house.management_company == @management_company
AND house.condition == @condition
RETURN {
"coordinates": house.coordinates,
"house_id": house.house_id,
"description": {
"built_year": house.built_year,
"floors": house.floors,
"apartments": house.apartments,
"condition": house.condition,
"management_company": house.management_company
}
}```
##### 7.1.8. Запрос на получение статистики по улицам
```aql
FOR street IN streets
COLLECT type = street.type WITH COUNT INTO count
RETURN { "type": type, "count": count }
FOR house IN houses
COLLECT year = house.built_year WITH COUNT INTO count
RETURN { "built_year": year, "count": count }
7.1.10. Запрос на получение статистики: сколько домов на какой улице было построено в каком десятилетии
FOR house IN houses
LET decade = FLOOR(house.built_year / 10) * 10
COLLECT street_id = house.address.street_id, decade INTO grouped
LET count = LENGTH(grouped)
RETURN {
"street_id": street_id,
"decade": decade,
"house_count": count
}
-
Экспорт: 1 запрос для выгрузки всех данных из
houses
. -
Импорт: 1 запрос для вставки данных в
houses
.
Итого: 2 запроса.
- Получение улиц по фильтру: 1 запрос.
- Получение домов на выбранной улице: 1 запрос.
- Получение информации о конкретном доме: 1 запрос.
Итого: 3 запроса.
- Получение домов по заданным параметрам: 1 запрос.
- Получение информации о конкретном доме: 1 запрос.
Итого: 2 запроса.
- Получение домов с заданными параметрами для отображения на карте: 1 запрос.
Итого: 1 запрос.
- Получение статистики по улицам: 1 запрос.
- Получение статистики по домам: 1 запрос.
Итого: 2 запроса.
ER-диаграмма для реляционной модели, включающая основные сущности houses
и streets
, а также связи между ними:
-
Таблица houses:
- Поля:
-
house_id
(PRIMARY KEY) -
street_id
(FOREIGN KEY ссылается на streets) number
built_year
floors
apartments
condition
management_company
series
image_url
coordinates
-
- Поля:
-
Таблица streets:
- Поля:
-
street_id
(PRIMARY KEY) name
type
-
district_id
(FOREIGN KEY) coordinates
-
- Поля:
-
Таблица districts:
- Поля:
-
district_id
(PRIMARY KEY) name
boundary
-
- Поля:
-
Таблица
houses
- Назначение: Хранение информации о домах с привязкой к улицам, состоянию, управляющей компании и т. д.
- Типы данных: Идентификаторы и строки, целые числа, ссылки.
- Сущности:
-
house_id
(строка) — уникальный идентификатор дома. -
street_id
(строка) — ID улицы. -
number
(строка) — номер дома. -
built_year
(целое число) — год постройки. -
floors
(целое число) — этажность. -
apartments
(целое число) — количество квартир. -
condition
(строка) — состояние. -
management_company
(строка) — управляющая компания. -
series
(строка) — серия или тип. -
image_url
(массив строк) — массив ссылок на изображения. -
coordinates
(массив из двух чисел) — условная центральная точка дома в формате [широта, долгота].
-
-
Таблица
streets
- Назначение: Хранение информации о улицах.
- Типы данных: Идентификаторы, строковые значения.
- Сущности:
-
street_id
(строка) — уникальный идентификатор улицы. -
name
(строка) — название. -
type
(строка) — тип улицы. -
district_id
(строка) — ID района, в котором расположена улица. -
coordinates
(массив массивов из двух чисел) — координаты ломаной линии, задающей улицу, в формате [широта, долгота]
-
-
Таблица
districs
- Назначение: Хранение информации о районах города, включая их границы, используемое для фильтрации домов и улиц по районам.
- Типы данных: Идентификаторы, строки, массивы.
- Сущности:
-
district_id
(строка) — уникальный идентификатор района. -
name
(строка) — название района. -
boundary
(массив массивов из двух чисел) — границы района, заданные массивом точек в формате [широта, долгота]
-
Общий объем для одного объекта house
:
Чистый объем хранения для одного объекта house
Общий объем для одного объекта street
:
Чистый объем хранения для одного объекта street
Общий объем для одного объекта district
:
Чистый объем хранения для одного объекта district
Общий объем хранения в зависимости от количества объектов, где количество домов (houses) —
Общая избыточность:
-
При увеличении числа объектов в таблице
houses
— объем хранимой информации увеличивается линейно, как функция от$$N_h$$ . -
При увеличении числа объектов в таблице
streets
— объем хранимой информации увеличивается линейно, как функция от$$N_s$$ . -
При увеличении числа объектов в таблице
districts
— объем хранимой информации увеличивается линейно, как функция от$$N_d$$ .
INSERT INTO houses (house_id, street_id, number, built_year, floors, apartments, condition, management_company, series, image_url, coordinates)
VALUES
('h123', 's456', '12', 1955, 5, 50, 'удовлетворительное', 'УК Жилсервис', 'К-7', '{"http://example.com/images/house123_1.jpg", "http://example.com/images/house123_2.jpg"}', '[59.9343, 30.3351]' ),
('h789', 's321', '45A', 1978, 9, 90, 'хорошее', 'УК Комфорт', 'П-44', '{"http://example.com/images/house789.jpg"}', '[59.8765, 30.1234]');
INSERT INTO streets (street_id, name, type, district_id, coordinates)
VALUES
('s456', 'Невский проспект', 'улица', 'd1', '[[59.9343, 30.3351], [59.9375, 30.3382]]'),
('s321', 'Ленинский проспект', 'проспект', 'd2', '[[59.8765, 30.1234], [59.8790, 30.1256]]');
INSERT INTO districts (district_id, name, boundary)
VALUES
('d1', 'Центральный', '[[59.9280, 30.3150], [59.9370, 30.3250], [59.9390, 30.3400], [59.9300, 30.3550]]'),
('d2', 'Фрунзенский', '[[59.8700, 30.1100], [59.8800, 30.1200], [59.8850, 30.1300], [59.8760, 30.1400]]');
SELECT * FROM houses;
INSERT INTO houses (house_id, street_id, number, built_year, floors, apartments, condition, management_company, series, image_url, coordinates)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
SELECT * FROM streets
WHERE type = ? AND district_id = ?;
SELECT * FROM houses
WHERE street_id = ?;
SELECT * FROM houses
WHERE house_id = ?;
SELECT h.*
FROM houses h
JOIN streets st ON h.street_id = st.street_id
WHERE (h.built_year = ? OR ? IS NULL)
AND (st.district_id = ? OR ? IS NULL)
AND (h.floors = ? OR ? IS NULL)
AND (h.apartments = ? OR ? IS NULL)
AND (h.street_id = ? OR ? IS NULL)
AND (h.management_company = ? OR ? IS NULL)
AND (h.condition = ? OR ? IS NULL);
SELECT
h.house_id,
CONCAT(st.name, ', ', h.number) AS address,
h.built_year,
h.floors,
h.apartments,
h.condition,
h.management_company,
h.series,
st.district_id,
h.image_url
FROM
houses h
JOIN
streets st ON h.street_id = st.street_id
WHERE
(h.built_year = ? OR ? IS NULL)
AND (st.district_id = ? OR ? IS NULL)
AND (h.floors = ? OR ? IS NULL)
AND (h.apartments = ? OR ? IS NULL)
AND (h.street_id = ? OR ? IS NULL)
AND (h.management_company = ? OR ? IS NULL)
AND (h.condition = ? OR ? IS NULL);
SELECT COUNT(street_id), type, district_id
FROM streets
GROUP BY type, district_id;
SELECT COUNT(house_id), built_year, floors, apartments, management_company, condition
FROM houses
GROUP BY built_year, floors, apartments, management_company, condition;
SELECT
st.name AS street_name,
FLOOR(h.built_year / 10) * 10 AS decade,
COUNT(h.house_id) AS house_count
FROM
houses h
JOIN
streets st ON h.street_id = st.street_id
GROUP BY
st.name,
FLOOR(h.built_year / 10)
ORDER BY
st.name,
decade;
-
Импорт и экспорт данных
-
Экспорт данных: 1 запрос
SELECT * FROM houses
-
Импорт данных: 1 запрос
INSERT
для массовой загрузки.- Итого: 2 запроса
-
Экспорт данных: 1 запрос
-
Получение информации о доме через фильтр улиц
- Получение списка улиц по фильтру: 1 запрос
SELECT
по таблицеstreets
- Получение списка домов на выбранной улице: 1 запрос
SELECT
по таблицеhouses
- Получение информации о конкретном доме: 1 запрос
SELECT
по таблицеhouses
- Итого: 3 запроса
- Получение списка улиц по фильтру: 1 запрос
-
Получение информации о доме через фильтр домов
- Получение списка домов по фильтру: 1 запрос
SELECT
по таблицеhouses
- Получение информации о конкретном доме: 1 запрос
SELECT
по таблицеhouses
- Итого: 2 запроса
- Получение списка домов по фильтру: 1 запрос
-
Найти дом на карте города
- Получение списка домов для отображения на карте с параметрами: 1 запрос
SELECT
- Итого: 1 запрос
- Получение списка домов для отображения на карте с параметрами: 1 запрос
-
Подсчет статистики в системе
- Подсчет количества домов по характеристикам: 1 запрос
SELECT
с группировкой по таблицеhouses
- Подсчет количества улиц по типу и району: 1 запрос
SELECT
с группировкой по таблицеstreets
- Итого: 2 запроса
- Подсчет количества домов по характеристикам: 1 запрос
В реляционной модели данные структурированы в таблицах, и при наличии большого количества взаимосвязанных данных требуется больше памяти на хранение. Для хранения одной записи может потребоваться дополнительное место для хранения индексов и для выполнения операций JOIN
, которые могут увеличивать объем хранимых данных. В нереляционной модели данные могут храниться в виде документов, и взаимосвязанные данные могут храниться вместе в одном документе, что снижает избыточность. На основании вышесказанного, можно отметить, что при прочих равных условиях реляционная модель может занимать больший объем памяти по сравнению с нереляционной моделью из-за избыточности.
В запросах для ArongoDB и SQL требуется одинаковое количество операций.
Для проекта, ориентированного на хранение информации о домах, как в историческом аспекте, так и в контексте удобного доступа и анализа, обе модели (SQL и NoSQL) имеют свои преимущества.
-
SQL модель: Подходит для строго структурированных данных с постоянными отношениями и обеспечивает строгую целостность данных. Она лучше для моделей, где требуется точное соблюдение связей, например, для реализации сложных отчетов и аналитики. SQL отлично поддерживает стандартизированные и табличные данные, что делает её оптимальной для моделей с фиксированными схемами и ограниченным количеством вложений и связей.
-
NoSQL модель (в частности, ArangoDB): Предлагает гибкость в структуре данных, что упрощает хранение и добавление новых свойств без необходимости изменять всю схему. ArangoDB, как база графов и документов, позволяет эффективно моделировать сложные отношения и вложения. В проектах с динамической структурой данных и при необходимости горизонтального масштабирования NoSQL будет более подходящим.
С учетом требований к проекту — высокой гибкости в хранении, работы с вложенными данными и возможных изменений в структуре данных — NoSQL может быть предпочтительным выбором, поскольку позволит легче адаптироваться к изменяющимся данным и требованиям.