Проектирование базы данных в GAE / J: реляционное моделирование против значения атрибута объекта - PullRequest
5 голосов
/ 19 декабря 2010

Представьте, что вы планируете создать социальную сеть , работающую на GAE / Java , где у каждого пользователя есть набор свойств (т. Е. Возраст, текущий город, интересы).

Альтернатива 1 : классический подход - user_id и каждое свойство в виде «строки»

entity  property_1 property_2 property_3
------  ---------- ---------- -----------------
bob     missing    NY         [football, books]
tom     34         missing    [books, horses]

Альтернатива 2 : значение сущности-атрибута (EAV)

entity   attribute   value
------   ---------   -----
bob      town        NY
bob      interests   [football, books]
tom      age         34
tom      interests   [books, horses]

Какие плюсы / минусы, на ваш взгляд, есть у каждого варианта? Мои основные проблемы:

  1. Каково влияние на поиск по нескольким критериям (т. Е. "дайте мне пользователей в возрасте до 45 лет, которые живут в Нью-Йорке и любят книги" )
  2. Какие последствия для GAE / J это может иметь? (т.е. индексы, размер хранилища данных ...)
  3. Как смоделировать атрибуты с несколькими значениями (например, "интересы"), если вы хотите получить "пользователей, которым нравятся книги" ?

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

Спасибо.

Ответы [ 2 ]

2 голосов
/ 21 декабря 2010

Вы смотрели на Создание масштабируемых сложных приложений на App Engine из Google I / O 2009?Видео имеет ужасное качество звука, но оно охватывает ваши темы.Он говорит о свойствах списков, объединениях и их ограничениях.

1 голос
/ 21 декабря 2010

Если гибкость EAV важна для вашего приложения, используйте его, в противном случае не используйте его, так как у него будут подводные камни при запросах.

Вернет все сущности, у которых есть книги по интересам:

final Iterator<EAV> eavs = Iterators.transform(
    datastoreService.prepare(
        new Query(EAV.class.getSimpleName()).addFilter("a",
            FilterOperator.EQUAL, "interests").addFilter(
            "v", FilterOperator.EQUAL, "books"))
        .asIterator(), new Function<Entity, EAV>() {
      @Override
      public EAV apply(final Entity input) {
        return new EAV(input);
      }
    });
while (eavs.hasNext()) {
  logger.debug("eav: " + eavs.next());
}

Попытка выбрать сущности, у которых есть книги по интересам и в возрасте до 45 лет, но ничего не получится, поскольку ни в одной строке не будет двух значений a и v:

final Iterator<EAV> eavs = Iterators.transform(
    datastoreService.prepare(
        new Query(EAV.class.getSimpleName()).addFilter("a",
            FilterOperator.EQUAL, "interests").addFilter(
            "v", FilterOperator.EQUAL, "books").addFilter("a",
            FilterOperator.EQUAL, "age").addFilter(
            "v", FilterOperator.LESS_THAN, 45))
        .asIterator(), new Function<Entity, EAV>() {
      @Override
      public EAV apply(final Entity input) {
        return new EAV(input);
      }
    });
while (eavs.hasNext()) {
  logger.debug("eav: " + eavs.next());
}

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

OTOH с «классическим подходом» - это тривиально:

final Iterator<Person> persons = Iterators.transform(
    datastoreService
        .prepare(
            new Query(Person.class.getSimpleName())
                .addFilter("interests",
                    FilterOperator.EQUAL, "books")
                .addFilter("age",
                    FilterOperator.NOT_EQUAL, null)
                .addFilter("age",
                    FilterOperator.LESS_THAN, 45))
        .asIterator(), new Function<Entity, Person>() {
      @Override
      public Person apply(final Entity input) {
        return new Person(input);
      }
    });
while (persons.hasNext()) {
  logger.debug("person: " + persons.next());
}

Это выведет данные Тома.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...