Database Design in GAE / J: Relational Modeling versus Attribute Cost

Imagine that you plan to create a social network running on GAE / Java , where each user has a set of properties (i.e. age, current city, interests).

Alternative 1 : classic approach - user_id and each property as a "string"

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

Alternative 2 : Object-Attribute-Value (EAV)

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

What pros / cons do you think each option has? My main concerns:

  • Which affects multicriteria searches (for example, “give me users under the age of 45 who live in New York and like books”).
  • What consequences can the effects of GAE / J have? (i.e. indexes, data store size)
  • (, "" ), ", "?

, , , , , .

.

+5
2

, App Engine Google I/O 2009? , . .

+2

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());
}

.

+1

All Articles