@Override
 public int hashCode() {
   int result = index.hashCode();
   result = 31 * result + (type != null ? type.hashCode() : 0);
   result = 31 * result + id.hashCode();
   result = 31 * result + (routing != null ? routing.hashCode() : 0);
   result = 31 * result + (fields != null ? Arrays.hashCode(fields) : 0);
   result = 31 * result + (int) (version ^ (version >>> 32));
   result = 31 * result + versionType.hashCode();
   result = 31 * result + (fetchSourceContext != null ? fetchSourceContext.hashCode() : 0);
   return result;
 }
  @Override
  public void readFrom(StreamInput in) throws IOException {
    super.readFrom(in);
    type = in.readString();
    id = in.readString();
    routing = in.readOptionalString();
    preference = in.readOptionalString();
    source = in.readBytesReference();
    filteringAlias = in.readStringArray();
    if (in.readBoolean()) {
      fields = in.readStringArray();
    }

    fetchSourceContext = FetchSourceContext.optionalReadFromStream(in);
    nowInMillis = in.readVLong();
  }
    @Override
    public void readFrom(StreamInput in) throws IOException {
      index = in.readString();
      type = in.readOptionalString();
      id = in.readString();
      routing = in.readOptionalString();
      int size = in.readVInt();
      if (size > 0) {
        fields = new String[size];
        for (int i = 0; i < size; i++) {
          fields[i] = in.readString();
        }
      }
      version = in.readLong();
      versionType = VersionType.fromValue(in.readByte());

      fetchSourceContext = FetchSourceContext.optionalReadFromStream(in);
    }
  @Override
  public void writeTo(StreamOutput out) throws IOException {
    super.writeTo(out);
    out.writeString(type);
    out.writeString(id);
    out.writeOptionalString(routing);
    out.writeOptionalString(preference);
    out.writeBytesReference(source);
    out.writeStringArray(filteringAlias);
    if (fields != null) {
      out.writeBoolean(true);
      out.writeStringArray(fields);
    } else {
      out.writeBoolean(false);
    }

    FetchSourceContext.optionalWriteToStream(fetchSourceContext, out);
    out.writeVLong(nowInMillis);
  }
    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (!(o instanceof Item)) return false;

      Item item = (Item) o;

      if (version != item.version) return false;
      if (fetchSourceContext != null
          ? !fetchSourceContext.equals(item.fetchSourceContext)
          : item.fetchSourceContext != null) return false;
      if (!Arrays.equals(fields, item.fields)) return false;
      if (!id.equals(item.id)) return false;
      if (!index.equals(item.index)) return false;
      if (routing != null ? !routing.equals(item.routing) : item.routing != null) return false;
      if (type != null ? !type.equals(item.type) : item.type != null) return false;
      if (versionType != item.versionType) return false;

      return true;
    }
    @Override
    public void writeTo(StreamOutput out) throws IOException {
      out.writeString(index);
      out.writeOptionalString(type);
      out.writeString(id);
      out.writeOptionalString(routing);
      if (fields == null) {
        out.writeVInt(0);
      } else {
        out.writeVInt(fields.length);
        for (String field : fields) {
          out.writeString(field);
        }
      }

      out.writeLong(version);
      out.writeByte(versionType.getValue());

      FetchSourceContext.optionalWriteToStream(fetchSourceContext, out);
    }
 /**
  * A shortcut function to see whether there is a fetchSourceContext and it says the source is
  * requested.
  *
  * @return
  */
 @Override
 public boolean sourceRequested() {
   return fetchSourceContext != null && fetchSourceContext.fetchSource();
 }
  public SearchSourceBuilder fromXContent(XContentParser parser, QueryParseContext context)
      throws IOException {
    SearchSourceBuilder builder = new SearchSourceBuilder();
    XContentParser.Token token = parser.currentToken();
    String currentFieldName = null;
    if (token != XContentParser.Token.START_OBJECT
        && (token = parser.nextToken()) != XContentParser.Token.START_OBJECT) {
      throw new ParsingException(
          parser.getTokenLocation(),
          "Expected [" + XContentParser.Token.START_OBJECT + "] but found [" + token + "]",
          parser.getTokenLocation());
    }
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token.isValue()) {
        if (context.parseFieldMatcher().match(currentFieldName, FROM_FIELD)) {
          builder.from = parser.intValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, SIZE_FIELD)) {
          builder.size = parser.intValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, TIMEOUT_FIELD)) {
          builder.timeoutInMillis = parser.longValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, TERMINATE_AFTER_FIELD)) {
          builder.terminateAfter = parser.intValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, MIN_SCORE_FIELD)) {
          builder.minScore = parser.floatValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, VERSION_FIELD)) {
          builder.version = parser.booleanValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, EXPLAIN_FIELD)) {
          builder.explain = parser.booleanValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, TRACK_SCORES_FIELD)) {
          builder.trackScores = parser.booleanValue();
        } else if (context.parseFieldMatcher().match(currentFieldName, _SOURCE_FIELD)) {
          builder.fetchSourceContext = FetchSourceContext.parse(parser, context);
        } else if (context.parseFieldMatcher().match(currentFieldName, FIELDS_FIELD)) {
          List<String> fieldNames = new ArrayList<>();
          fieldNames.add(parser.text());
          builder.fieldNames = fieldNames;
        } else if (context.parseFieldMatcher().match(currentFieldName, SORT_FIELD)) {
          builder.sort(parser.text());
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unknown key for a " + token + " in [" + currentFieldName + "].",
              parser.getTokenLocation());
        }
      } else if (token == XContentParser.Token.START_OBJECT) {
        if (context.parseFieldMatcher().match(currentFieldName, QUERY_FIELD)) {
          builder.queryBuilder = context.parseInnerQueryBuilder();
        } else if (context.parseFieldMatcher().match(currentFieldName, POST_FILTER_FIELD)) {
          builder.postQueryBuilder = context.parseInnerQueryBuilder();
        } else if (context.parseFieldMatcher().match(currentFieldName, _SOURCE_FIELD)) {
          builder.fetchSourceContext = FetchSourceContext.parse(parser, context);
        } else if (context.parseFieldMatcher().match(currentFieldName, SCRIPT_FIELDS_FIELD)) {
          List<ScriptField> scriptFields = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
            String scriptFieldName = parser.currentName();
            token = parser.nextToken();
            if (token == XContentParser.Token.START_OBJECT) {
              Script script = null;
              boolean ignoreFailure = false;
              while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
                if (token == XContentParser.Token.FIELD_NAME) {
                  currentFieldName = parser.currentName();
                } else if (token.isValue()) {
                  if (context.parseFieldMatcher().match(currentFieldName, SCRIPT_FIELD)) {
                    script = Script.parse(parser, context.parseFieldMatcher());
                  } else if (context
                      .parseFieldMatcher()
                      .match(currentFieldName, IGNORE_FAILURE_FIELD)) {
                    ignoreFailure = parser.booleanValue();
                  } else {
                    throw new ParsingException(
                        parser.getTokenLocation(),
                        "Unknown key for a " + token + " in [" + currentFieldName + "].",
                        parser.getTokenLocation());
                  }
                } else if (token == XContentParser.Token.START_OBJECT) {
                  if (context.parseFieldMatcher().match(currentFieldName, SCRIPT_FIELD)) {
                    script = Script.parse(parser, context.parseFieldMatcher());
                  } else {
                    throw new ParsingException(
                        parser.getTokenLocation(),
                        "Unknown key for a " + token + " in [" + currentFieldName + "].",
                        parser.getTokenLocation());
                  }
                } else {
                  throw new ParsingException(
                      parser.getTokenLocation(),
                      "Unknown key for a " + token + " in [" + currentFieldName + "].",
                      parser.getTokenLocation());
                }
              }
              scriptFields.add(new ScriptField(scriptFieldName, script, ignoreFailure));
            } else {
              throw new ParsingException(
                  parser.getTokenLocation(),
                  "Expected ["
                      + XContentParser.Token.START_OBJECT
                      + "] in ["
                      + currentFieldName
                      + "] but found ["
                      + token
                      + "]",
                  parser.getTokenLocation());
            }
          }
          builder.scriptFields = scriptFields;
        } else if (context.parseFieldMatcher().match(currentFieldName, INDICES_BOOST_FIELD)) {
          ObjectFloatHashMap<String> indexBoost = new ObjectFloatHashMap<String>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
            if (token == XContentParser.Token.FIELD_NAME) {
              currentFieldName = parser.currentName();
            } else if (token.isValue()) {
              indexBoost.put(currentFieldName, parser.floatValue());
            } else {
              throw new ParsingException(
                  parser.getTokenLocation(),
                  "Unknown key for a " + token + " in [" + currentFieldName + "].",
                  parser.getTokenLocation());
            }
          }
          builder.indexBoost = indexBoost;
        } else if (context.parseFieldMatcher().match(currentFieldName, AGGREGATIONS_FIELD)) {
          List<BytesReference> aggregations = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
            currentFieldName = parser.currentName();
            token = parser.nextToken();
            if (token == XContentParser.Token.START_OBJECT) {
              XContentBuilder xContentBuilder =
                  XContentFactory.contentBuilder(parser.contentType());
              xContentBuilder.startObject();
              xContentBuilder.field(currentFieldName);
              xContentBuilder.copyCurrentStructure(parser);
              xContentBuilder.endObject();
              aggregations.add(xContentBuilder.bytes());
            } else {
              throw new ParsingException(
                  parser.getTokenLocation(),
                  "Unknown key for a " + token + " in [" + currentFieldName + "].",
                  parser.getTokenLocation());
            }
          }
          builder.aggregations = aggregations;
        } else if (context.parseFieldMatcher().match(currentFieldName, HIGHLIGHT_FIELD)) {
          XContentBuilder xContentBuilder =
              XContentFactory.contentBuilder(parser.contentType()).copyCurrentStructure(parser);
          builder.highlightBuilder = xContentBuilder.bytes();
        } else if (context.parseFieldMatcher().match(currentFieldName, INNER_HITS_FIELD)) {
          XContentBuilder xContentBuilder =
              XContentFactory.contentBuilder(parser.contentType()).copyCurrentStructure(parser);
          builder.innerHitsBuilder = xContentBuilder.bytes();
        } else if (context.parseFieldMatcher().match(currentFieldName, SUGGEST_FIELD)) {
          XContentBuilder xContentBuilder = XContentFactory.contentBuilder(parser.contentType());
          xContentBuilder.copyCurrentStructure(parser);
          builder.suggestBuilder = xContentBuilder.bytes();
        } else if (context.parseFieldMatcher().match(currentFieldName, SORT_FIELD)) {
          List<BytesReference> sorts = new ArrayList<>();
          XContentBuilder xContentBuilder =
              XContentFactory.contentBuilder(parser.contentType()).copyCurrentStructure(parser);
          sorts.add(xContentBuilder.bytes());
          builder.sorts = sorts;
        } else if (context.parseFieldMatcher().match(currentFieldName, EXT_FIELD)) {
          XContentBuilder xContentBuilder =
              XContentFactory.contentBuilder(parser.contentType()).copyCurrentStructure(parser);
          builder.ext = xContentBuilder.bytes();
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unknown key for a " + token + " in [" + currentFieldName + "].",
              parser.getTokenLocation());
        }
      } else if (token == XContentParser.Token.START_ARRAY) {

        if (context.parseFieldMatcher().match(currentFieldName, FIELDS_FIELD)) {
          List<String> fieldNames = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            if (token == XContentParser.Token.VALUE_STRING) {
              fieldNames.add(parser.text());
            } else {
              throw new ParsingException(
                  parser.getTokenLocation(),
                  "Expected ["
                      + XContentParser.Token.VALUE_STRING
                      + "] in ["
                      + currentFieldName
                      + "] but found ["
                      + token
                      + "]",
                  parser.getTokenLocation());
            }
          }
          builder.fieldNames = fieldNames;
        } else if (context.parseFieldMatcher().match(currentFieldName, FIELDDATA_FIELDS_FIELD)) {
          List<String> fieldDataFields = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            if (token == XContentParser.Token.VALUE_STRING) {
              fieldDataFields.add(parser.text());
            } else {
              throw new ParsingException(
                  parser.getTokenLocation(),
                  "Expected ["
                      + XContentParser.Token.VALUE_STRING
                      + "] in ["
                      + currentFieldName
                      + "] but found ["
                      + token
                      + "]",
                  parser.getTokenLocation());
            }
          }
          builder.fieldDataFields = fieldDataFields;
        } else if (context.parseFieldMatcher().match(currentFieldName, SORT_FIELD)) {
          List<BytesReference> sorts = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            XContentBuilder xContentBuilder =
                XContentFactory.contentBuilder(parser.contentType()).copyCurrentStructure(parser);
            sorts.add(xContentBuilder.bytes());
          }
          builder.sorts = sorts;
        } else if (context.parseFieldMatcher().match(currentFieldName, RESCORE_FIELD)) {
          List<BytesReference> rescoreBuilders = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            XContentBuilder xContentBuilder =
                XContentFactory.contentBuilder(parser.contentType()).copyCurrentStructure(parser);
            rescoreBuilders.add(xContentBuilder.bytes());
          }
          builder.rescoreBuilders = rescoreBuilders;
        } else if (context.parseFieldMatcher().match(currentFieldName, STATS_FIELD)) {
          List<String> stats = new ArrayList<>();
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            if (token == XContentParser.Token.VALUE_STRING) {
              stats.add(parser.text());
            } else {
              throw new ParsingException(
                  parser.getTokenLocation(),
                  "Expected ["
                      + XContentParser.Token.VALUE_STRING
                      + "] in ["
                      + currentFieldName
                      + "] but found ["
                      + token
                      + "]",
                  parser.getTokenLocation());
            }
          }
          builder.stats = stats;
        } else if (context.parseFieldMatcher().match(currentFieldName, _SOURCE_FIELD)) {
          builder.fetchSourceContext = FetchSourceContext.parse(parser, context);
        } else {
          throw new ParsingException(
              parser.getTokenLocation(),
              "Unknown key for a " + token + " in [" + currentFieldName + "].",
              parser.getTokenLocation());
        }
      } else {
        throw new ParsingException(
            parser.getTokenLocation(),
            "Unknown key for a " + token + " in [" + currentFieldName + "].",
            parser.getTokenLocation());
      }
    }
    return builder;
  }
 @Override
 public void writeTo(StreamOutput out) throws IOException {
   boolean hasAggregations = aggregations != null;
   out.writeBoolean(hasAggregations);
   if (hasAggregations) {
     out.writeVInt(aggregations.size());
     for (BytesReference aggregation : aggregations) {
       out.writeBytesReference(aggregation);
     }
   }
   out.writeOptionalBoolean(explain);
   FetchSourceContext.optionalWriteToStream(fetchSourceContext, out);
   boolean hasFieldDataFields = fieldDataFields != null;
   out.writeBoolean(hasFieldDataFields);
   if (hasFieldDataFields) {
     out.writeVInt(fieldDataFields.size());
     for (String field : fieldDataFields) {
       out.writeString(field);
     }
   }
   boolean hasFieldNames = fieldNames != null;
   out.writeBoolean(hasFieldNames);
   if (hasFieldNames) {
     out.writeVInt(fieldNames.size());
     for (String field : fieldNames) {
       out.writeString(field);
     }
   }
   out.writeVInt(from);
   boolean hasHighlightBuilder = highlightBuilder != null;
   out.writeBoolean(hasHighlightBuilder);
   if (hasHighlightBuilder) {
     out.writeBytesReference(highlightBuilder);
   }
   boolean hasIndexBoost = indexBoost != null;
   out.writeBoolean(hasIndexBoost);
   if (hasIndexBoost) {
     out.writeVInt(indexBoost.size());
     for (ObjectCursor<String> key : indexBoost.keys()) {
       out.writeString(key.value);
       out.writeFloat(indexBoost.get(key.value));
     }
   }
   boolean hasInnerHitsBuilder = innerHitsBuilder != null;
   out.writeBoolean(hasInnerHitsBuilder);
   if (hasInnerHitsBuilder) {
     out.writeBytesReference(innerHitsBuilder);
   }
   boolean hasMinScore = minScore != null;
   out.writeBoolean(hasMinScore);
   if (hasMinScore) {
     out.writeFloat(minScore);
   }
   boolean hasPostQuery = postQueryBuilder != null;
   out.writeBoolean(hasPostQuery);
   if (hasPostQuery) {
     out.writeQuery(postQueryBuilder);
   }
   boolean hasQuery = queryBuilder != null;
   out.writeBoolean(hasQuery);
   if (hasQuery) {
     out.writeQuery(queryBuilder);
   }
   boolean hasRescoreBuilders = rescoreBuilders != null;
   out.writeBoolean(hasRescoreBuilders);
   if (hasRescoreBuilders) {
     out.writeVInt(rescoreBuilders.size());
     for (BytesReference rescoreBuilder : rescoreBuilders) {
       out.writeBytesReference(rescoreBuilder);
     }
   }
   boolean hasScriptFields = scriptFields != null;
   out.writeBoolean(hasScriptFields);
   if (hasScriptFields) {
     out.writeVInt(scriptFields.size());
     for (ScriptField scriptField : scriptFields) {
       scriptField.writeTo(out);
     }
   }
   out.writeVInt(size);
   boolean hasSorts = sorts != null;
   out.writeBoolean(hasSorts);
   if (hasSorts) {
     out.writeVInt(sorts.size());
     for (BytesReference sort : sorts) {
       out.writeBytesReference(sort);
     }
   }
   boolean hasStats = stats != null;
   out.writeBoolean(hasStats);
   if (hasStats) {
     out.writeVInt(stats.size());
     for (String stat : stats) {
       out.writeString(stat);
     }
   }
   boolean hasSuggestBuilder = suggestBuilder != null;
   out.writeBoolean(hasSuggestBuilder);
   if (hasSuggestBuilder) {
     out.writeBytesReference(suggestBuilder);
   }
   out.writeVInt(terminateAfter);
   out.writeLong(timeoutInMillis);
   out.writeBoolean(trackScores);
   out.writeOptionalBoolean(version);
   boolean hasExt = ext != null;
   out.writeBoolean(hasExt);
   if (hasExt) {
     out.writeBytesReference(ext);
   }
 }
 @Override
 public SearchSourceBuilder readFrom(StreamInput in) throws IOException {
   SearchSourceBuilder builder = new SearchSourceBuilder();
   if (in.readBoolean()) {
     int size = in.readVInt();
     List<BytesReference> aggregations = new ArrayList<>(size);
     for (int i = 0; i < size; i++) {
       aggregations.add(in.readBytesReference());
     }
     builder.aggregations = aggregations;
   }
   builder.explain = in.readOptionalBoolean();
   builder.fetchSourceContext = FetchSourceContext.optionalReadFromStream(in);
   boolean hasFieldDataFields = in.readBoolean();
   if (hasFieldDataFields) {
     int size = in.readVInt();
     List<String> fieldDataFields = new ArrayList<>(size);
     for (int i = 0; i < size; i++) {
       fieldDataFields.add(in.readString());
     }
     builder.fieldDataFields = fieldDataFields;
   }
   boolean hasFieldNames = in.readBoolean();
   if (hasFieldNames) {
     int size = in.readVInt();
     List<String> fieldNames = new ArrayList<>(size);
     for (int i = 0; i < size; i++) {
       fieldNames.add(in.readString());
     }
     builder.fieldNames = fieldNames;
   }
   builder.from = in.readVInt();
   if (in.readBoolean()) {
     builder.highlightBuilder = in.readBytesReference();
   }
   boolean hasIndexBoost = in.readBoolean();
   if (hasIndexBoost) {
     int size = in.readVInt();
     ObjectFloatHashMap<String> indexBoost = new ObjectFloatHashMap<String>(size);
     for (int i = 0; i < size; i++) {
       indexBoost.put(in.readString(), in.readFloat());
     }
     builder.indexBoost = indexBoost;
   }
   if (in.readBoolean()) {
     builder.innerHitsBuilder = in.readBytesReference();
   }
   if (in.readBoolean()) {
     builder.minScore = in.readFloat();
   }
   if (in.readBoolean()) {
     builder.postQueryBuilder = in.readQuery();
   }
   if (in.readBoolean()) {
     builder.queryBuilder = in.readQuery();
   }
   if (in.readBoolean()) {
     int size = in.readVInt();
     List<BytesReference> rescoreBuilders = new ArrayList<>();
     for (int i = 0; i < size; i++) {
       rescoreBuilders.add(in.readBytesReference());
     }
     builder.rescoreBuilders = rescoreBuilders;
   }
   if (in.readBoolean()) {
     int size = in.readVInt();
     List<ScriptField> scriptFields = new ArrayList<>(size);
     for (int i = 0; i < size; i++) {
       scriptFields.add(ScriptField.PROTOTYPE.readFrom(in));
     }
     builder.scriptFields = scriptFields;
   }
   builder.size = in.readVInt();
   if (in.readBoolean()) {
     int size = in.readVInt();
     List<BytesReference> sorts = new ArrayList<>();
     for (int i = 0; i < size; i++) {
       sorts.add(in.readBytesReference());
     }
     builder.sorts = sorts;
   }
   if (in.readBoolean()) {
     int size = in.readVInt();
     List<String> stats = new ArrayList<>();
     for (int i = 0; i < size; i++) {
       stats.add(in.readString());
     }
     builder.stats = stats;
   }
   if (in.readBoolean()) {
     builder.suggestBuilder = in.readBytesReference();
   }
   builder.terminateAfter = in.readVInt();
   builder.timeoutInMillis = in.readLong();
   builder.trackScores = in.readBoolean();
   builder.version = in.readOptionalBoolean();
   if (in.readBoolean()) {
     builder.ext = in.readBytesReference();
   }
   return builder;
 }
  public static SearchSourceBuilder parseSearchSource(RestRequest request) {
    SearchSourceBuilder searchSourceBuilder = null;

    QuerySourceBuilder querySourceBuilder = RestActions.parseQuerySource(request);
    if (querySourceBuilder != null) {
      searchSourceBuilder = new SearchSourceBuilder();
      searchSourceBuilder.query(querySourceBuilder);
    }

    int from = request.paramAsInt("from", -1);
    if (from != -1) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.from(from);
    }
    int size = request.paramAsInt("size", -1);
    if (size != -1) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.size(size);
    }

    if (request.hasParam("explain")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.explain(request.paramAsBoolean("explain", null));
    }
    if (request.hasParam("version")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.version(request.paramAsBoolean("version", null));
    }
    if (request.hasParam("timeout")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.timeout(request.paramAsTime("timeout", null));
    }
    if (request.hasParam("terminate_after")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      int terminateAfter =
          request.paramAsInt("terminate_after", SearchContext.DEFAULT_TERMINATE_AFTER);
      if (terminateAfter < 0) {
        throw new IllegalArgumentException("terminateAfter must be > 0");
      } else if (terminateAfter > 0) {
        searchSourceBuilder.terminateAfter(terminateAfter);
      }
    }

    String sField = request.param("fields");
    if (sField != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      if (!Strings.hasText(sField)) {
        searchSourceBuilder.noFields();
      } else {
        String[] sFields = Strings.splitStringByCommaToArray(sField);
        if (sFields != null) {
          for (String field : sFields) {
            searchSourceBuilder.field(field);
          }
        }
      }
    }
    String sFieldDataFields = request.param("fielddata_fields");
    if (sFieldDataFields != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      if (Strings.hasText(sFieldDataFields)) {
        String[] sFields = Strings.splitStringByCommaToArray(sFieldDataFields);
        if (sFields != null) {
          for (String field : sFields) {
            searchSourceBuilder.fieldDataField(field);
          }
        }
      }
    }
    FetchSourceContext fetchSourceContext = FetchSourceContext.parseFromRestRequest(request);
    if (fetchSourceContext != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.fetchSource(fetchSourceContext);
    }

    if (request.hasParam("track_scores")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.trackScores(request.paramAsBoolean("track_scores", false));
    }

    String sSorts = request.param("sort");
    if (sSorts != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      String[] sorts = Strings.splitStringByCommaToArray(sSorts);
      for (String sort : sorts) {
        int delimiter = sort.lastIndexOf(":");
        if (delimiter != -1) {
          String sortField = sort.substring(0, delimiter);
          String reverse = sort.substring(delimiter + 1);
          if ("asc".equals(reverse)) {
            searchSourceBuilder.sort(sortField, SortOrder.ASC);
          } else if ("desc".equals(reverse)) {
            searchSourceBuilder.sort(sortField, SortOrder.DESC);
          }
        } else {
          searchSourceBuilder.sort(sort);
        }
      }
    }

    String sStats = request.param("stats");
    if (sStats != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.stats(Strings.splitStringByCommaToArray(sStats));
    }

    String suggestField = request.param("suggest_field");
    if (suggestField != null) {
      String suggestText = request.param("suggest_text", request.param("q"));
      int suggestSize = request.paramAsInt("suggest_size", 5);
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      String suggestMode = request.param("suggest_mode");
      searchSourceBuilder
          .suggest()
          .addSuggestion(
              termSuggestion(suggestField)
                  .field(suggestField)
                  .text(suggestText)
                  .size(suggestSize)
                  .suggestMode(suggestMode));
    }

    return searchSourceBuilder;
  }