diff --git a/.travis.yml b/.travis.yml
index bf66d920..482b6277 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ jdk:
before_install:
- sudo rm -rf /var/lib/elasticsearch
- - curl https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.13.4-amd64.deb -o elasticsearch.deb && sudo dpkg -i --force-confnew elasticsearch.deb
+ - curl https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.14.0-amd64.deb -o elasticsearch.deb && sudo dpkg -i --force-confnew elasticsearch.deb
- sudo cp ./src/test/resources/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml
- sudo cat /etc/elasticsearch/elasticsearch.yml
- sudo java -version
diff --git a/pom.xml b/pom.xml
index dbe83481..57f6c641 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0org.nlpcnelasticsearch-sql
- 8.13.4.0
+ 8.14.0.0jarQuery elasticsearch using SQLelasticsearch-sql
@@ -44,7 +44,7 @@
UTF-8**/MainTestSuite.classsql
- 8.13.4
+ 8.14.0org.elasticsearch.plugin.nlpcn.SqlPlug1.2.1532.0.0-jre
diff --git a/src/main/java/org/elasticsearch/action/ParsedDocWriteResponse.java b/src/main/java/org/elasticsearch/action/ParsedDocWriteResponse.java
new file mode 100644
index 00000000..29441b93
--- /dev/null
+++ b/src/main/java/org/elasticsearch/action/ParsedDocWriteResponse.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+package org.elasticsearch.action;
+
+import org.elasticsearch.cluster.metadata.IndexMetadata;
+import org.elasticsearch.index.Index;
+import org.elasticsearch.index.shard.ShardId;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.XContentParser;
+
+import java.io.IOException;
+
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+
+/**
+ * A base class for the response of a write operation that involves a single doc
+ */
+public abstract class ParsedDocWriteResponse {
+
+ /**
+ * Parse the output of the {@link #innerToXContent(XContentBuilder, Params)} method.
+ *
+ * This method is intended to be called by subclasses and must be called multiple times to parse all the information concerning
+ * {@link DocWriteResponse} objects. It always parses the current token, updates the given parsing context accordingly
+ * if needed and then immediately returns.
+ */
+ public static void parseInnerToXContent(XContentParser parser, DocWriteResponse.Builder context) throws IOException {
+ XContentParser.Token token = parser.currentToken();
+ ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser);
+
+ String currentFieldName = parser.currentName();
+ token = parser.nextToken();
+
+ if (token.isValue()) {
+ if (DocWriteResponse._INDEX.equals(currentFieldName)) {
+ // index uuid and shard id are unknown and can't be parsed back for now.
+ context.setShardId(new ShardId(new Index(parser.text(), IndexMetadata.INDEX_UUID_NA_VALUE), -1));
+ } else if (DocWriteResponse._ID.equals(currentFieldName)) {
+ context.setId(parser.text());
+ } else if (DocWriteResponse._VERSION.equals(currentFieldName)) {
+ context.setVersion(parser.longValue());
+ } else if (DocWriteResponse.RESULT.equals(currentFieldName)) {
+ String result = parser.text();
+ for (DocWriteResponse.Result r : DocWriteResponse.Result.values()) {
+ if (r.getLowercase().equals(result)) {
+ context.setResult(r);
+ break;
+ }
+ }
+ } else if (DocWriteResponse.FORCED_REFRESH.equals(currentFieldName)) {
+ context.setForcedRefresh(parser.booleanValue());
+ } else if (DocWriteResponse._SEQ_NO.equals(currentFieldName)) {
+ context.setSeqNo(parser.longValue());
+ } else if (DocWriteResponse._PRIMARY_TERM.equals(currentFieldName)) {
+ context.setPrimaryTerm(parser.longValue());
+ }
+ } else if (token == XContentParser.Token.START_OBJECT) {
+ if (DocWriteResponse._SHARDS.equals(currentFieldName)) {
+ context.setShardInfo(DocWriteResponse.ShardInfo.fromXContent(parser));
+ } else {
+ parser.skipChildren(); // skip potential inner objects for forward compatibility
+ }
+ } else if (token == XContentParser.Token.START_ARRAY) {
+ parser.skipChildren(); // skip potential inner arrays for forward compatibility
+ }
+ }
+}
diff --git a/src/main/java/org/elasticsearch/action/admin/cluster/settings/ParsedClusterUpdateSettingsResponse.java b/src/main/java/org/elasticsearch/action/admin/cluster/settings/ParsedClusterUpdateSettingsResponse.java
new file mode 100644
index 00000000..ff5c2387
--- /dev/null
+++ b/src/main/java/org/elasticsearch/action/admin/cluster/settings/ParsedClusterUpdateSettingsResponse.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.action.admin.cluster.settings;
+
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.xcontent.ConstructingObjectParser;
+import org.elasticsearch.xcontent.XContentParser;
+
+import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
+
+/**
+ * A response for a cluster update settings action.
+ */
+public class ParsedClusterUpdateSettingsResponse {
+
+ private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(
+ "cluster_update_settings_response",
+ true,
+ args -> {
+ return new ClusterUpdateSettingsResponse((boolean) args[0], (Settings) args[1], (Settings) args[2]);
+ }
+ );
+
+ static {
+ AcknowledgedResponse.declareAcknowledgedField(PARSER);
+ PARSER.declareObject(constructorArg(), (p, c) -> Settings.fromXContent(p), ClusterUpdateSettingsResponse.TRANSIENT);
+ PARSER.declareObject(constructorArg(), (p, c) -> Settings.fromXContent(p), ClusterUpdateSettingsResponse.PERSISTENT);
+ }
+
+ public static ClusterUpdateSettingsResponse fromXContent(XContentParser parser) {
+ return PARSER.apply(parser, null);
+ }
+}
diff --git a/src/main/java/org/elasticsearch/action/admin/indices/refresh/ParsedRefreshResponse.java b/src/main/java/org/elasticsearch/action/admin/indices/refresh/ParsedRefreshResponse.java
index 43f48a05..f980e11f 100644
--- a/src/main/java/org/elasticsearch/action/admin/indices/refresh/ParsedRefreshResponse.java
+++ b/src/main/java/org/elasticsearch/action/admin/indices/refresh/ParsedRefreshResponse.java
@@ -8,20 +8,30 @@
package org.elasticsearch.action.admin.indices.refresh;
+import org.elasticsearch.action.support.DefaultShardOperationFailedException;
import org.elasticsearch.action.support.broadcast.BaseBroadcastResponse;
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
import org.elasticsearch.xcontent.ConstructingObjectParser;
+import org.elasticsearch.xcontent.ParseField;
import org.elasticsearch.xcontent.XContentParser;
import java.util.Arrays;
+import java.util.List;
-import static org.elasticsearch.action.support.broadcast.BaseBroadcastResponse.declareBroadcastFields;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
/**
* The response of a refresh action.
*/
public class ParsedRefreshResponse {
+ private static final ParseField _SHARDS_FIELD = new ParseField("_shards");
+ private static final ParseField TOTAL_FIELD = new ParseField("total");
+ private static final ParseField SUCCESSFUL_FIELD = new ParseField("successful");
+ private static final ParseField FAILED_FIELD = new ParseField("failed");
+ private static final ParseField FAILURES_FIELD = new ParseField("failures");
+
private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("refresh", true, arg -> {
BaseBroadcastResponse response = (BaseBroadcastResponse) arg[0];
return new BroadcastResponse(
@@ -39,4 +49,25 @@ public class ParsedRefreshResponse {
public static BroadcastResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}
+
+ /**
+ * {@link BaseBroadcastResponse#declareBroadcastFields(ConstructingObjectParser)}
+ */
+ @SuppressWarnings("unchecked")
+ public static void declareBroadcastFields(ConstructingObjectParser PARSER) {
+ ConstructingObjectParser shardsParser = new ConstructingObjectParser<>(
+ "_shards",
+ true,
+ arg -> new BaseBroadcastResponse((int) arg[0], (int) arg[1], (int) arg[2], (List) arg[3])
+ );
+ shardsParser.declareInt(constructorArg(), TOTAL_FIELD);
+ shardsParser.declareInt(constructorArg(), SUCCESSFUL_FIELD);
+ shardsParser.declareInt(constructorArg(), FAILED_FIELD);
+ shardsParser.declareObjectArray(
+ optionalConstructorArg(),
+ (p, c) -> DefaultShardOperationFailedException.fromXContent(p),
+ FAILURES_FIELD
+ );
+ PARSER.declareObject(constructorArg(), shardsParser, _SHARDS_FIELD);
+ }
}
diff --git a/src/main/java/org/elasticsearch/action/bulk/ParsedBulkItemResponse.java b/src/main/java/org/elasticsearch/action/bulk/ParsedBulkItemResponse.java
index a543f2d8..aefbfd73 100644
--- a/src/main/java/org/elasticsearch/action/bulk/ParsedBulkItemResponse.java
+++ b/src/main/java/org/elasticsearch/action/bulk/ParsedBulkItemResponse.java
@@ -12,7 +12,10 @@
import org.elasticsearch.action.DocWriteRequest.OpType;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteResponse;
+import org.elasticsearch.action.delete.ParsedDeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
+import org.elasticsearch.action.index.ParsedIndexResponse;
+import org.elasticsearch.action.update.ParsedUpdateResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.core.CheckedConsumer;
import org.elasticsearch.rest.RestStatus;
@@ -54,17 +57,17 @@ public static BulkItemResponse fromXContent(XContentParser parser, int id) throw
if (opType == OpType.INDEX || opType == OpType.CREATE) {
final IndexResponse.Builder indexResponseBuilder = new IndexResponse.Builder();
builder = indexResponseBuilder;
- itemParser = (indexParser) -> IndexResponse.parseXContentFields(indexParser, indexResponseBuilder);
+ itemParser = (indexParser) -> ParsedIndexResponse.parseXContentFields(indexParser, indexResponseBuilder);
} else if (opType == OpType.UPDATE) {
final UpdateResponse.Builder updateResponseBuilder = new UpdateResponse.Builder();
builder = updateResponseBuilder;
- itemParser = (updateParser) -> UpdateResponse.parseXContentFields(updateParser, updateResponseBuilder);
+ itemParser = (updateParser) -> ParsedUpdateResponse.parseXContentFields(updateParser, updateResponseBuilder);
} else if (opType == OpType.DELETE) {
final DeleteResponse.Builder deleteResponseBuilder = new DeleteResponse.Builder();
builder = deleteResponseBuilder;
- itemParser = (deleteParser) -> DeleteResponse.parseXContentFields(deleteParser, deleteResponseBuilder);
+ itemParser = (deleteParser) -> ParsedDeleteResponse.parseXContentFields(deleteParser, deleteResponseBuilder);
} else {
throwUnknownField(currentFieldName, parser);
}
diff --git a/src/main/java/org/elasticsearch/action/delete/ParsedDeleteResponse.java b/src/main/java/org/elasticsearch/action/delete/ParsedDeleteResponse.java
new file mode 100644
index 00000000..63c4581f
--- /dev/null
+++ b/src/main/java/org/elasticsearch/action/delete/ParsedDeleteResponse.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.action.delete;
+
+import org.elasticsearch.action.ParsedDocWriteResponse;
+import org.elasticsearch.xcontent.XContentParser;
+
+import java.io.IOException;
+
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+
+/**
+ * The response of the delete action.
+ *
+ * @see org.elasticsearch.action.delete.DeleteRequest
+ * @see org.elasticsearch.client.internal.Client#delete(DeleteRequest)
+ */
+public class ParsedDeleteResponse {
+
+ public static DeleteResponse fromXContent(XContentParser parser) throws IOException {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
+
+ DeleteResponse.Builder context = new DeleteResponse.Builder();
+ while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
+ parseXContentFields(parser, context);
+ }
+ return context.build();
+ }
+
+ /**
+ * Parse the current token and update the parsing context appropriately.
+ */
+ public static void parseXContentFields(XContentParser parser, DeleteResponse.Builder context) throws IOException {
+ ParsedDocWriteResponse.parseInnerToXContent(parser, context);
+ }
+}
diff --git a/src/main/java/org/elasticsearch/action/index/ParsedIndexResponse.java b/src/main/java/org/elasticsearch/action/index/ParsedIndexResponse.java
new file mode 100644
index 00000000..df1c0f15
--- /dev/null
+++ b/src/main/java/org/elasticsearch/action/index/ParsedIndexResponse.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.action.index;
+
+import org.elasticsearch.action.ParsedDocWriteResponse;
+import org.elasticsearch.xcontent.XContentParser;
+
+import java.io.IOException;
+
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+
+/**
+ * A response of an index operation,
+ *
+ * @see org.elasticsearch.action.index.IndexRequest
+ * @see org.elasticsearch.client.internal.Client#index(IndexRequest)
+ */
+public class ParsedIndexResponse {
+
+ public static IndexResponse fromXContent(XContentParser parser) throws IOException {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
+
+ IndexResponse.Builder context = new IndexResponse.Builder();
+ while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
+ parseXContentFields(parser, context);
+ }
+ return context.build();
+ }
+
+ /**
+ * Parse the current token and update the parsing context appropriately.
+ */
+ public static void parseXContentFields(XContentParser parser, IndexResponse.Builder context) throws IOException {
+ ParsedDocWriteResponse.parseInnerToXContent(parser, context);
+ }
+}
diff --git a/src/main/java/org/elasticsearch/action/search/ParsedSearchResponse.java b/src/main/java/org/elasticsearch/action/search/ParsedSearchResponse.java
index ac328caf..7d882582 100644
--- a/src/main/java/org/elasticsearch/action/search/ParsedSearchResponse.java
+++ b/src/main/java/org/elasticsearch/action/search/ParsedSearchResponse.java
@@ -12,9 +12,12 @@
import org.elasticsearch.core.RefCounted;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.rest.action.RestActions;
+import org.elasticsearch.search.ParsedSearchHits;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.InternalAggregations;
+import org.elasticsearch.search.profile.ParsedSearchProfileResults;
import org.elasticsearch.search.profile.SearchProfileResults;
+import org.elasticsearch.search.suggest.ParsedSuggest;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.xcontent.XContentParser;
import org.elasticsearch.xcontent.XContentParser.Token;
@@ -91,13 +94,13 @@ public static SearchResponse innerFromXContent(XContentParser parser) throws IOE
}
} else if (token == Token.START_OBJECT) {
if (SearchHits.Fields.HITS.equals(currentFieldName)) {
- hits = SearchHits.fromXContent(parser);
+ hits = ParsedSearchHits.fromXContent(parser);
} else if (InternalAggregations.AGGREGATIONS_FIELD.equals(currentFieldName)) {
aggs = InternalAggregations.fromXContent(parser);
} else if (Suggest.NAME.equals(currentFieldName)) {
- suggest = Suggest.fromXContent(parser);
+ suggest = ParsedSuggest.fromXContent(parser);
} else if (SearchProfileResults.PROFILE_FIELD.equals(currentFieldName)) {
- profile = SearchProfileResults.fromXContent(parser);
+ profile = ParsedSearchProfileResults.fromXContent(parser);
} else if (RestActions._SHARDS_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
while ((token = parser.nextToken()) != Token.END_OBJECT) {
if (token == Token.FIELD_NAME) {
diff --git a/src/main/java/org/elasticsearch/action/update/ParsedUpdateResponse.java b/src/main/java/org/elasticsearch/action/update/ParsedUpdateResponse.java
new file mode 100644
index 00000000..ca1272ce
--- /dev/null
+++ b/src/main/java/org/elasticsearch/action/update/ParsedUpdateResponse.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.action.update;
+
+import org.elasticsearch.action.ParsedDocWriteResponse;
+import org.elasticsearch.index.get.GetResult;
+import org.elasticsearch.xcontent.XContentParser;
+
+import java.io.IOException;
+
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+
+public class ParsedUpdateResponse {
+
+ public static UpdateResponse fromXContent(XContentParser parser) throws IOException {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
+
+ UpdateResponse.Builder context = new UpdateResponse.Builder();
+ while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
+ parseXContentFields(parser, context);
+ }
+ return context.build();
+ }
+
+ /**
+ * Parse the current token and update the parsing context appropriately.
+ */
+ public static void parseXContentFields(XContentParser parser, UpdateResponse.Builder context) throws IOException {
+ XContentParser.Token token = parser.currentToken();
+ String currentFieldName = parser.currentName();
+
+ if (UpdateResponse.GET.equals(currentFieldName)) {
+ if (token == XContentParser.Token.START_OBJECT) {
+ context.setGetResult(GetResult.fromXContentEmbedded(parser));
+ }
+ } else {
+ ParsedDocWriteResponse.parseInnerToXContent(parser, context);
+ }
+ }
+}
diff --git a/src/main/java/org/elasticsearch/index/reindex/ParsedBulkByScrollResponse.java b/src/main/java/org/elasticsearch/index/reindex/ParsedBulkByScrollResponse.java
index 7eed05cb..6e575e00 100644
--- a/src/main/java/org/elasticsearch/index/reindex/ParsedBulkByScrollResponse.java
+++ b/src/main/java/org/elasticsearch/index/reindex/ParsedBulkByScrollResponse.java
@@ -11,7 +11,6 @@
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.bulk.BulkItemResponse.Failure;
-import org.elasticsearch.index.reindex.BulkByScrollTask.Status;
import org.elasticsearch.index.reindex.ScrollableHitSource.SearchFailure;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xcontent.ObjectParser;
@@ -39,7 +38,7 @@ public class ParsedBulkByScrollResponse {
PARSER.declareBoolean(BulkByScrollResponseBuilder::setTimedOut, new ParseField(BulkByScrollResponse.TIMED_OUT_FIELD));
PARSER.declareObjectArray(BulkByScrollResponseBuilder::setFailures, (p, c) -> parseFailure(p), new ParseField(BulkByScrollResponse.FAILURES_FIELD));
// since the result of BulkByScrollResponse.Status are mixed we also parse that in this
- Status.declareFields(PARSER);
+ ParsedBulkByScrollTask.ParsedStatus.declareFields(PARSER);
}
public static BulkByScrollResponse fromXContent(XContentParser parser) {
diff --git a/src/main/java/org/elasticsearch/index/reindex/ParsedBulkByScrollTask.java b/src/main/java/org/elasticsearch/index/reindex/ParsedBulkByScrollTask.java
new file mode 100644
index 00000000..1f00506f
--- /dev/null
+++ b/src/main/java/org/elasticsearch/index/reindex/ParsedBulkByScrollTask.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.index.reindex;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.core.Tuple;
+import org.elasticsearch.tasks.Task;
+import org.elasticsearch.xcontent.ConstructingObjectParser;
+import org.elasticsearch.xcontent.ObjectParser;
+import org.elasticsearch.xcontent.ParseField;
+import org.elasticsearch.xcontent.XContentParseException;
+import org.elasticsearch.xcontent.XContentParser;
+import org.elasticsearch.xcontent.XContentParser.Token;
+
+import java.io.IOException;
+
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
+
+/**
+ * Task storing information about a currently running BulkByScroll request.
+ *
+ * When the request is not sliced, this task is the only task created, and starts an action to perform search requests.
+ *
+ * When the request is sliced, this task can either represent a coordinating task (using
+ * {@link BulkByScrollTask#setWorkerCount(int)}) or a worker task that performs search queries (using
+ * {@link BulkByScrollTask#setWorker(float, Integer)}).
+ *
+ * We don't always know if this task will be a leader or worker task when it's created, because if slices is set to "auto" it may
+ * be either depending on the number of shards in the source indices. We figure that out when the request is handled and set it on this
+ * class with {@link #setWorkerCount(int)} or {@link #setWorker(float, Integer)}.
+ */
+public class ParsedBulkByScrollTask {
+
+ /**
+ * Status of the reindex, update by query, or delete by query. While in
+ * general we allow {@linkplain Task.Status} implementations to make
+ * backwards incompatible changes to their {@link Task.Status#toXContent}
+ * implementations, this one has become defacto standardized because Kibana
+ * parses it. As such, we should be very careful about removing things from
+ * this.
+ */
+ public static class ParsedStatus {
+
+ static final ConstructingObjectParser, Void> RETRIES_PARSER = new ConstructingObjectParser<>(
+ "bulk_by_scroll_task_status_retries",
+ true,
+ a -> new Tuple<>(((Long) a[0]), (Long) a[1])
+ );
+ static {
+ RETRIES_PARSER.declareLong(constructorArg(), new ParseField(BulkByScrollTask.Status.RETRIES_BULK_FIELD));
+ RETRIES_PARSER.declareLong(constructorArg(), new ParseField(BulkByScrollTask.Status.RETRIES_SEARCH_FIELD));
+ }
+
+ public static void declareFields(ObjectParser extends BulkByScrollTask.StatusBuilder, Void> parser) {
+ parser.declareInt(BulkByScrollTask.StatusBuilder::setSliceId, new ParseField(BulkByScrollTask.Status.SLICE_ID_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setTotal, new ParseField(BulkByScrollTask.Status.TOTAL_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setUpdated, new ParseField(BulkByScrollTask.Status.UPDATED_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setCreated, new ParseField(BulkByScrollTask.Status.CREATED_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setDeleted, new ParseField(BulkByScrollTask.Status.DELETED_FIELD));
+ parser.declareInt(BulkByScrollTask.StatusBuilder::setBatches, new ParseField(BulkByScrollTask.Status.BATCHES_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setVersionConflicts, new ParseField(BulkByScrollTask.Status.VERSION_CONFLICTS_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setNoops, new ParseField(BulkByScrollTask.Status.NOOPS_FIELD));
+ parser.declareObject(BulkByScrollTask.StatusBuilder::setRetries, RETRIES_PARSER, new ParseField(BulkByScrollTask.Status.RETRIES_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setThrottled, new ParseField(BulkByScrollTask.Status.THROTTLED_RAW_FIELD));
+ parser.declareFloat(BulkByScrollTask.StatusBuilder::setRequestsPerSecond, new ParseField(BulkByScrollTask.Status.REQUESTS_PER_SEC_FIELD));
+ parser.declareString(BulkByScrollTask.StatusBuilder::setReasonCancelled, new ParseField(BulkByScrollTask.Status.CANCELED_FIELD));
+ parser.declareLong(BulkByScrollTask.StatusBuilder::setThrottledUntil, new ParseField(BulkByScrollTask.Status.THROTTLED_UNTIL_RAW_FIELD));
+ parser.declareObjectArray(
+ BulkByScrollTask.StatusBuilder::setSliceStatuses,
+ (p, c) -> ParsedStatusOrException.fromXContent(p),
+ new ParseField(BulkByScrollTask.Status.SLICES_FIELD)
+ );
+ }
+
+ public static BulkByScrollTask.Status fromXContent(XContentParser parser) throws IOException {
+ XContentParser.Token token;
+ if (parser.currentToken() == Token.START_OBJECT) {
+ token = parser.nextToken();
+ } else {
+ token = parser.nextToken();
+ }
+ ensureExpectedToken(Token.START_OBJECT, token, parser);
+ token = parser.nextToken();
+ ensureExpectedToken(Token.FIELD_NAME, token, parser);
+ return innerFromXContent(parser);
+ }
+
+ public static BulkByScrollTask.Status innerFromXContent(XContentParser parser) throws IOException {
+ Token token = parser.currentToken();
+ String fieldName = parser.currentName();
+ ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser);
+ BulkByScrollTask.StatusBuilder builder = new BulkByScrollTask.StatusBuilder();
+ while ((token = parser.nextToken()) != Token.END_OBJECT) {
+ if (token == Token.FIELD_NAME) {
+ fieldName = parser.currentName();
+ } else if (token == Token.START_OBJECT) {
+ if (fieldName.equals(BulkByScrollTask.Status.RETRIES_FIELD)) {
+ builder.setRetries(ParsedStatus.RETRIES_PARSER.parse(parser, null));
+ } else {
+ parser.skipChildren();
+ }
+ } else if (token == Token.START_ARRAY) {
+ if (fieldName.equals(BulkByScrollTask.Status.SLICES_FIELD)) {
+ while ((token = parser.nextToken()) != Token.END_ARRAY) {
+ builder.addToSliceStatuses(ParsedStatusOrException.fromXContent(parser));
+ }
+ } else {
+ parser.skipChildren();
+ }
+ } else { // else if it is a value
+ switch (fieldName) {
+ case BulkByScrollTask.Status.SLICE_ID_FIELD -> builder.setSliceId(parser.intValue());
+ case BulkByScrollTask.Status.TOTAL_FIELD -> builder.setTotal(parser.longValue());
+ case BulkByScrollTask.Status.UPDATED_FIELD -> builder.setUpdated(parser.longValue());
+ case BulkByScrollTask.Status.CREATED_FIELD -> builder.setCreated(parser.longValue());
+ case BulkByScrollTask.Status.DELETED_FIELD -> builder.setDeleted(parser.longValue());
+ case BulkByScrollTask.Status.BATCHES_FIELD -> builder.setBatches(parser.intValue());
+ case BulkByScrollTask.Status.VERSION_CONFLICTS_FIELD -> builder.setVersionConflicts(parser.longValue());
+ case BulkByScrollTask.Status.NOOPS_FIELD -> builder.setNoops(parser.longValue());
+ case BulkByScrollTask.Status.THROTTLED_RAW_FIELD -> builder.setThrottled(parser.longValue());
+ case BulkByScrollTask.Status.REQUESTS_PER_SEC_FIELD -> builder.setRequestsPerSecond(parser.floatValue());
+ case BulkByScrollTask.Status.CANCELED_FIELD -> builder.setReasonCancelled(parser.text());
+ case BulkByScrollTask.Status.THROTTLED_UNTIL_RAW_FIELD -> builder.setThrottledUntil(parser.longValue());
+ }
+ }
+ }
+ return builder.buildStatus();
+ }
+ }
+
+ /**
+ * The status of a slice of the request. Successful requests store the {@link StatusOrException#status} while failing requests store a
+ * {@link StatusOrException#exception}.
+ */
+ public static class ParsedStatusOrException {
+
+ /**
+ * Since {@link StatusOrException} can contain either an {@link Exception} or a {@link Status} we need to peek
+ * at a field first before deciding what needs to be parsed since the same object could contains either.
+ * The {@link #EXPECTED_EXCEPTION_FIELDS} contains the fields that are expected when the serialised object
+ * was an instance of exception and the {@link Status#FIELDS_SET} is the set of fields expected when the
+ * serialized object was an instance of Status.
+ */
+ public static BulkByScrollTask.StatusOrException fromXContent(XContentParser parser) throws IOException {
+ XContentParser.Token token = parser.currentToken();
+ if (token == null) {
+ token = parser.nextToken();
+ }
+ if (token == Token.VALUE_NULL) {
+ return null;
+ } else {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser);
+ token = parser.nextToken();
+ // This loop is present only to ignore unknown tokens. It breaks as soon as we find a field
+ // that is allowed.
+ while (token != Token.END_OBJECT) {
+ ensureExpectedToken(Token.FIELD_NAME, token, parser);
+ String fieldName = parser.currentName();
+ // weird way to ignore unknown tokens
+ if (BulkByScrollTask.Status.FIELDS_SET.contains(fieldName)) {
+ return new BulkByScrollTask.StatusOrException(ParsedStatus.innerFromXContent(parser));
+ } else if (BulkByScrollTask.StatusOrException.EXPECTED_EXCEPTION_FIELDS.contains(fieldName)) {
+ return new BulkByScrollTask.StatusOrException(ElasticsearchException.innerFromXContent(parser, false));
+ } else {
+ // Ignore unknown tokens
+ token = parser.nextToken();
+ if (token == Token.START_OBJECT || token == Token.START_ARRAY) {
+ parser.skipChildren();
+ }
+ token = parser.nextToken();
+ }
+ }
+ throw new XContentParseException("Unable to parse StatusFromException. Expected fields not found.");
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/BulkActionHandler.java b/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/BulkActionHandler.java
index 241ee774..28183130 100644
--- a/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/BulkActionHandler.java
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/BulkActionHandler.java
@@ -14,9 +14,9 @@
import co.elastic.clients.elasticsearch.core.bulk.UpdateOperation;
import jakarta.json.stream.JsonParser;
import org.elasticsearch.action.DocWriteRequest;
-import org.elasticsearch.action.bulk.BulkAction;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.bulk.ParsedBulkResponse;
+import org.elasticsearch.action.bulk.TransportBulkAction;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.ActiveShardCount;
@@ -47,7 +47,7 @@ public BulkActionHandler(ElasticsearchClient client) {
@Override
public String getName() {
- return BulkAction.NAME;
+ return TransportBulkAction.NAME;
}
@Override
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/ClusterUpdateSettingsActionHandler.java b/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/ClusterUpdateSettingsActionHandler.java
index 59e97603..64ac7b5a 100644
--- a/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/ClusterUpdateSettingsActionHandler.java
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/ClusterUpdateSettingsActionHandler.java
@@ -8,6 +8,7 @@
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsAction;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
+import org.elasticsearch.action.admin.cluster.settings.ParsedClusterUpdateSettingsResponse;
import org.elasticsearch.common.Strings;
import java.io.IOException;
@@ -52,6 +53,6 @@ protected PutClusterSettingsRequest convertRequest(ClusterUpdateSettingsRequest
@Override
protected ClusterUpdateSettingsResponse convertResponse(PutClusterSettingsResponse putClusterSettingsResponse) throws IOException {
- return parseJson(putClusterSettingsResponse, ClusterUpdateSettingsResponse::fromXContent);
+ return parseJson(putClusterSettingsResponse, ParsedClusterUpdateSettingsResponse::fromXContent);
}
}
diff --git a/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/CreateIndexActionHandler.java b/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/CreateIndexActionHandler.java
index 86b366b2..5ead5b5e 100644
--- a/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/CreateIndexActionHandler.java
+++ b/src/main/java/org/elasticsearch/plugin/nlpcn/client/handler/CreateIndexActionHandler.java
@@ -7,8 +7,8 @@
import co.elastic.clients.elasticsearch.indices.Alias;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
-import org.elasticsearch.action.admin.indices.create.CreateIndexAction;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
+import org.elasticsearch.action.admin.indices.create.TransportCreateIndexAction;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentHelper;
@@ -38,7 +38,7 @@ public CreateIndexActionHandler(ElasticsearchClient client) {
@Override
public String getName() {
- return CreateIndexAction.NAME;
+ return TransportCreateIndexAction.TYPE.name();
}
@Override
diff --git a/src/main/java/org/elasticsearch/search/ParsedSearchHit.java b/src/main/java/org/elasticsearch/search/ParsedSearchHit.java
new file mode 100644
index 00000000..476cc48c
--- /dev/null
+++ b/src/main/java/org/elasticsearch/search/ParsedSearchHit.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.search;
+
+import org.apache.lucene.search.Explanation;
+import org.elasticsearch.common.ParsingException;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.document.DocumentField;
+import org.elasticsearch.common.text.Text;
+import org.elasticsearch.index.mapper.IgnoredFieldMapper;
+import org.elasticsearch.index.mapper.SourceFieldMapper;
+import org.elasticsearch.index.seqno.SequenceNumbers;
+import org.elasticsearch.index.shard.ShardId;
+import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
+import org.elasticsearch.transport.RemoteClusterAware;
+import org.elasticsearch.xcontent.ConstructingObjectParser;
+import org.elasticsearch.xcontent.ObjectParser;
+import org.elasticsearch.xcontent.ObjectParser.ValueType;
+import org.elasticsearch.xcontent.ParseField;
+import org.elasticsearch.xcontent.XContentBuilder;
+import org.elasticsearch.xcontent.XContentParser;
+import org.elasticsearch.xcontent.XContentParser.Token;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureFieldName;
+import static org.elasticsearch.core.RefCounted.ALWAYS_REFERENCED;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
+import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
+
+/**
+ * A single search hit.
+ *
+ * @see SearchHits
+ */
+public final class ParsedSearchHit {
+
+ // All fields on the root level of the parsed SearhHit are interpreted as metadata fields
+ // public because we use it in a completion suggestion option
+ @SuppressWarnings("unchecked")
+ public static final ObjectParser.UnknownFieldConsumer