mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-03 09:29:11 +00:00
add fields parameter for update API (#1822)
This commit is contained in:
parent
2c4f7d1fc3
commit
0cf0703a7b
@ -48,6 +48,7 @@ import org.elasticsearch.common.xcontent.XContentType;
|
|||||||
import org.elasticsearch.index.engine.DocumentMissingException;
|
import org.elasticsearch.index.engine.DocumentMissingException;
|
||||||
import org.elasticsearch.index.engine.DocumentSourceMissingException;
|
import org.elasticsearch.index.engine.DocumentSourceMissingException;
|
||||||
import org.elasticsearch.index.engine.VersionConflictEngineException;
|
import org.elasticsearch.index.engine.VersionConflictEngineException;
|
||||||
|
import org.elasticsearch.index.get.GetField;
|
||||||
import org.elasticsearch.index.get.GetResult;
|
import org.elasticsearch.index.get.GetResult;
|
||||||
import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
|
import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.internal.RoutingFieldMapper;
|
import org.elasticsearch.index.mapper.internal.RoutingFieldMapper;
|
||||||
@ -60,12 +61,16 @@ import org.elasticsearch.index.shard.service.IndexShard;
|
|||||||
import org.elasticsearch.indices.IndicesService;
|
import org.elasticsearch.indices.IndicesService;
|
||||||
import org.elasticsearch.script.ExecutableScript;
|
import org.elasticsearch.script.ExecutableScript;
|
||||||
import org.elasticsearch.script.ScriptService;
|
import org.elasticsearch.script.ScriptService;
|
||||||
|
import org.elasticsearch.search.lookup.SourceLookup;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Maps.newHashMapWithExpectedSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public class TransportUpdateAction extends TransportInstanceSingleOperationAction<UpdateRequest, UpdateResponse> {
|
public class TransportUpdateAction extends TransportInstanceSingleOperationAction<UpdateRequest, UpdateResponse> {
|
||||||
@ -148,6 +153,35 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
|
|||||||
shardOperation(request, listener, 0);
|
shardOperation(request, listener, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Map<String, GetField> extractFieldsFromSource(final UpdateRequest request, final Map<String, Object> source) {
|
||||||
|
Map<String, GetField> fields = null;
|
||||||
|
if (request.fields() != null && request.fields().length > 0) {
|
||||||
|
SourceLookup sourceLookup = new SourceLookup();
|
||||||
|
sourceLookup.setNextSource(source);
|
||||||
|
for (String field : request.fields()) {
|
||||||
|
Object value = null;
|
||||||
|
if (field.equals("_source")) {
|
||||||
|
value = source;
|
||||||
|
} else {
|
||||||
|
value = sourceLookup.extractValue(field);
|
||||||
|
}
|
||||||
|
if (value != null) {
|
||||||
|
if (fields == null) {
|
||||||
|
fields = newHashMapWithExpectedSize(2);
|
||||||
|
}
|
||||||
|
GetField getField = fields.get(field);
|
||||||
|
if (getField == null) {
|
||||||
|
getField = new GetField(field, new ArrayList<Object>(2));
|
||||||
|
fields.put(field, getField);
|
||||||
|
}
|
||||||
|
getField.values().add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
protected void shardOperation(final UpdateRequest request, final ActionListener<UpdateResponse> listener, final int retryCount) throws ElasticSearchException {
|
protected void shardOperation(final UpdateRequest request, final ActionListener<UpdateResponse> listener, final int retryCount) throws ElasticSearchException {
|
||||||
IndexService indexService = indicesService.indexServiceSafe(request.index());
|
IndexService indexService = indicesService.indexServiceSafe(request.index());
|
||||||
IndexShard indexShard = indexService.shardSafe(request.shardId());
|
IndexShard indexShard = indexService.shardSafe(request.shardId());
|
||||||
@ -207,6 +241,9 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract fields from updated source if necessary
|
||||||
|
final Map<String, GetField> fields = extractFieldsFromSource(request, source);
|
||||||
|
|
||||||
// TODO: external version type, does it make sense here? does not seem like it...
|
// TODO: external version type, does it make sense here? does not seem like it...
|
||||||
|
|
||||||
if (operation == null || "index".equals(operation)) {
|
if (operation == null || "index".equals(operation)) {
|
||||||
@ -222,6 +259,7 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
|
|||||||
public void onResponse(IndexResponse response) {
|
public void onResponse(IndexResponse response) {
|
||||||
UpdateResponse update = new UpdateResponse(response.index(), response.type(), response.id(), response.version());
|
UpdateResponse update = new UpdateResponse(response.index(), response.type(), response.id(), response.version());
|
||||||
update.matches(response.matches());
|
update.matches(response.matches());
|
||||||
|
update.fields(fields);
|
||||||
listener.onResponse(update);
|
listener.onResponse(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,6 +288,7 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
|
|||||||
@Override
|
@Override
|
||||||
public void onResponse(DeleteResponse response) {
|
public void onResponse(DeleteResponse response) {
|
||||||
UpdateResponse update = new UpdateResponse(response.index(), response.type(), response.id(), response.version());
|
UpdateResponse update = new UpdateResponse(response.index(), response.type(), response.id(), response.version());
|
||||||
|
update.fields(fields);
|
||||||
listener.onResponse(update);
|
listener.onResponse(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +310,9 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if ("none".equals(operation)) {
|
} else if ("none".equals(operation)) {
|
||||||
listener.onResponse(new UpdateResponse(getResult.index(), getResult.type(), getResult.id(), getResult.version()));
|
UpdateResponse update = new UpdateResponse(getResult.index(), getResult.type(), getResult.id(), getResult.version());
|
||||||
|
update.fields(fields);
|
||||||
|
listener.onResponse(update);
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Used update operation [{}] for script [{}], doing nothing...", operation, request.script);
|
logger.warn("Used update operation [{}] for script [{}], doing nothing...", operation, request.script);
|
||||||
listener.onResponse(new UpdateResponse(getResult.index(), getResult.type(), getResult.id(), getResult.version()));
|
listener.onResponse(new UpdateResponse(getResult.index(), getResult.type(), getResult.id(), getResult.version()));
|
||||||
|
@ -49,6 +49,8 @@ public class UpdateRequest extends InstanceShardOperationRequest {
|
|||||||
@Nullable
|
@Nullable
|
||||||
Map<String, Object> scriptParams;
|
Map<String, Object> scriptParams;
|
||||||
|
|
||||||
|
private String[] fields;
|
||||||
|
|
||||||
int retryOnConflict = 0;
|
int retryOnConflict = 0;
|
||||||
|
|
||||||
private String percolate;
|
private String percolate;
|
||||||
@ -230,6 +232,21 @@ public class UpdateRequest extends InstanceShardOperationRequest {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly specify the fields that will be returned. By default, nothing is returned.
|
||||||
|
*/
|
||||||
|
public UpdateRequest fields(String... fields) {
|
||||||
|
this.fields = fields;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the fields to be returned.
|
||||||
|
*/
|
||||||
|
public String[] fields() {
|
||||||
|
return this.fields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the number of retries of a version conflict occurs because the document was updated between
|
* Sets the number of retries of a version conflict occurs because the document was updated between
|
||||||
* getting it and updating it. Defaults to 1.
|
* getting it and updating it. Defaults to 1.
|
||||||
@ -333,6 +350,13 @@ public class UpdateRequest extends InstanceShardOperationRequest {
|
|||||||
percolate = in.readUTF();
|
percolate = in.readUTF();
|
||||||
}
|
}
|
||||||
refresh = in.readBoolean();
|
refresh = in.readBoolean();
|
||||||
|
int size = in.readInt();
|
||||||
|
if (size >= 0) {
|
||||||
|
fields = new String[size];
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
fields[i] = in.readUTF();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -364,5 +388,13 @@ public class UpdateRequest extends InstanceShardOperationRequest {
|
|||||||
out.writeUTF(percolate);
|
out.writeUTF(percolate);
|
||||||
}
|
}
|
||||||
out.writeBoolean(refresh);
|
out.writeBoolean(refresh);
|
||||||
|
if (fields == null) {
|
||||||
|
out.writeInt(-1);
|
||||||
|
} else {
|
||||||
|
out.writeInt(fields.length);
|
||||||
|
for (String field : fields) {
|
||||||
|
out.writeUTF(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,14 @@ public class UpdateRequestBuilder extends BaseRequestBuilder<UpdateRequest, Upda
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly specify the fields that will be returned. By default, nothing is returned.
|
||||||
|
*/
|
||||||
|
public UpdateRequestBuilder setFields(String... fields) {
|
||||||
|
request.fields(fields);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the number of retries of a version conflict occurs because the document was updated between
|
* Sets the number of retries of a version conflict occurs because the document was updated between
|
||||||
* getting it and updating it. Defaults to 1.
|
* getting it and updating it. Defaults to 1.
|
||||||
|
@ -20,13 +20,19 @@
|
|||||||
package org.elasticsearch.action.update;
|
package org.elasticsearch.action.update;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.index.get.GetField;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Maps.newHashMapWithExpectedSize;
|
||||||
|
import static org.elasticsearch.index.get.GetField.readGetField;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@ -42,6 +48,8 @@ public class UpdateResponse implements ActionResponse {
|
|||||||
|
|
||||||
private List<String> matches;
|
private List<String> matches;
|
||||||
|
|
||||||
|
private Map<String, GetField> fields;
|
||||||
|
|
||||||
public UpdateResponse() {
|
public UpdateResponse() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -123,6 +131,27 @@ public class UpdateResponse implements ActionResponse {
|
|||||||
return this.matches;
|
return this.matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal.
|
||||||
|
*/
|
||||||
|
public void fields(Map<String, GetField> fields) {
|
||||||
|
this.fields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns extracted fields from updated source. <tt>null</tt> if no field was requested.
|
||||||
|
*/
|
||||||
|
public Map<String, GetField> fields() {
|
||||||
|
return this.fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns extracted fields from updated source. <tt>null</tt> if no field was requested.
|
||||||
|
*/
|
||||||
|
public Map<String, GetField> getFields() {
|
||||||
|
return this.fields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal.
|
* Internal.
|
||||||
*/
|
*/
|
||||||
@ -157,6 +186,16 @@ public class UpdateResponse implements ActionResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int size = in.readVInt();
|
||||||
|
if (size == 0) {
|
||||||
|
fields = ImmutableMap.of();
|
||||||
|
} else {
|
||||||
|
fields = newHashMapWithExpectedSize(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
GetField field = readGetField(in);
|
||||||
|
fields.put(field.name(), field);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -174,5 +213,13 @@ public class UpdateResponse implements ActionResponse {
|
|||||||
out.writeUTF(match);
|
out.writeUTF(match);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fields == null) {
|
||||||
|
out.writeVInt(0);
|
||||||
|
} else {
|
||||||
|
out.writeVInt(fields.size());
|
||||||
|
for (GetField field : fields.values()) {
|
||||||
|
field.writeTo(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,14 @@ import org.elasticsearch.action.support.replication.ReplicationType;
|
|||||||
import org.elasticsearch.action.update.UpdateRequest;
|
import org.elasticsearch.action.update.UpdateRequest;
|
||||||
import org.elasticsearch.action.update.UpdateResponse;
|
import org.elasticsearch.action.update.UpdateResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilderString;
|
import org.elasticsearch.common.xcontent.XContentBuilderString;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.index.get.GetField;
|
||||||
import org.elasticsearch.rest.*;
|
import org.elasticsearch.rest.*;
|
||||||
import org.elasticsearch.rest.action.support.RestXContentBuilder;
|
import org.elasticsearch.rest.action.support.RestXContentBuilder;
|
||||||
|
|
||||||
@ -76,6 +78,13 @@ public class RestUpdateAction extends BaseRestHandler {
|
|||||||
updateRequest.addScriptParam(entry.getKey().substring(3), entry.getValue());
|
updateRequest.addScriptParam(entry.getKey().substring(3), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String sField = request.param("fields");
|
||||||
|
if (sField != null) {
|
||||||
|
String[] sFields = Strings.splitStringByCommaToArray(sField);
|
||||||
|
if (sFields != null) {
|
||||||
|
updateRequest.fields(sFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
updateRequest.retryOnConflict(request.paramAsInt("retry_on_conflict", updateRequest.retryOnConflict()));
|
updateRequest.retryOnConflict(request.paramAsInt("retry_on_conflict", updateRequest.retryOnConflict()));
|
||||||
|
|
||||||
// see if we have it in the body
|
// see if we have it in the body
|
||||||
@ -116,6 +125,34 @@ public class RestUpdateAction extends BaseRestHandler {
|
|||||||
.field(Fields._TYPE, response.type())
|
.field(Fields._TYPE, response.type())
|
||||||
.field(Fields._ID, response.id())
|
.field(Fields._ID, response.id())
|
||||||
.field(Fields._VERSION, response.version());
|
.field(Fields._VERSION, response.version());
|
||||||
|
|
||||||
|
if (response.fields() != null) {
|
||||||
|
Map<String, GetField> fields = response.fields();
|
||||||
|
GetField sourceField = fields.get("_source");
|
||||||
|
if (sourceField != null) {
|
||||||
|
builder.field(Fields._SOURCE, sourceField.values().get(0));
|
||||||
|
fields.remove("_source");
|
||||||
|
}
|
||||||
|
if (fields.size() > 0) {
|
||||||
|
builder.startObject(Fields.FIELDS);
|
||||||
|
for (GetField field : fields.values()) {
|
||||||
|
if (field.values().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (field.values().size() == 1) {
|
||||||
|
builder.field(field.name(), field.values().get(0));
|
||||||
|
} else {
|
||||||
|
builder.field(field.name());
|
||||||
|
builder.startArray();
|
||||||
|
for (Object value : field.values()) {
|
||||||
|
builder.value(value);
|
||||||
|
}
|
||||||
|
builder.endArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.endObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (response.matches() != null) {
|
if (response.matches() != null) {
|
||||||
builder.startArray(Fields.MATCHES);
|
builder.startArray(Fields.MATCHES);
|
||||||
for (String match : response.matches()) {
|
for (String match : response.matches()) {
|
||||||
@ -151,6 +188,8 @@ public class RestUpdateAction extends BaseRestHandler {
|
|||||||
static final XContentBuilderString _TYPE = new XContentBuilderString("_type");
|
static final XContentBuilderString _TYPE = new XContentBuilderString("_type");
|
||||||
static final XContentBuilderString _ID = new XContentBuilderString("_id");
|
static final XContentBuilderString _ID = new XContentBuilderString("_id");
|
||||||
static final XContentBuilderString _VERSION = new XContentBuilderString("_version");
|
static final XContentBuilderString _VERSION = new XContentBuilderString("_version");
|
||||||
|
static final XContentBuilderString _SOURCE = new XContentBuilderString("_source");
|
||||||
static final XContentBuilderString MATCHES = new XContentBuilderString("matches");
|
static final XContentBuilderString MATCHES = new XContentBuilderString("matches");
|
||||||
|
static final XContentBuilderString FIELDS = new XContentBuilderString("fields");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,5 +169,10 @@ public class UpdateTests extends AbstractNodesTests {
|
|||||||
getResponse = client.prepareGet("test", "type1", "3").setFields("_timestamp").execute().actionGet();
|
getResponse = client.prepareGet("test", "type1", "3").setFields("_timestamp").execute().actionGet();
|
||||||
long timestamp = ((Number) getResponse.field("_timestamp").value()).longValue();
|
long timestamp = ((Number) getResponse.field("_timestamp").value()).longValue();
|
||||||
assertThat(timestamp, equalTo(1258294332000L));
|
assertThat(timestamp, equalTo(1258294332000L));
|
||||||
|
|
||||||
|
// check fields parameter
|
||||||
|
client.prepareIndex("test", "type1", "1").setSource("field", 1).execute().actionGet();
|
||||||
|
updateResponse = client.prepareUpdate("test", "type1", "1").setScript("ctx._source.field += 1").setFields("_source", "field").execute().actionGet();
|
||||||
|
assertThat(updateResponse.fields().size(), equalTo(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user