@Override
  public Result<T, K> createSearchResult(SearchImpl<T, K> searchRequest) {
    String queryString = buildQueryString(searchRequest.query());
    SortOptions.Builder sortOptions = buildSortOptions(searchRequest.order());

    QueryOptions.Builder queryOptions = QueryOptions.newBuilder();
    Integer limit = searchRequest.limit();
    int offset = 0;
    if (limit != null) {
      offset = searchRequest.offset() == null ? 0 : searchRequest.offset();
      int effectiveLimit = limit + offset;
      if (effectiveLimit > 1000) {
        Logger.warn(
            "Currently the Google Search API does not support queries with a limit over 1000. With an offset of %d and a limit of %d, you have an effective limit of %d",
            offset, limit, effectiveLimit);
      }
      limit = effectiveLimit;
      /* Note, this can't be more than 1000 (Crashes) */
      queryOptions = queryOptions.setLimit(limit);
    }
    if (searchRequest.accuracy() != null) {
      queryOptions.setNumberFoundAccuracy(searchRequest.accuracy());
    }
    queryOptions.setSortOptions(sortOptions);
    Query query = Query.newBuilder().setOptions(queryOptions).build(queryString);
    Future<Results<ScoredDocument>> searchAsync = getIndex().searchAsync(query);
    return new ResultImpl<T, K>(this, searchAsync, searchRequest.offset());
  }
  // Search for nearby places
  @Override
  public CursorPage<DProduct, String> searchForNearby(
      int pageSize,
      String cursor,
      Float latitude,
      Float longitude,
      int radius,
      RnrService.SortOrder sortOrder) {

    // Build the query string
    String queryString =
        String.format("distance(location, geopoint(%f, %f)) < %d", latitude, longitude, radius);

    // Sort expression
    SortExpression sortExpression = null;
    switch (sortOrder) {
      case DISTANCE:
        String sortString =
            String.format("distance(location, geopoint(%f, %f))", latitude, longitude);
        sortExpression =
            SortExpression.newBuilder()
                .setExpression(sortString)
                .setDirection(SortExpression.SortDirection.ASCENDING)
                .setDefaultValueNumeric(radius + 1)
                .build();
        break;
      case TOP_RATED:
        sortExpression =
            SortExpression.newBuilder()
                .setExpression("averageRating")
                .setDirection(SortExpression.SortDirection.DESCENDING)
                .setDefaultValue("")
                .build();
        break;
      case MOST_LIKED:
        sortExpression =
            SortExpression.newBuilder()
                .setExpression("likeCount")
                .setDirection(SortExpression.SortDirection.DESCENDING)
                .setDefaultValue("")
                .build();
        break;
      case MOST_THUMBS_UP:
        sortExpression =
            SortExpression.newBuilder()
                .setExpression("thumbsUp")
                .setDirection(SortExpression.SortDirection.DESCENDING)
                .setDefaultValue("")
                .build();
        break;
    }

    // Options
    QueryOptions options = null;
    QueryOptions.Builder builder =
        QueryOptions.newBuilder()
            .setSortOptions(SortOptions.newBuilder().addSortExpression(sortExpression))
            .setLimit(pageSize);

    if (null != cursor)
      builder.setCursor(com.google.appengine.api.search.Cursor.newBuilder().build(cursor));

    // Build query
    com.google.appengine.api.search.Query query =
        com.google.appengine.api.search.Query.newBuilder().setOptions(options).build(queryString);

    return searchInIndexWithQuery(query, getLocationIndex());
  }