Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.elasticsearch.search.fieldcaps;

import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.ResolvedIndexExpressions;
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesFailure;
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
import org.elasticsearch.client.internal.Client;
Expand All @@ -21,18 +22,21 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.emptyArray;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;

public class CCSFieldCapabilitiesIT extends AbstractMultiClustersTestCase {

Expand Down Expand Up @@ -266,4 +270,35 @@ public void testReturnAllLocal() {
}
}
}

public void testResolvedTo() {
String localIndex = "index-local";
String remoteIndex = "index-remote";
String remoteClusterAlias = "remote_cluster";
populateIndices(localIndex, remoteIndex, remoteClusterAlias, false);
String remoteIndexWithCluster = String.join(":", remoteClusterAlias, remoteIndex);
FieldCapabilitiesResponse response = client().prepareFieldCaps(localIndex, remoteIndexWithCluster)
.setFields("*")
.setIncludeResolvedTo(true)
.get();

assertThat(response.getIndices(), arrayContainingInAnyOrder(localIndex, remoteIndexWithCluster));

ResolvedIndexExpressions local = response.getResolvedLocally();
assertThat(local, notNullValue());
assertThat(local.expressions(), hasSize(1));

List<String> localIndicesList = local.getLocalIndicesList();
assertThat(localIndicesList, hasSize(1));
assertThat(localIndicesList, containsInAnyOrder(localIndex));

Map<String, ResolvedIndexExpressions> remote = response.getResolvedRemotely();
assertThat(remote, notNullValue());
assertThat(remote, aMapWithSize(1));
assertThat(remote.keySet(), contains(remoteClusterAlias));

List<String> remoteIndicesList = remote.get(remoteClusterAlias).getLocalIndicesList();
assertThat(remoteIndicesList, hasSize(1));
assertThat(remoteIndicesList, containsInAnyOrder(remoteIndex));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;

Expand Down Expand Up @@ -913,6 +914,13 @@ public void testIndexMode() throws Exception {
assertThat(actualIndexModes, equalTo(indexModes));
}

public void testNoneExpressionIndices() {
// The auth code injects the pattern ["*", "-*"] which effectively means a request that requests no indices
FieldCapabilitiesResponse response = client().prepareFieldCaps("*", "-*").setFields("*").get();

assertThat(response.getIndices().length, is(0));
}

private void assertIndices(FieldCapabilitiesResponse response, String... indices) {
assertNotNull(response.getIndices());
Arrays.sort(indices);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public final class FieldCapabilitiesRequest extends LegacyActionRequest implemen
public static final IndicesOptions DEFAULT_INDICES_OPTIONS = IndicesOptions.strictExpandOpenAndForbidClosed();

private static final TransportVersion FIELD_CAPS_ADD_CLUSTER_ALIAS = TransportVersion.fromName("field_caps_add_cluster_alias");
private static final TransportVersion RESOLVED_FIELDS_CAPS = TransportVersion.fromName("resolved_fields_caps");

private String clusterAlias = RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY;

Expand All @@ -58,6 +59,8 @@ public final class FieldCapabilitiesRequest extends LegacyActionRequest implemen
*/
private transient boolean includeIndices = false;

private boolean includeResolvedTo = false;

/**
* Controls whether all local indices should be returned if no remotes matched
* See {@link org.elasticsearch.transport.RemoteClusterService#groupIndices} returnLocalAll argument.
Expand Down Expand Up @@ -91,6 +94,11 @@ public FieldCapabilitiesRequest(StreamInput in) throws IOException {
} else {
clusterAlias = RemoteClusterAware.LOCAL_CLUSTER_GROUP_KEY;
}
if (in.getTransportVersion().supports(RESOLVED_FIELDS_CAPS)) {
includeResolvedTo = in.readBoolean();
} else {
includeResolvedTo = false;
}
}

public FieldCapabilitiesRequest() {}
Expand Down Expand Up @@ -141,6 +149,9 @@ public void writeTo(StreamOutput out) throws IOException {
if (out.getTransportVersion().supports(FIELD_CAPS_ADD_CLUSTER_ALIAS)) {
out.writeOptionalString(clusterAlias);
}
if (out.getTransportVersion().supports(RESOLVED_FIELDS_CAPS)) {
out.writeBoolean(includeResolvedTo);
}
}

@Override
Expand Down Expand Up @@ -219,6 +230,11 @@ public FieldCapabilitiesRequest includeIndices(boolean includeIndices) {
return this;
}

public FieldCapabilitiesRequest includeResolvedTo(boolean includeResolvedTo) {
this.includeResolvedTo = includeResolvedTo;
return this;
}

public FieldCapabilitiesRequest returnLocalAll(boolean returnLocalAll) {
this.returnLocalAll = returnLocalAll;
return this;
Expand Down Expand Up @@ -252,6 +268,10 @@ public boolean includeIndices() {
return includeIndices;
}

public boolean includeResolvedTo() {
return includeResolvedTo;
}

public boolean returnLocalAll() {
return returnLocalAll;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,9 @@ public FieldCapabilitiesRequestBuilder setReturnLocalAll(boolean returnLocalAll)
request().returnLocalAll(returnLocalAll);
return this;
}

public FieldCapabilitiesRequestBuilder setIncludeResolvedTo(boolean resolvedTo) {
request().includeResolvedTo(resolvedTo);
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

package org.elasticsearch.action.fieldcaps;

import org.elasticsearch.TransportVersion;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.ResolvedIndexExpressions;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Iterators;
import org.elasticsearch.common.io.stream.StreamInput;
Expand All @@ -19,7 +21,9 @@
import org.elasticsearch.xcontent.ToXContent;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
Expand All @@ -35,41 +39,55 @@ public class FieldCapabilitiesResponse extends ActionResponse implements Chunked
private static final ParseField FAILED_INDICES_FIELD = new ParseField("failed_indices");
public static final ParseField FAILURES_FIELD = new ParseField("failures");

private static final TransportVersion RESOLVED_FIELDS_CAPS = TransportVersion.fromName("resolved_fields_caps");

private final String[] indices;
private final ResolvedIndexExpressions resolvedLocally;
private final Map<String, ResolvedIndexExpressions> resolvedRemotely;
private final Map<String, Map<String, FieldCapabilities>> fields;
private final List<FieldCapabilitiesFailure> failures;
private final List<FieldCapabilitiesIndexResponse> indexResponses;

public FieldCapabilitiesResponse(
String[] indices,
Map<String, Map<String, FieldCapabilities>> fields,
List<FieldCapabilitiesFailure> failures
) {
this(indices, fields, Collections.emptyList(), failures);
}

public FieldCapabilitiesResponse(String[] indices, Map<String, Map<String, FieldCapabilities>> fields) {
this(indices, fields, Collections.emptyList(), Collections.emptyList());
public static FieldCapabilitiesResponse empty() {
return new FieldCapabilitiesResponse(
Strings.EMPTY_ARRAY,
null,
Collections.emptyMap(),
Collections.emptyMap(),
Collections.emptyList(),
Collections.emptyList()
);
}

public FieldCapabilitiesResponse(List<FieldCapabilitiesIndexResponse> indexResponses, List<FieldCapabilitiesFailure> failures) {
this(Strings.EMPTY_ARRAY, Collections.emptyMap(), indexResponses, failures);
public static FieldCapabilitiesResponse.Builder builder() {
return new FieldCapabilitiesResponse.Builder();
}

private FieldCapabilitiesResponse(
String[] indices,
ResolvedIndexExpressions resolvedLocally,
Map<String, ResolvedIndexExpressions> resolvedRemotely,
Map<String, Map<String, FieldCapabilities>> fields,
List<FieldCapabilitiesIndexResponse> indexResponses,
List<FieldCapabilitiesFailure> failures
) {
this.fields = Objects.requireNonNull(fields);
this.resolvedLocally = resolvedLocally;
this.resolvedRemotely = Objects.requireNonNull(resolvedRemotely);
this.indexResponses = Objects.requireNonNull(indexResponses);
this.indices = indices;
this.failures = failures;
}

public FieldCapabilitiesResponse(StreamInput in) throws IOException {
this.indices = in.readStringArray();
if (in.getTransportVersion().supports(RESOLVED_FIELDS_CAPS)) {
this.resolvedLocally = in.readOptionalWriteable(ResolvedIndexExpressions::new);
this.resolvedRemotely = in.readImmutableMap(StreamInput::readString, ResolvedIndexExpressions::new);
} else {
this.resolvedLocally = null;
this.resolvedRemotely = Collections.emptyMap();
}
this.fields = in.readMap(FieldCapabilitiesResponse::readField);
this.indexResponses = FieldCapabilitiesIndexResponse.readList(in);
this.failures = in.readCollectionAsList(FieldCapabilitiesFailure::new);
Expand Down Expand Up @@ -115,6 +133,20 @@ public List<FieldCapabilitiesIndexResponse> getIndexResponses() {
return indexResponses;
}

/**
* Locally resolved index expressions
*/
public ResolvedIndexExpressions getResolvedLocally() {
return resolvedLocally;
}

/**
* Locally resolved index expressions
*/
public Map<String, ResolvedIndexExpressions> getResolvedRemotely() {
return resolvedRemotely;
}

/**
*
* Get the field capabilities per type for the provided {@code field}.
Expand All @@ -141,6 +173,10 @@ private static Map<String, FieldCapabilities> readField(StreamInput in) throws I
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeStringArray(indices);
if (out.getTransportVersion().supports(RESOLVED_FIELDS_CAPS)) {
out.writeOptionalWriteable(resolvedLocally);
out.writeMap(resolvedRemotely, StreamOutput::writeWriteable);
}
out.writeMap(fields, FieldCapabilitiesResponse::writeField);
FieldCapabilitiesIndexResponse.writeList(out, indexResponses);
out.writeCollection(failures);
Expand Down Expand Up @@ -182,14 +218,16 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
FieldCapabilitiesResponse that = (FieldCapabilitiesResponse) o;
return Arrays.equals(indices, that.indices)
&& Objects.equals(resolvedLocally, that.resolvedLocally)
&& Objects.equals(resolvedRemotely, that.resolvedRemotely)
&& Objects.equals(fields, that.fields)
&& Objects.equals(indexResponses, that.indexResponses)
&& Objects.equals(failures, that.failures);
}

@Override
public int hashCode() {
int result = Objects.hash(fields, indexResponses, failures);
int result = Objects.hash(resolvedLocally, resolvedRemotely, fields, indexResponses, failures);
result = 31 * result + Arrays.hashCode(indices);
return result;
}
Expand All @@ -201,4 +239,46 @@ public String toString() {
}
return Strings.toString(this);
}

public static class Builder {
private String[] indices = Strings.EMPTY_ARRAY;
private ResolvedIndexExpressions resolvedLocally;
private Map<String, ResolvedIndexExpressions> resolvedRemotely = Collections.emptyMap();
private Map<String, Map<String, FieldCapabilities>> fields = Collections.emptyMap();
private List<FieldCapabilitiesIndexResponse> indexResponses = Collections.emptyList();
private List<FieldCapabilitiesFailure> failures = Collections.emptyList();

private Builder() {}

public Builder withIndices(String[] indices) {
this.indices = indices;
return this;
}

public Builder withResolved(ResolvedIndexExpressions resolvedLocally, Map<String, ResolvedIndexExpressions> resolvedRemotely) {
this.resolvedLocally = resolvedLocally;
this.resolvedRemotely = resolvedRemotely;
return this;
}

public Builder withFields(Map<String, Map<String, FieldCapabilities>> fields) {
this.fields = fields;
return this;
}

public Builder withIndexResponses(Collection<FieldCapabilitiesIndexResponse> indexResponses) {
this.indexResponses = new ArrayList<>(indexResponses);
return this;
}

public Builder withFailures(List<FieldCapabilitiesFailure> failures) {
this.failures = failures;
return this;
}

public FieldCapabilitiesResponse build() {
return new FieldCapabilitiesResponse(indices, resolvedLocally, resolvedRemotely, fields, indexResponses, failures);
}
}

}
Loading