Search for substring within an entity using objectify
Asked Answered
A

4

10

I have an entity called lastName with value "Benjamin". Is there a way in objectify that if the user put "Ben" or "jam" or "Benja". I still be able to find this entity using query.filter(). I must use the query as there are other search criteria iam checking.

I saw something in "Obgaektify" called "starts with" operator. but it isnot working. Any suggestions would be appreciated. Thanks

Almsgiver answered 10/8, 2011 at 16:52 Comment(4)
Why would you want to do a substring search within names? I've never seen a good use-case for this.Mestee
It isnot within names actully. It is within text search in general. but for simplicity i just said name :)Almsgiver
Well, the question remained. Fulltext search does stemming and normalization, then searches on whole words, because there's very little point in having a query for 'cat' return 'defecate'.Mestee
Well right now the requirements changed, I only need to check if it starts with the given text. like "benjamin" starts with "ben" not "jam" or anything else. So i will try the solution posted below and see the results. Thanks for your helpAlmsgiver
C
12

There's no "LIKE" type queries for sub-string, however a case sensitive "starts with" could be simulated by taking advantage of the > and < operators on indexes.

// The start string
String searchStr = "Ben";

// emulate a "starts with" query
Query q = new Query("MyEntity")
q.addFilter("name", Query.FilterOperator.GREATER_THAN_OR_EQUAL, searchStr);
q.addFilter("name", Query.FilterOperator.LESS_THAN, searchStr + "\ufffd");

The query will 'search' the name property for items that begining with "Ben", and are less than "Ben\ufffd", where \ufffd is the highest possible unicode character.

Crescentic answered 10/8, 2011 at 18:22 Comment(2)
`u'\ufffd' is the canonical 'largest UTF character' to use here.Mestee
Cool Shady, accept the answer by ticking the green tick, this gives you 2rep, rep to the answer owner and indicates to others that the question is resolved.Crescentic
P
2

There is no standard existing index for contains-like queries. Btw, you can always introduce your own. At this case you can do:

  1. add and synthetic field like String[] lastNameIndex
  2. add method marked as @PrePersist that will fill lastNameIndex field with all available combinations
  3. When you want to find entities using this index do query.filter('lastNameIndex =', val)
Penetration answered 10/8, 2011 at 18:17 Comment(0)
W
0

Putting the answer from Chris and the comment from Nick together, here is the code to build a query filter for objectify V4:

public <T> Query<T> fieldStartsWith(Query<T> query, String field, String search){
    query = query.filter(field + " >=", search);
    return query.filter(field + " <", searchStr+"\ufffd");
}
Wag answered 23/2, 2013 at 8:43 Comment(2)
I believe it should be < "\ufffd" and not <= because FFFD is not a printable ascii character so you would want to exclude it. In practice it probably won't matter, though. Correct me if I'm wrong.Bureaucratize
Thanks Oliver, you are right. I modified my answer!Wag
Y
0

I have used the tokenization method. Here is the code in Java:

private String tokenize(String phrase) {
StringBuilder tokens = new StringBuilder();
try {
  for (String word : phrase.split(" ")) {
    if (word.length() < 1) {
      continue;
    }
    int j = 1;
    while (true) {
      for (int i = 0; i < word.length() - j + 1; i++) {
        tokens.append(word.substring(i, i + j)).append(" ");
      }
      if (j == word.length()) {
        break;
      }
      j++;
    }
  }
} catch (Throwable t) {
  t.printStackTrace();
}
return tokens.toString();}

This allows to define an indexable field, then process standard Ofy queries and SearchService.

Yacketyyak answered 27/10, 2015 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.