Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Field stats: added index_constraint option #11259

Merged
Merged
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 @@ -31,7 +31,7 @@

import java.io.IOException;

public abstract class FieldStats<T> implements Streamable, ToXContent {
public abstract class FieldStats<T extends Comparable<T>> implements Streamable, ToXContent {

private byte type;
private long maxDoc;
Expand Down Expand Up @@ -120,6 +120,12 @@ public long getSumTotalTermFreq() {
*/
public abstract String getMaxValue();

/**
* @param value The string to be parsed
* @return The concrete object represented by the string argument
*/
protected abstract T valueOf(String value);

/**
* Merges the provided stats into this stats instance.
*/
Expand All @@ -142,6 +148,34 @@ public void append(FieldStats stats) {
}
}

/**
* @return <code>true</code> if this instance matches with the provided index constraint, otherwise <code>false</code> is returned
*/
public boolean match(IndexConstraint constraint) {
int cmp;
T value = valueOf(constraint.getValue());
if (constraint.getProperty() == IndexConstraint.Property.MIN) {
cmp = minValue.compareTo(value);
} else if (constraint.getProperty() == IndexConstraint.Property.MAX) {
cmp = maxValue.compareTo(value);
} else {
throw new IllegalArgumentException("Unsupported property [" + constraint.getProperty() + "]");
}

switch (constraint.getComparison()) {
case GT:
return cmp > 0;
case GTE:
return cmp >= 0;
case LT:
return cmp < 0;
case LTE:
return cmp <= 0;
default:
throw new IllegalArgumentException("Unsupported comparison [" + constraint.getComparison() + "]");
}
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
Expand Down Expand Up @@ -210,6 +244,11 @@ public void append(FieldStats stats) {
this.maxValue = Math.max(other.maxValue, maxValue);
}

@Override
protected java.lang.Long valueOf(String value) {
return java.lang.Long.valueOf(value);
}

@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
Expand Down Expand Up @@ -255,6 +294,11 @@ public void append(FieldStats stats) {
this.maxValue = Math.max(other.maxValue, maxValue);
}

@Override
protected java.lang.Float valueOf(String value) {
return java.lang.Float.valueOf(value);
}

@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
Expand Down Expand Up @@ -300,6 +344,11 @@ public void append(FieldStats stats) {
this.maxValue = Math.max(other.maxValue, maxValue);
}

@Override
protected java.lang.Double valueOf(String value) {
return java.lang.Double.valueOf(value);
}

@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
Expand Down Expand Up @@ -349,6 +398,11 @@ public void append(FieldStats stats) {
}
}

@Override
protected BytesRef valueOf(String value) {
return new BytesRef(value);
}

@Override
protected void toInnerXContent(XContentBuilder builder) throws IOException {
builder.field(Fields.MIN_VALUE, getMinValue());
Expand Down Expand Up @@ -393,6 +447,11 @@ public String getMaxValue() {
return dateFormatter.printer().print(maxValue);
}

@Override
protected java.lang.Long valueOf(String value) {
return dateFormatter.parser().parseMillis(value);
}

@Override
protected void toInnerXContent(XContentBuilder builder) throws IOException {
builder.field(Fields.MIN_VALUE, getMinValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,131 @@
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ValidateActions;
import org.elasticsearch.action.support.broadcast.BroadcastRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParser.Token;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
*/
public class FieldStatsRequest extends BroadcastRequest<FieldStatsRequest> {

public final static String DEFAULT_LEVEL = "cluster";

private String[] fields;
private String[] fields = Strings.EMPTY_ARRAY;
private String level = DEFAULT_LEVEL;
private IndexConstraint[] indexConstraints = new IndexConstraint[0];

public String[] fields() {
public String[] getFields() {
return fields;
}

public void fields(String[] fields) {
public void setFields(String[] fields) {
if (fields == null) {
throw new NullPointerException("specified fields can't be null");
}
this.fields = fields;
}

public IndexConstraint[] getIndexConstraints() {
return indexConstraints;
}

public void setIndexConstraints(IndexConstraint[] indexConstraints) {
if (indexConstraints == null) {
throw new NullPointerException("specified index_contraints can't be null");
}
this.indexConstraints = indexConstraints;
}

public void source(BytesReference content) throws IOException {
List<IndexConstraint> indexConstraints = new ArrayList<>();
List<String> fields = new ArrayList<>();
try (XContentParser parser = XContentHelper.createParser(content)) {
String fieldName = null;
Token token = parser.nextToken();
assert token == Token.START_OBJECT;
for (token = parser.nextToken(); token != Token.END_OBJECT; token = parser.nextToken()) {
switch (token) {
case FIELD_NAME:
fieldName = parser.currentName();
break;
case START_OBJECT:
if ("index_constraints".equals(fieldName)) {
parseIndexContraints(indexConstraints, parser);
} else {
throw new IllegalArgumentException("unknown field [" + fieldName + "]");
}
break;
case START_ARRAY:
if ("fields".equals(fieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token.isValue()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this mean we will silently ignore other tokens?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes... instead lets fail if there is another token.

fields.add(parser.text());
} else {
throw new IllegalArgumentException("unexpected token [" + token + "]");
}
}
} else {
throw new IllegalArgumentException("unknown field [" + fieldName + "]");
}
break;
default:
throw new IllegalArgumentException("unexpected token [" + token + "]");
}
}
}
this.fields = fields.toArray(new String[fields.size()]);
this.indexConstraints = indexConstraints.toArray(new IndexConstraint[indexConstraints.size()]);
}

private void parseIndexContraints(List<IndexConstraint> indexConstraints, XContentParser parser) throws IOException {
Token token = parser.currentToken();
assert token == Token.START_OBJECT;
String field = null;
String currentName = null;
for (token = parser.nextToken(); token != Token.END_OBJECT; token = parser.nextToken()) {
if (token == Token.FIELD_NAME) {
field = currentName = parser.currentName();
} else if (token == Token.START_OBJECT) {
for (Token fieldToken = parser.nextToken(); fieldToken != Token.END_OBJECT; fieldToken = parser.nextToken()) {
if (fieldToken == Token.FIELD_NAME) {
currentName = parser.currentName();
} else if (fieldToken == Token.START_OBJECT) {
IndexConstraint.Property property = IndexConstraint.Property.parse(currentName);
Token propertyToken = parser.nextToken();
if (propertyToken != Token.FIELD_NAME) {
throw new IllegalArgumentException("unexpected token [" + propertyToken + "]");
}
IndexConstraint.Comparison comparison = IndexConstraint.Comparison.parse(parser.currentName());
propertyToken = parser.nextToken();
if (propertyToken.isValue() == false) {
throw new IllegalArgumentException("unexpected token [" + propertyToken + "]");
}
String value = parser.text();
indexConstraints.add(new IndexConstraint(field, property, comparison, value));

propertyToken = parser.nextToken();
if (propertyToken != Token.END_OBJECT) {
throw new IllegalArgumentException("unexpected token [" + propertyToken + "]");
}
} else {
throw new IllegalArgumentException("unexpected token [" + fieldToken + "]");
}
}
} else {
throw new IllegalArgumentException("unexpected token [" + token + "]");
}
}
}

public String level() {
return level;
}
Expand All @@ -58,20 +161,36 @@ public ActionRequestValidationException validate() {
if ("cluster".equals(level) == false && "indices".equals(level) == false) {
validationException = ValidateActions.addValidationError("invalid level option [" + level + "]", validationException);
}
if (fields == null || fields.length == 0) {
validationException = ValidateActions.addValidationError("no fields specified", validationException);
}
return validationException;
}

@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
fields = in.readStringArray();
int size = in.readVInt();
indexConstraints = new IndexConstraint[size];
for (int i = 0; i < size; i++) {
indexConstraints[i] = new IndexConstraint(in);
}
level = in.readString();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeStringArrayNullable(fields);
out.writeVInt(indexConstraints.length);
for (IndexConstraint indexConstraint : indexConstraints) {
out.writeString(indexConstraint.getField());
out.writeByte(indexConstraint.getProperty().getId());
out.writeByte(indexConstraint.getComparison().getId());
out.writeString(indexConstraint.getValue());
}
out.writeString(level);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ public FieldStatsRequestBuilder(ElasticsearchClient client, FieldStatsAction act
}

public FieldStatsRequestBuilder setFields(String... fields) {
request().fields(fields);
request().setFields(fields);
return this;
}

public FieldStatsRequestBuilder setIndexContraints(IndexConstraint... fields) {
request().setIndexConstraints(fields);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import org.elasticsearch.index.shard.ShardId;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
*/
Expand All @@ -37,7 +40,12 @@ public FieldStatsShardRequest() {

public FieldStatsShardRequest(ShardId shardId, FieldStatsRequest request) {
super(shardId, request);
this.fields = request.fields();
Set<String> fields = new HashSet<>();
fields.addAll(Arrays.asList(request.getFields()));
for (IndexConstraint indexConstraint : request.getIndexConstraints()) {
fields.add(indexConstraint.getField());
}
this.fields = fields.toArray(new String[fields.size()]);
}

public String[] getFields() {
Expand Down
Loading