1

I am storing an entity using Objectify and would now like to add an index to one of the properties in order to run a query.

The entity arrives from an iOS client that is connected via Google Cloud Endpoints. It sets the property in the Objective-C class that was generated by ServiceGenerator.

So what I have tried is adding an @Index annotation to the property in Eclipse and uploading the project again with appcfg. However, when I inspect the datastore in Google Developers Console is still says "No indexes serving" and if I create new entities and run Objectify queries on the (now indexed) property is still get zero items back.

So what exact steps do I have to go through in order to add an index to an existing property for an existing entity that is defined with Objectify annotations in an Eclipse project?

This Q&A suggests it should be straightforward, but for some reason it is (apparently) not. Perhaps the complication arises from the involvement of Google Cloud Endpoints and an Objective-C client.

Update Here are some relevant code snippets, as requested:

The property is defined as follows:

@Entity
@Cache
public class SomeEntity {
    @Id public String someID;
    @Index String someProperty
}

The iOS client sets the the property as follows (relying on Objective-C classes produced by ServiceGenerator):

someEntity.someProperty = @"someString";

The server receives and saves the entity as follows:

@ApiMethod
public AddEntityResponse addEntity(AddEntityRequest request, HttpServletRequest httpServletRequest) throws ServletException {
    SomeEntity someEntity = request.someEntity;
    someEntity.someID = UUID.randomUUID().toString();
    ofy().save().entity(someEntity).now();
    // ...
}

When the server runs the following query it receives zero items back, although an entity with the given property value exists (is e.g. visible in the datastore viewer):

ofy().load().type(SomeEntity.class).filter("someProperty", "someString").list();
Community
  • 1
  • 1
Drux
  • 11,992
  • 13
  • 66
  • 116

4 Answers4

2

In order to add indexes to existing entities you have to perform these simple steps:

  1. Annotate your properties with @Index
  2. Save the existing entity

The reason for point 2 is because annotating your entity is not enough by itself because in the DataStore your data are unaffected. You have to explicitly re-save the existing entity to force the Datastore to create the index(es) for newly annotated properties.

The same applies to when removing indexes. You must re-save for changes to take effect.

Edit

From your code snippet I can see that your query is not quite right. You are invoking the query method on the object returned by type(...) which implements LoadType interface but neither of the two interfaces extended by [LoadType][1] (namely LoadIds and Query define that method! I assume you haven't created your own wrapper as your code looks like standard objectify, so I'm not sure how your code is compiling or not blowing up at runtime.

Anyway to fix, since it looks like what you want to do is filter by specified predicate, change your query to look:

ofy().load().type(SomeEntity.class).filter("someProperty", "someString").list();
elcid
  • 574
  • 4
  • 10
  • 1. and 2. are understood but I'm still not able to perform the query (nor see any indices in the console's datastore viewer). – Drux Aug 18 '14 at 15:33
  • In theory things should be working now. Can you post some code? Maybe there is something else to it – elcid Aug 18 '14 at 16:02
  • Re `query` vs. `filter`: that was a typo in my question (fixed now). Thx for noticing. – Drux Aug 20 '14 at 09:47
1

Yes, I think it is should be straight-forward - you just add the @Index annotation to the appropriate attribute of your entity. Remember that this won't affect existing entities, or the kind in general - just new entities written with this updated class.

For verifying, I suggest you look at the datastore viewer in the new cloud console. It provides more information and allows you to see index info for individual entities. Make sure to inspect your newly created entities there.

Tom
  • 17,103
  • 8
  • 67
  • 75
1

When I add a seemingly redundant assignment to the newly indexed property to the code that runs on the server I can make progress and receive the expected results from queries.

@ApiMethod
public AddEntityResponse addEntity(AddEntityRequest request, HttpServletRequest httpServletRequest) throws ServletException {
    SomeEntity someEntity = request.someEntity;
    someEntity.someID       = UUID.randomUUID().toString();
    someEntity.someProperty = someEntity.someProperty;
    ofy().save().entity(someEntity).now();
    // ...
}

After storing one new entity, I see this entity in Google Developers Console's Cloud Datastore Query (section) and I receive it from the query that applies a filter for someProperty. (For some reason the Google Developer Console's Cloud Datastore Indexes section still says "No indexes serving").

So my conclusion is that assignments to @Indexed properties only have actual effects on indices (and hence queries) if they are carried out directly with Objectify on the server (not indirectly on iOS clients and then passed to the server with Google Cloud Endpoints).

Drux
  • 11,992
  • 13
  • 66
  • 116
  • It sounds like what you're saying is "cloud endpoints is not reconstituting your SomeEntity object correctly". Objectify is not involved; it just saves whatever you give it. FWIW, "No indexes serving" is telling you that there are no multi-property indexes, which GAE manages separately from single-property indexes. – stickfigure Aug 21 '14 at 05:14
  • @stickfigure Thx for clarifying "no indexes serving". – Drux Aug 21 '14 at 07:40
0

I am unsure how this correlates to indexes, but I know modifying your model can be problematic if there is already data in that specific model. I've had issues adding properties or switching default values on some

I don't know how relevant it could be in your case, but could you "copy" your model with the new indexes and then migrate data to your new model, which should have that index properly built?

(p.s: yes I'm aware I'm asking you to "turn it off and on again" ;) )

Patrice
  • 4,641
  • 9
  • 33
  • 43
  • After annotating the property with `@Index` I even empty the model and populate it with new entities. Still there does not seem to be any index on the newly annotated property judging from query return values. – Drux Aug 19 '14 at 12:47
  • wow that IS weird.... you see the index in your admin console or not even? because if you see the index and it still returns nothing, the problem is in your query. If you don't see the index at all.... yeah there is definitely a problem – Patrice Aug 19 '14 at 13:07
  • I enter Google Developers Console, then go to Storage | Cloud Storage | Indexes: it says "No indexes serving". Under Storage | Cloud Storage | Query it reports approx. half a dozen entities that were added after annotating one property with `@Index`. – Drux Aug 19 '14 at 16:41
  • ok, so your index IS empty. Or you would see it in the storage/cloudstorage..... there is something that, for some reason, doesn't create the index – Patrice Aug 19 '14 at 16:51
  • Yep. In the [Datastore](https://developers.google.com/appengine/docs/java/datastore/indexes) documentation I see that at some level there is a difference between `setProperty()` and `setUnindexedProperty()`. I'm wondering whether the Objective-C code "perhaps"/"somehow" sets the property as unindexed when it should not. But it's only a theory for now ... – Drux Aug 19 '14 at 17:56