Я тут все с туризмом вожусь. Чувствую, что уже задавал этот вопрос, н онайти не могу
Задача:
У нас в отеле есть комната. В этой комнате могут проживать взрослые (ADL), а с ними — дети (CHLD) разных категорий. Категории детей типа 0-6 лет, 7-10 лет, 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 *
*в третьем отеле просто дети огрничиваются пятлетним возрастом
Я пока в грусти и раздумье. Когда категорий детей было ровно две, все было хорошо. А сейчас... Я не говорю уже про генерацию цен...
Здравствуйте, 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
Тогда каждую разрешенную комбинацию можно однозначно представить в виде строки, отсортировав категории по алфавиту:
Ну и точно так же представить и семью. Например, твой взрослый с двумя детьми порождает цепочку ACD.
В таком случае можно было бы выполнить поиск на точное совпадение строки, а он работает blazingly fast.
Как залудить строковый поиск в случае переменного количества диапазонов возрастов я пока не придумал .
В принципе, есть хомячковый способ — унифицировать классификацию, а для тех отелей, где мало категорий, вводить "лишние комбинации". Типа если отель разбирается только на уровне "ребенок/взрослый", и есть всего три цены — 1ADL, 2ADL, 1ADL+Child, то генерировать все комбинации 1ADL+0..6, 1ADL+7..10, 1ADL+11..13.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>1. Реляционизировать представление "возможные варианты проживания в комнате". S>Примерно так: S>Потом будет болезненно много joinов, експоненциальный взрыв количества записей во временных таблицах и унылая борьба с попыткой двух взрослых занять одну и ту же кровать.
Ага, у нас так сейчас и есть на 2-х категориях детей. Запросы еще те
S>2. Воспользоваться возможностями строкового поиска.
Здравствуйте, 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>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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>
Надо подумать
Я вот, что еще подумал У нас же категория детей — это набор каких-то возрастов. Можно будет тупо эти возрасты и записать.
Здравствуйте, 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>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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>
Здравствуйте, 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>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, 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>Здесь наоборот.
Здравствуйте, Mamut, Вы писали: M>Хороший какой MSSQL, а у нас — MySQL поэтому будм тестить performance запроса с REGEXP (только тапками не бейте )
Не переживай. Основной тормоз, скорее всего, будет именно в table scan, а не в вычислении выражения.
Для сравнения гоняй на той же таблице такой же запрос, в котором предикат с like заменен на (IsNull(ID, ID) != ID). Это приведет к table scan, у которого вычисление предиката экстремально дешево.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Mamut, Вы писали: M>Меня сильно интересует вопрос, как это все максимально просто и эффективно хранить в базе данных (RDBMS, на всякие OO и Document-oriented не замахиваемся ), учитывая, что по этому всему еще и искать надо
Общий совет: вначале думай как хранить, то что будешь искать, а потом как хранить то, что будет приждойниваться к результатам поиска.
Я так понял, что самый трудоемкий поиск — поиск свободной комнаты на данное число человек, а потом уже к найденным результатам вычисляется цена и конкретный вариант проживания по данному отелю. Или всетаки "вариант проживания" — это свойство конкретной комнаты?
Здравствуйте, AlexVinS, Вы писали: AVS>Общий совет: вначале думай как хранить, то что будешь искать, а потом как хранить то, что будет приждойниваться к результатам поиска. AVS>Я так понял, что самый трудоемкий поиск — поиск свободной комнаты на данное число человек, а потом уже к найденным результатам вычисляется цена и конкретный вариант проживания по данному отелю. Или всетаки "вариант проживания" — это свойство конкретной комнаты?
Скорее всего именно комнаты. Потому что там, грубо говоря, может стоять одна двуспальная кровать + одна детская тахта. + опционально можно запихать туда же еще и колыбельку.
И всё, ты уже туда двух мужиков, к примеру, не поселишь. Или маму с двумя детьми-подростками.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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 дает пересечение множеств
и в результате получаем комнаты в которых есть все входные условия (состав семьи)
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>и в результате получаем комнаты в которых есть все входные условия (состав семьи)
У нас уже пробовалося похожий вариант Он довольно тормозной. В частности — из-за того, что такой запрос приходится составлять в коде, а не хранить в базе, например
AVS>Общий совет: вначале думай как хранить, то что будешь искать, а потом как хранить то, что будет приждойниваться к результатам поиска. AVS>Я так понял, что самый трудоемкий поиск — поиск свободной комнаты на данное число человек, а потом уже к найденным результатам вычисляется цена и конкретный вариант проживания по данному отелю.
Хочется сразу вычислить все цены, потому то так будет проще. Вопрос — собственно в хранении всех этих цен
Здравствуйте, Sinclair, Вы писали:
AVS>>Или всетаки "вариант проживания" — это свойство конкретной комнаты? S>Скорее всего именно комнаты. Потому что там, грубо говоря, может стоять одна двуспальная кровать + одна детская тахта. + опционально можно запихать туда же еще и колыбельку. S>И всё, ты уже туда двух мужиков, к примеру, не поселишь. Или маму с двумя детьми-подростками.
Тогда такая мысль: (допустим что максимальное коичество постояльцев в комнате=3) в таблице комнат добавить 3 поля показывающие максимальный возраст каждого гостя (правда пока не понятно как быть с двухспальными кроватями)