Поможите. Одна комната, много детей :)
От: Mamut Швеция http://dmitriid.com
Дата: 15.10.08 14:39
Оценка:
Я тут все с туризмом вожусь. Чувствую, что уже задавал этот вопрос, н онайти не могу

Задача:
У нас в отеле есть комната. В этой комнате могут проживать взрослые (ADL), а с ними — дети (CHLD) разных категорий. Категории детей типа 0-6 лет, 7-10 лет, 12-13 лет. Для каждого отлея разные, внутри одного отеля возраст в категории детей не пересекается

Таким образом, для комнаты могут быть такие комбинации проживания:
1 ADL, 2 ADL, 3 ADL

1 ADL + 1 CHLD 0-6    1 ADL + 1 CHLD 7-10    1 ADL + 1 CHLD 12-13
1 ADL + 2 CHLD 0-6    1 ADL + 2 CHLD 7-10    1 ADL + 2 CHLD 12-13

2 ADL + 1 CHLD 0-6    2 ADL + 1 CHLD 7-10    2 ADL + 1 CHLD 12-13
2 ADL + 2 CHLD 0-6    2 ADL + 2 CHLD 7-10    2 ADL + 2 CHLD 12-13

1 ADL + 1 CHLD 0-6 + 1 CHLD 7-10
1 ADL + 1 CHLD 0-6 + 1 CHLD 12-13

и т.п. - перебор всех вариантов


Это все усугубляется тем, что в одном отеле может быть одна категория детей, а в другом — пять категорий.

Меня сильно интересует вопрос, как это все максимально просто и эффективно хранить в базе данных (RDBMS, на всякие OO и Document-oriented не замахиваемся ), учитывая, что по этому всему еще и искать надо

То есть ищет человек комнату на 1 взрослого с двумя детьми 4-х и 8-и лет. Я должен выдать
Hоtel 1        1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12
Hotel 2        1 ADL + 2 CHLD 3-12
Hotel 3        2 ADL + 1 CHLD 0-3 *
*в третьем отеле просто дети огрничиваются пятлетним возрастом


Я пока в грусти и раздумье. Когда категорий детей было ровно две, все было хорошо. А сейчас... Я не говорю уже про генерацию цен...


dmitriid.comGitHubLinkedIn
Re: Поможите. Одна комната, много детей :)
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.10.08 06:49
Оценка: 45 (1)
Здравствуйте, Mamut, Вы писали:
У тебя есть всего два варианта:
1. Реляционизировать представление "возможные варианты проживания в комнате".
Примерно так:
create table slot
(
    id int identity,
    combinationId int not null,
    roomId int not null foreign key references room(id),
    minAge int
    maxage int
)

Потом будет болезненно много joinов, експоненциальный взрыв количества записей во временных таблицах и унылая борьба с попыткой двух взрослых занять одну и ту же кровать.
2. Воспользоваться возможностями строкового поиска.
Вот смотри: если бы у тебя был фиксированный набор "категорий", то можно было бы сопоставить каждой категории букву.
Например, так:
14-99: A
11-13: B
 7-10: C
 0- 6: D

Тогда каждую разрешенную комбинацию можно однозначно представить в виде строки, отсортировав категории по алфавиту:
A, AA, AAA // 1 ADL, 2 ADL, 3 ADL

AD, AC, AB // 1 ADL + 1 CHLD 0-6    1 ADL + 1 CHLD 7-10    1 ADL + 1 CHLD 12-13
ADD, ACC, ABB // 1 ADL + 2 CHLD 0-6    1 ADL + 2 CHLD 7-10    1 ADL + 2 CHLD 12-13

AAD, AAC, AAB // 2 ADL + 1 CHLD 0-6    2 ADL + 1 CHLD 7-10    2 ADL + 1 CHLD 12-13
AADD, AACC, AABB // 2 ADL + 2 CHLD 0-6    2 ADL + 2 CHLD 7-10    2 ADL + 2 CHLD 12-13

ACD // 1 ADL + 1 CHLD 0-6 + 1 CHLD 7-10
ABD // 1 ADL + 1 CHLD 0-6 + 1 CHLD 12-13


Ну и точно так же представить и семью. Например, твой взрослый с двумя детьми порождает цепочку ACD.

В таком случае можно было бы выполнить поиск на точное совпадение строки, а он работает blazingly fast.

Как залудить строковый поиск в случае переменного количества диапазонов возрастов я пока не придумал .
В принципе, есть хомячковый способ — унифицировать классификацию, а для тех отелей, где мало категорий, вводить "лишние комбинации". Типа если отель разбирается только на уровне "ребенок/взрослый", и есть всего три цены — 1ADL, 2ADL, 1ADL+Child, то генерировать все комбинации 1ADL+0..6, 1ADL+7..10, 1ADL+11..13.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Поможите. Одна комната, много детей :)
От: Mamut Швеция http://dmitriid.com
Дата: 16.10.08 14:38
Оценка:
S>1. Реляционизировать представление "возможные варианты проживания в комнате".
S>Примерно так:
S>Потом будет болезненно много joinов, експоненциальный взрыв количества записей во временных таблицах и унылая борьба с попыткой двух взрослых занять одну и ту же кровать.

Ага, у нас так сейчас и есть на 2-х категориях детей. Запросы еще те

S>2. Воспользоваться возможностями строкового поиска.


О! Спасибо! Буду думать в этом направлении


dmitriid.comGitHubLinkedIn
Re[3]: Поможите. Одна комната, много детей :)
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.10.08 04:01
Оценка: 30 (1)
Здравствуйте, Mamut, Вы писали:

M>О! Спасибо! Буду думать в этом направлении

Вообще есть подозрение, что модель переусложнена. В том смысле, что насколько мне известно, отели работают проще.
Идея в том, что у комнаты существует, грубо говоря, некоторое количество посадочных мест. И всё — размещайся, как хочешь.
А возраст детей влияет только на ценообразование. Причем аддитивно и рефлексивно, то есть если ребенок 11-13 — это +23 за ночь, то и второй тоже +23. А не так, что у каждой комбинации своя независимая цена.
Если копать в эту сторону, то всё будет намного проще. Просто ищешь все варианты трехместного размещения, а потом вычисляешь для них цену в зависимости от правил.

Но тебе виднее. Если не получается вынести сложность за пределы комнат, то можно упростить себе жизнь (и усложнить ее серверу), кодируя возможные варианты при помощи like-expressions.
То есть в принципе латинских букв достаточно для детальной классификации возрастов от 0 до 26, чего, в принципе, должно хватить.
А дальше записываешь комбинацию "1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12" как 'Z[H-M][A-G]', семью как 'ZIE', и делаешь
select from combination where @family like ages
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Поможите. Одна комната, много детей :)
От: Mamut Швеция http://dmitriid.com
Дата: 17.10.08 08:49
Оценка:
M>>О! Спасибо! Буду думать в этом направлении
S>Вообще есть подозрение, что модель переусложнена. В том смысле, что насколько мне известно, отели работают проще.
S>Идея в том, что у комнаты существует, грубо говоря, некоторое количество посадочных мест. И всё — размещайся, как хочешь.
S>А возраст детей влияет только на ценообразование. Причем аддитивно и рефлексивно, то есть если ребенок 11-13 — это +23 за ночь, то и второй тоже +23. А не так, что у каждой комбинации своя независимая цена.
S>Если копать в эту сторону, то всё будет намного проще. Просто ищешь все варианты трехместного размещения, а потом вычисляешь для них цену в зависимости от правил.


Ну, это грубо говоря На самом деле может быть все хитро На самом деле +23 может действовать при следующих ограничениях: максимум на одного ребенка, минимум при двух взрослых

То есть 1 ADL + 2 CHLD 11-13 это будет не ADL + 23 + 23, а 2 ADL + 23 Но это действительно влияет не на поиск, а на формирование цены

S>Но тебе виднее. Если не получается вынести сложность за пределы комнат, то можно упростить себе жизнь (и усложнить ее серверу), кодируя возможные варианты при помощи like-expressions.

S>То есть в принципе латинских букв достаточно для детальной классификации возрастов от 0 до 26, чего, в принципе, должно хватить.
S>А дальше записываешь комбинацию "1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12" как 'Z[H-M][A-G]', семью как 'ZIE', и делаешь
S>
S>select from combination where @family like ages
S>


Надо подумать

Я вот, что еще подумал У нас же категория детей — это набор каких-то возрастов. Можно будет тупо эти возрасты и записать.

То есть
1 ADL                 99;
1 ADL + 1 CHLD 0-6    99;0;1;2;3;4;5;6;
1 ADL + 2 CHLD 0-6    99;0;0;1;1;2;2;3;3;4;4;5;5;6;6;
1 ADL + 1 CHLD 0-6 + 1 CHLD 7-10  99;0;1;2;3;4;5;6;7;8;9;10;


и т.п. натравить на них full-text index и выбирать LIKE'ом Правда, боюсь это будет не совсем хорошо на, скажем, 10 миллионах записей


dmitriid.comGitHubLinkedIn
Re[5]: Поможите. Одна комната, много детей :)
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.10.08 09:14
Оценка: 12 (1)
Здравствуйте, Mamut, Вы писали:

M>Ну, это грубо говоря На самом деле может быть все хитро На самом деле +23 может действовать при следующих ограничениях: максимум на одного ребенка, минимум при двух взрослых

M>То есть 1 ADL + 2 CHLD 11-13 это будет не ADL + 23 + 23, а 2 ADL + 23 Но это действительно влияет не на поиск, а на формирование цены
Вот именно. Формирование цены уже можно себе позволить делать с маленьким объемом отфильтрованных записей, т.к. в запросе будет еще много ограничений.
К примеру, не имеет смысла считать цены для номеров в отелях, где нет свободных мест на запрошенные даты.

S>>Но тебе виднее. Если не получается вынести сложность за пределы комнат, то можно упростить себе жизнь


M>Надо подумать

Скорее надо поэкспериментировать

M>Я вот, что еще подумал У нас же категория детей — это набор каких-то возрастов. Можно будет тупо эти возрасты и записать.


M>и т.п. натравить на них full-text index и выбирать LIKE'ом

Это будет не намного лучше, чем решение с ручной реляционизацией. Потому, что ровно его и будет пытаться сделать FT-index: построить список слов (разрешенных возрастов), ссылающихся на вариант размещения. А с like всё сведется к тому же table/index scan, для которого единственная оптимизация — это сократить IO cost за счет тесной упаковки (вроде той, которую я предложил). В ней для описания комбинации размещения четырехместной комнаты достаточно 13 символов.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Поможите. Одна комната, много детей :)
От: Mamut Швеция http://dmitriid.com
Дата: 03.12.08 11:54
Оценка:
S>То есть в принципе латинских букв достаточно для детальной классификации возрастов от 0 до 26, чего, в принципе, должно хватить.
S>А дальше записываешь комбинацию "1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12" как 'Z[H-M][A-G]', семью как 'ZIE', и делаешь
S>
S>select from combination where @family like ages
S>


Да я тупой Но эту идею я так и не понял


dmitriid.comGitHubLinkedIn
Re[5]: Поможите. Одна комната, много детей :)
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.08 12:18
Оценка: 32 (1)
Здравствуйте, Mamut, Вы писали:

S>>То есть в принципе латинских букв достаточно для детальной классификации возрастов от 0 до 26, чего, в принципе, должно хватить.

S>>А дальше записываешь комбинацию "1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12" как 'Z[H-M][A-G]', семью как 'ZIE', и делаешь
S>>
S>>select from combination where @family like ages
S>>


M>Да я тупой Но эту идею я так и не понял

A = 1 year
B = 2 years
C = 3 years
...
Z = adult.

Требования к возрастам записываются всегда по убыванию. Как и возраста семьи. Это позволяет не рассматривать перестановки.
Далее, like в MSSQL умеет искать по диапазонам.
Поэтому строка 'Z[H-M][A-G]' матчит 'ZIE', а строка 'ZZ' — нет.
Обычно like делают в другую сторону: в таблице лежат строки, а в запросе передается выражение-константа.
Здесь наоборот.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Поможите. Одна комната, много детей :)
От: Mamut Швеция http://dmitriid.com
Дата: 03.12.08 12:54
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Mamut, Вы писали:


S>>>То есть в принципе латинских букв достаточно для детальной классификации возрастов от 0 до 26, чего, в принципе, должно хватить.

S>>>А дальше записываешь комбинацию "1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12" как 'Z[H-M][A-G]', семью как 'ZIE', и делаешь
S>>>
S>>>select from combination where @family like ages
S>>>


M>>Да я тупой Но эту идею я так и не понял

S>A = 1 year
S>B = 2 years
S>C = 3 years
S>...
S>Z = adult.

S>Требования к возрастам записываются всегда по убыванию. Как и возраста семьи. Это позволяет не рассматривать перестановки.

S>Далее, like в MSSQL умеет искать по диапазонам.
S>Поэтому строка 'Z[H-M][A-G]' матчит 'ZIE', а строка 'ZZ' — нет.

Хороший какой MSSQL, а у нас — MySQL поэтому будм тестить performance запроса с REGEXP (только тапками не бейте )

S>Обычно like делают в другую сторону: в таблице лежат строки, а в запросе передается выражение-константа.

S>Здесь наоборот.

Ага


dmitriid.comGitHubLinkedIn
Re[7]: Поможите. Одна комната, много детей :)
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.08 13:26
Оценка: 21 (2)
Здравствуйте, Mamut, Вы писали:
M>Хороший какой MSSQL, а у нас — MySQL поэтому будм тестить performance запроса с REGEXP (только тапками не бейте )
Не переживай. Основной тормоз, скорее всего, будет именно в table scan, а не в вычислении выражения.
Для сравнения гоняй на той же таблице такой же запрос, в котором предикат с like заменен на (IsNull(ID, ID) != ID). Это приведет к table scan, у которого вычисление предиката экстремально дешево.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Поможите. Одна комната, много детей :)
От: AlexVinS Россия  
Дата: 29.12.08 19:38
Оценка:
Здравствуйте, Mamut, Вы писали:
M>Меня сильно интересует вопрос, как это все максимально просто и эффективно хранить в базе данных (RDBMS, на всякие OO и Document-oriented не замахиваемся ), учитывая, что по этому всему еще и искать надо

Общий совет: вначале думай как хранить, то что будешь искать, а потом как хранить то, что будет приждойниваться к результатам поиска.
Я так понял, что самый трудоемкий поиск — поиск свободной комнаты на данное число человек, а потом уже к найденным результатам вычисляется цена и конкретный вариант проживания по данному отелю. Или всетаки "вариант проживания" — это свойство конкретной комнаты?


Умный человек знает не многое, но нужное
Re[2]: Поможите. Одна комната, много детей :)
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.12.08 11:17
Оценка: +1
Здравствуйте, AlexVinS, Вы писали:
AVS>Общий совет: вначале думай как хранить, то что будешь искать, а потом как хранить то, что будет приждойниваться к результатам поиска.
AVS>Я так понял, что самый трудоемкий поиск — поиск свободной комнаты на данное число человек, а потом уже к найденным результатам вычисляется цена и конкретный вариант проживания по данному отелю. Или всетаки "вариант проживания" — это свойство конкретной комнаты?
Скорее всего именно комнаты. Потому что там, грубо говоря, может стоять одна двуспальная кровать + одна детская тахта. + опционально можно запихать туда же еще и колыбельку.
И всё, ты уже туда двух мужиков, к примеру, не поселишь. Или маму с двумя детьми-подростками.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Поможите. Одна комната, много детей :)
От: sergmesh  
Дата: 30.12.08 16:47
Оценка:
Здравствуйте,

M>Таким образом, для комнаты могут быть такие комбинации проживания:

M>[code]
M>1 ADL, 2 ADL, 3 ADL

M>1 ADL + 1 CHLD 0-6 1 ADL + 1 CHLD 7-10 1 ADL + 1 CHLD 12-13

M>1 ADL + 2 CHLD 0-6 1 ADL + 2 CHLD 7-10 1 ADL + 2 CHLD 12-13

M>2 ADL + 1 CHLD 0-6 2 ADL + 1 CHLD 7-10 2 ADL + 1 CHLD 12-13

M>2 ADL + 2 CHLD 0-6 2 ADL + 2 CHLD 7-10 2 ADL + 2 CHLD 12-13

M>1 ADL + 1 CHLD 0-6 + 1 CHLD 7-10

M>1 ADL + 1 CHLD 0-6 + 1 CHLD 12-13
как вариант можно использовать такую структуру

create table hotel (
pkey number
, name varchar2(100)
);

create table room (
pkey number
, fkey_hotel number
);

create table who_can_live (
pkey number
, fkey_room number
, num number
, person_type varchar2(100)
, age_from number
, age_to number
);

то есть в who_can_live хранятся все варианты использования комнаты

потом строим запрос по запросу

select fkey_room
from who_can_live
where <src_age> < age_to
and <src_age> > age_from
and <adult/child> = person_type
and <num> = num
union
...

например

1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12

select fkey_room
from who_can_live
where 99 < age_to
and 16 > age_from
and 'adult' = person_type
and 1 = num
union
select fkey_room
from who_can_live
where 6 < age_to
and 0 > age_from
and 'child' = person_type
and 1 = num
union
select fkey_room
from who_can_live
where 12 < age_to
and 7 > age_from
and 'child' = person_type
and 1 = num

union дает пересечение множеств
и в результате получаем комнаты в которых есть все входные условия (состав семьи)
Re[2]: Поможите. Одна комната, много детей :)
От: Mamut Швеция http://dmitriid.com
Дата: 01.01.09 21:37
Оценка:
S>1 ADL + 1 CHLD 0-6 + 1 CHLD 7-12

S>select fkey_room

S> from who_can_live
S> where 99 < age_to
S> and 16 > age_from
S> and 'adult' = person_type
S> and 1 = num
S>union
S>select fkey_room
S> from who_can_live
S> where 6 < age_to
S> and 0 > age_from
S> and 'child' = person_type
S> and 1 = num
S>union
S>select fkey_room
S> from who_can_live
S> where 12 < age_to
S> and 7 > age_from
S> and 'child' = person_type
S> and 1 = num

S>union дает пересечение множеств

S>и в результате получаем комнаты в которых есть все входные условия (состав семьи)


У нас уже пробовалося похожий вариант Он довольно тормозной. В частности — из-за того, что такой запрос приходится составлять в коде, а не хранить в базе, например


dmitriid.comGitHubLinkedIn
Re[2]: Поможите. Одна комната, много детей :)
От: Mamut Швеция http://dmitriid.com
Дата: 01.01.09 21:39
Оценка:
AVS>Общий совет: вначале думай как хранить, то что будешь искать, а потом как хранить то, что будет приждойниваться к результатам поиска.
AVS>Я так понял, что самый трудоемкий поиск — поиск свободной комнаты на данное число человек, а потом уже к найденным результатам вычисляется цена и конкретный вариант проживания по данному отелю.

Хочется сразу вычислить все цены, потому то так будет проще. Вопрос — собственно в хранении всех этих цен


dmitriid.comGitHubLinkedIn
Re[3]: Долго удаляются записи иэ таблиц FireBird
От: AlexVinS Россия  
Дата: 01.01.09 22:11
Оценка:
Здравствуйте, Sinclair, Вы писали:

AVS>>Или всетаки "вариант проживания" — это свойство конкретной комнаты?

S>Скорее всего именно комнаты. Потому что там, грубо говоря, может стоять одна двуспальная кровать + одна детская тахта. + опционально можно запихать туда же еще и колыбельку.
S>И всё, ты уже туда двух мужиков, к примеру, не поселишь. Или маму с двумя детьми-подростками.

Тогда такая мысль: (допустим что максимальное коичество постояльцев в комнате=3) в таблице комнат добавить 3 поля показывающие максимальный возраст каждого гостя (правда пока не понятно как быть с двухспальными кроватями)


Умный человек знает не многое, но нужное
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.