IN Query Google App Engine Datastore Java With Preference of Sorting Based on Number of matching keywords in list

StackOverflow https://stackoverflow.com/questions/22859380

Question

We have the tags in the datastore in kind as column and it has list of tag words and we want to filter the datastore matching or case and sort it based on the number of matching keywords

How can we do this in app engine query platform Java, Please help us if you have any idea.

Please find the model

Consider model

public class Car {

  String id;  

  String name;

  String model;

  String manufacture;

  int year;

  List<String> tags;

}  

same thing for DB structure too,

List<String> searchKeyword =  Arrays.asList(q.split(","));

Query query = new Query("Car");
query.setFilter(new FilterPredicate("tags",FilterOperation.IN,searchKeyword);
List<Entity> entities = ds.prepare(query).asList(withLimit(10));

In this case for example, q = royal,coupe

result should match both the keywords show come in the top and in one keyword should be followed.

Caterham 7 - one keyword Nissan 370Z - match two keyword

output Nissan 370z Caterham 7

Same thing for news belongs to the cars model also has tags and search should work there also same way

News will have title,description,tags,images,video

Thanks Krishnan

Was it helpful?

Solution

There is no way to do this natively in the datastore. The way IN works in the Datastore is that it issues one query for each item in your list, then provides the union of the results (really it is using disjunctive normal form (App Engine source code)).

Instead, you could issues the queries yourself to guarantee the order you want (first query for results that match N tags using an AND filter, then N-1, then N-2, ...).

For two tags, this would look like:

List<String> searchKeyword = Arrays.asList(q.split(","));

Query query = new Query("Car");
query.setFilter(CompositeFilter.and(Arrays.asList(
    new FilterPredicate("tags", FilterOperation.EQUAL, searchKeyword.get(0)),
    new FilterPredicate("tags", FilterOperation.EQUAL, searchKeyword.get(1)))));

List<Entity> entities = ds.prepare(query).asList(withLimit(10));

query.setFilter(CompositeFilter.or(Arrays.asList(
    new FilterPredicate("tags", FilterOperation.EQUAL, searchKeyword.get(0)),
    new FilterPredicate("tags", FilterOperation.EQUAL, searchKeyword.get(1)))));
entities.addAll(ds.prepare(query).asList(withLimit(10));

Obviously, this will only work for two tags, but can be generalized for more than that. You should probably also use the async API so that you can issue all the queries in parallel.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top