2010-06-26 3 views
5

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

Этот вопрос связан с предыдущим вопросом, что я в курсе, но я воспроизведен соответствующей информацию ниже: Database design - google app engine

В этом приложении есть понятия «назначения» и «Line Items. "

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

Объекты - это сервис, плата или сопутствующая информация. Пример позиций, которые могли бы пойти на прием:

 
Name:       Price: Commission: Time estimate 
Full Detail, Regular Size:  160  75  3.5 hours 
$10 Off Full Detail Coupon:  -10  0   0 hours 
Premium Detail:     220  110  4.5 hours 
Derived totals(not a line item): $370  $185  8.0 hours 

В моей предыдущей реализации этого приложения, Line Items содержатся одним назначением. Это работало отлично в большинстве случаев, но иногда вызывало проблемы. Примером может служить случай, когда назначение прерывается на полпути из-за дождя, и технический специалист должен был вернуться на следующий день и закончить. Для этой ситуации требуется две встречи для одной и той же позиции. В таких случаях я просто немного подтолкнул данные, установив «позицию» на второй встрече, чтобы прочитать что-то вроде «Finish Up», а затем стоимость будет равна $ 0.

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

Appointment 
start_time 
etc... 

Line_Item 
appointment_Key_List 
name 
price 
etc... 

Общая проблема с этой структурой состоит в том, что сложно и я даже не уверен, соответствует ли она одной позиции с несколькими встречами. Если Линейные позиции могут быть только частью одного Назначения, тогда я могу на самом деле просто разместить список позиций в каждом Назначении, когда я получаю «Назначения», я уже получаю Линейные позиции.

Более конкретная проблема заключается в том, что я использую механизм Google для работы с Google, и если я хочу запросить набор встреч и связанных с ними позиций, мне придется сначала запросить набор встреч, а затем сделать второй запрос для позиций с использованием оператора IN для проверки того, попадает ли какой-либо из ключей назначения Line_Item в набор ключей назначения, которые были возвращены из предыдущего запроса. Второй запрос не удастся, если у меня есть более 30 ключей, требующих, чтобы я очертил запрос. Я мог бы денормализовать данные, чтобы избежать этого сложного и расширенного запроса на чтение, и мне, вероятно, придется в какой-то степени денормализовать, но я предпочел бы избежать сложности, когда это необходимо.

Мой вопрос: как этот тип ситуации обычно моделируется? Является ли даже целесообразным, чтобы позиция позиции была сопряжена с несколькими встречами, или это нормально, чтобы просто разделить позиции на отдельные для каждой встречи, такие как «1-я половина двухдневного задания» и «2-я половина двухдневного задания» «. Как делают подобные успешные приложения? Каковы эмпирические правила этого типа ситуации? Какие реализации оказались менее проблематичными?

Спасибо!

ответ

2

Подход, который вы предлагаете, будет работать нормально; вы можете смоделировать позицию «назначение_Key_list» позиции в качестве свойства списка, и она будет работать так, как вы ожидаете. Вам не нужно использовать оператор IN - это для сопоставления одного значения в хранилище данных со списком ключей, которые у вас есть (например, «WHERE datastore_column IN (« a »,« b »,« c »)), тогда как вы делаете обратное - сопоставление одного значения со списком в хранилище данных.

Я бы предположил, что обратное может быть лучше подходит для вашей задачи: пусть каждое назначение имеет список ключей позиции. Это работает точно так же, но для получения всех данных о встрече вы вместо этого сначала получаете назначение, затем делаете массовый доступ к позициям, используя ключи от объекта Назначения. Если вам известен ключ Назначения , вы избегаете необходимости делать какие-либо запросы вообще.

Я пытался объяснить Pindatjuh, почему запрос свойства списка не менее эффективен, чем однозначный, но, как ни странно, требуется более подробное описание, поэтому без каких-либо дополнительных атак здесь ...

краткий учебник по App Engine Datastore индексации

Хотя Python и Java предоставляют различные интерфейсы высокого уровня в хранилище данных, сам хранилищу говорит на нижний уровень абстракции, который называется сущностями. Объект состоит из следующих действий:

  1. Уникальный первичный ключ
  2. список (имя, значение) пар

Первичный ключ является ключом Datastore вы уже знакомы. Список пар (имя, значение) представляет собой представление App Engine для данных в вашей организации. До сих пор так просто. Субъект со следующими значениями:

a_string = "Hello, world" 
an_int = 123 

бы сериализованная к чему-то, напоминающее это:

[('a_string', 'Hello, world'), ('an_int', 123)] 

Но как это взаимодействует со списками? Ну, списки рассматриваются как «многозначные» свойства. То есть список с n элементами сохраняется как n отдельных свойств. Пример, вероятно, делает это более ясным:

a_string = "Hello, world" 
an_int = 123 
a_list_of_ints = [42, 314, 9] 

будет сериализовать:

[('a_string', 'Hello, world'), ('an_int', 123), ('a_list_of_ints', 42), ('a_list_of_ints', 314), ('a_list_of_ints', 9)] 

Как вы можете видеть, список получает представлен ряд значений, все с тем же именем. Когда вы загружаете данные из хранилища данных, SDK видит повторяющееся значение и превращает его в список.

Где это важно, когда он взаимодействует с индексированием. Предположим, у вас есть указатель на 'a_string' и 'an_int'. Когда вы вставляете или изменяете значение, App Engine создает для него набор записей индекса; для приведенного выше индекса и выше сущности, она генерирует одну строку в индексе, который выглядит примерно так:

('Hello, world', 123, a_key) 

(«a_key» здесь является заполнителем для ключа исходного объекта.) Когда вы делаете запрос, который использует этот индекс, просто нужно выполнить поиск по индексу, чтобы найти строки с соответствующим префиксом (например, «SELECT * FROM Kind WHERE a_string =« Hello, world »ORDER BY an_int»).

При индексировании списка App Engine вставляет несколько строк индекса. Индекс «an_int» и «a_list_of_ints» будет генерировать эти строки для указанной организации:

(123, 42, a_key) 
(123, 314, a_key) 
(123, 9, a_key) 

Опять же, выполнение запроса работает так же, как это было ранее - App Engine просто должен искать строку с правильным префиксом в индексе. Количество записей в списке не влияет на скорость выполнения запроса - только на сколько времени потребовалось для создания и записи записей индекса. Фактически, планировщик запросов не знает, что «a_list_of_ints» является многозначным свойством - он просто рассматривает его как любую другую запись индекса.

Таким образом, в двух словах:

  1. Там нет практической разницы между списком с одним элементом в нем и индивидуальной собственности, в индексации и запрашивающие термины
  2. Размер индексируемой списка влияет на время и пространство, необходимое для индексирования, но не для запросов.
  3. Вы можете выполнить запрос, соответствующий любому объекту с заданным значением в списке, используя простой фильтр равенства.
+0

Очень информативный ответ! Спасибо, что разделили эту информацию с SO. @DutrowLLC, пожалуйста, отметьте этот ответ как правильный, как есть, на мой взгляд, гораздо лучший ответ на ваш вопрос. @Nick Johnson Приносим извинения за то, что вы верите в неправильные вещи. Спасибо за объяснение и предоставление этого очень приятного ответа с отличной информацией для всех! – Pindatjuh

+0

@Pindatjuh - Его много, чтобы заглянуть. В этом видео также подробно рассказывается о том, как индексируются и просматриваются списки. Я нашел вторую половину при объединении-join чрезвычайно полезной. Это был pdf-файл с слайдами, на который вы можете смотреть во время просмотра видео: http://code.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html –

+0

Спасибо, что нашли время, чтобы ответить на этот вопрос так тщательно , Я надеюсь, что другие люди также смогут найти ваш ответ и воспользоваться им. –

1

Обычное решение для таких проблем - это нормализация модели, то есть к First Normal Form.

Ваша модель, в нормализованной форме, будет иметь третью таблицу, со ссылками на Appointment и Line_Item строк:

Appointment 
start_time 
... 

Line_Item 
name 
price 
... 

Appointment_Line_Item 
appointment_key 
line_item_key 

Существует проблема, однако! Поскольку вы используете Google App Engine, а их хранилище данных довольно ограничено ("GQL cannot perform an SQL-like JOIN") и в основном требует денормализации.

Вы предложили использовать поле, подобное списку. Это возможность использовать это, но его очень сложно индексировать. Поиск ключа (appointment_key) в списке на строку в базе данных на самом деле не выполняется. Я предлагаю две возможности:

  1. Duplicate Line_Item.

    Line_Item 
    appointment_key 
    name 
    price 
    finished 
    ... 
    

    А Line_Item должен иметь finished состояния, когда этот пункт был закончен или не работник. Если работник не закончил все позиции, отметьте их как незавершенные, создайте новую встречу и скопируйте все незавершенные предметы. Вы можете указать на поле appointment_key на всех Line_Items, что является хорошей вещью. Однако могут возникнуть проблемы с дублируемыми данными .

  2. Динамические поля для Line_Item:

    Line_Item 
    duplicate_key 
    appointment_key 
    name 
    price 
    finished 
    ... 
    

    Создать новое поле, duplicate_key для Line_Item, который указывает на другой Line_Item или обнулить (Оставляем этот ключ!). Null означает, что Line_Item является оригинальным, любое другое значение означает, что этот Line_Item является дубликатом полей, на которые указывает поле. Все поля Line_Item, помеченные как дубликаты, наследуют поля оригинала Line_Item, за исключением appointment_key: так что это займет меньше места. Также это решение должно содержать индекс appointment_key, чтобы ускорить время поиска. Для этого требуется один дополнительный запрос для дублированного Line_Item, что может быть проблемой.

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

+0

Благодарим за отзыв. Я никогда не думал о дублирующем ключевом подходе, это действительно интересное решение. Одна вещь, которую следует учитывать при использовании движка приложения, заключается в том, что они делают индексные списки и позволяют вам искать их. Они называют это «объединение слиянием» и, как представляется, расширяют свои возможности за пределами простого хранилища ключей: http://code.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html –

+1

«Поиск ключ (destination_key) в списке на строку в базе данных не выполняется. " - не правда. Вы можете фильтровать свойства списка в App Engine так же эффективно, как и для не-списков. –

+0

@ Ник Джонсон - Спасибо за то, что он с этим согласен. Я думаю, что это ключевой игровой чейнджер с движком приложения, который является неожиданным и не очень известным. –

Смежные вопросы