Skip to content

Commit c9a6136

Browse files
authored
[ML] Remove the undocumented "delimited" format for post_data (elastic#74188)
The data_description of anomaly detection jobs used to accept delimited data, although this was never documented. This change removes the delimited option from the data_description, and the associated functionality in post_data that handled it. This is not a breaking change because it's removing functionality that officially never existed. However, just in case somebody was using it it is only removed from 8.0 and higher, so that at least they won't find out during a patch install.
1 parent 94d6978 commit c9a6136

File tree

46 files changed

+120
-1732
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+120
-1732
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/config/DataDescription.java

Lines changed: 8 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99

1010
import org.elasticsearch.common.xcontent.ParseField;
1111
import org.elasticsearch.common.xcontent.ObjectParser;
12-
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
1312
import org.elasticsearch.common.xcontent.ToXContentObject;
1413
import org.elasticsearch.common.xcontent.XContentBuilder;
15-
import org.elasticsearch.common.xcontent.XContentParser;
1614

1715
import java.io.IOException;
1816
import java.util.Locale;
@@ -31,12 +29,7 @@ public class DataDescription implements ToXContentObject {
3129
* Enum of the acceptable data formats.
3230
*/
3331
public enum DataFormat {
34-
XCONTENT,
35-
36-
/**
37-
* This is deprecated
38-
*/
39-
DELIMITED;
32+
XCONTENT;
4033

4134
/**
4235
* Case-insensitive from string method.
@@ -56,11 +49,8 @@ public String toString() {
5649
}
5750

5851
private static final ParseField DATA_DESCRIPTION_FIELD = new ParseField("data_description");
59-
private static final ParseField FORMAT_FIELD = new ParseField("format");
6052
private static final ParseField TIME_FIELD_NAME_FIELD = new ParseField("time_field");
6153
private static final ParseField TIME_FORMAT_FIELD = new ParseField("time_format");
62-
private static final ParseField FIELD_DELIMITER_FIELD = new ParseField("field_delimiter");
63-
private static final ParseField QUOTE_CHARACTER_FIELD = new ParseField("quote_character");
6454

6555
/**
6656
* Special time format string for epoch times (seconds)
@@ -77,70 +67,39 @@ public String toString() {
7767
*/
7868
public static final String DEFAULT_TIME_FIELD = "time";
7969

80-
/**
81-
* The default field delimiter expected by the native autodetect
82-
* program.
83-
*/
84-
public static final char DEFAULT_DELIMITER = '\t';
85-
86-
/**
87-
* The default quote character used to escape text in
88-
* delimited data formats
89-
*/
90-
public static final char DEFAULT_QUOTE_CHAR = '"';
91-
92-
private final DataFormat dataFormat;
9370
private final String timeFieldName;
9471
private final String timeFormat;
95-
private final Character fieldDelimiter;
96-
private final Character quoteCharacter;
9772

9873
public static final ObjectParser<Builder, Void> PARSER =
9974
new ObjectParser<>(DATA_DESCRIPTION_FIELD.getPreferredName(), true, Builder::new);
10075

10176
static {
102-
PARSER.declareString(Builder::setFormat, FORMAT_FIELD);
10377
PARSER.declareString(Builder::setTimeField, TIME_FIELD_NAME_FIELD);
10478
PARSER.declareString(Builder::setTimeFormat, TIME_FORMAT_FIELD);
105-
PARSER.declareField(Builder::setFieldDelimiter, DataDescription::extractChar, FIELD_DELIMITER_FIELD, ValueType.STRING);
106-
PARSER.declareField(Builder::setQuoteCharacter, DataDescription::extractChar, QUOTE_CHARACTER_FIELD, ValueType.STRING);
10779
}
10880

109-
public DataDescription(DataFormat dataFormat, String timeFieldName, String timeFormat, Character fieldDelimiter,
110-
Character quoteCharacter) {
111-
this.dataFormat = dataFormat;
81+
public DataDescription(String timeFieldName, String timeFormat) {
11282
this.timeFieldName = timeFieldName;
11383
this.timeFormat = timeFormat;
114-
this.fieldDelimiter = fieldDelimiter;
115-
this.quoteCharacter = quoteCharacter;
11684
}
11785

11886
@Override
11987
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
12088
builder.startObject();
121-
if (dataFormat != DataFormat.XCONTENT) {
122-
builder.field(FORMAT_FIELD.getPreferredName(), dataFormat);
123-
}
12489
builder.field(TIME_FIELD_NAME_FIELD.getPreferredName(), timeFieldName);
12590
builder.field(TIME_FORMAT_FIELD.getPreferredName(), timeFormat);
126-
if (fieldDelimiter != null) {
127-
builder.field(FIELD_DELIMITER_FIELD.getPreferredName(), String.valueOf(fieldDelimiter));
128-
}
129-
if (quoteCharacter != null) {
130-
builder.field(QUOTE_CHARACTER_FIELD.getPreferredName(), String.valueOf(quoteCharacter));
131-
}
13291
builder.endObject();
13392
return builder;
13493
}
13594

13695
/**
13796
* The format of the data to be processed.
138-
* Defaults to {@link DataDescription.DataFormat#XCONTENT}
97+
* Always {@link DataDescription.DataFormat#XCONTENT}
13998
*
14099
* @return The data format
141100
*/
142101
public DataFormat getFormat() {
143-
return dataFormat;
102+
return DataFormat.XCONTENT;
144103
}
145104

146105
/**
@@ -164,39 +123,6 @@ public String getTimeFormat() {
164123
return timeFormat;
165124
}
166125

167-
/**
168-
* If the data is in a delimited format with a header e.g. csv or tsv
169-
* this is the delimiter character used. This is only applicable if
170-
* {@linkplain #getFormat()} is {@link DataDescription.DataFormat#DELIMITED}.
171-
* The default value for delimited format is {@value #DEFAULT_DELIMITER}.
172-
*
173-
* @return A char
174-
*/
175-
public Character getFieldDelimiter() {
176-
return fieldDelimiter;
177-
}
178-
179-
/**
180-
* The quote character used in delimited formats.
181-
* The default value for delimited format is {@value #DEFAULT_QUOTE_CHAR}.
182-
*
183-
* @return The delimited format quote character
184-
*/
185-
public Character getQuoteCharacter() {
186-
return quoteCharacter;
187-
}
188-
189-
private static Character extractChar(XContentParser parser) throws IOException {
190-
if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
191-
String charStr = parser.text();
192-
if (charStr.length() != 1) {
193-
throw new IllegalArgumentException("String must be a single character, found [" + charStr + "]");
194-
}
195-
return charStr.charAt(0);
196-
}
197-
throw new IllegalArgumentException("Unsupported token [" + parser.currentToken() + "]");
198-
}
199-
200126
/**
201127
* Overridden equality test
202128
*/
@@ -212,33 +138,21 @@ public boolean equals(Object other) {
212138

213139
DataDescription that = (DataDescription) other;
214140

215-
return this.dataFormat == that.dataFormat &&
216-
Objects.equals(this.quoteCharacter, that.quoteCharacter) &&
217-
Objects.equals(this.timeFieldName, that.timeFieldName) &&
218-
Objects.equals(this.timeFormat, that.timeFormat) &&
219-
Objects.equals(this.fieldDelimiter, that.fieldDelimiter);
141+
return Objects.equals(this.timeFieldName, that.timeFieldName) && Objects.equals(this.timeFormat, that.timeFormat);
220142
}
221143

222144
@Override
223145
public int hashCode() {
224-
return Objects.hash(dataFormat, quoteCharacter, timeFieldName, timeFormat, fieldDelimiter);
146+
return Objects.hash(timeFieldName, timeFormat);
225147
}
226148

227149
public static class Builder {
228150

229-
private DataFormat dataFormat = DataFormat.XCONTENT;
230151
private String timeFieldName = DEFAULT_TIME_FIELD;
231152
private String timeFormat = EPOCH_MS;
232-
private Character fieldDelimiter;
233-
private Character quoteCharacter;
234153

235154
public Builder setFormat(DataFormat format) {
236-
dataFormat = Objects.requireNonNull(format);
237-
return this;
238-
}
239-
240-
private Builder setFormat(String format) {
241-
setFormat(DataFormat.forString(format));
155+
Objects.requireNonNull(format);
242156
return this;
243157
}
244158

@@ -252,26 +166,8 @@ public Builder setTimeFormat(String format) {
252166
return this;
253167
}
254168

255-
public Builder setFieldDelimiter(Character delimiter) {
256-
fieldDelimiter = delimiter;
257-
return this;
258-
}
259-
260-
public Builder setQuoteCharacter(Character value) {
261-
quoteCharacter = value;
262-
return this;
263-
}
264-
265169
public DataDescription build() {
266-
if (dataFormat == DataFormat.DELIMITED) {
267-
if (fieldDelimiter == null) {
268-
fieldDelimiter = DEFAULT_DELIMITER;
269-
}
270-
if (quoteCharacter == null) {
271-
quoteCharacter = DEFAULT_QUOTE_CHAR;
272-
}
273-
}
274-
return new DataDescription(dataFormat, timeFieldName, timeFormat, fieldDelimiter, quoteCharacter);
170+
return new DataDescription(timeFieldName, timeFormat);
275171
}
276172
}
277173
}

client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/config/DataDescriptionTests.java

Lines changed: 1 addition & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212

1313
import static org.elasticsearch.client.ml.job.config.DataDescription.DataFormat;
1414
import static org.hamcrest.Matchers.equalTo;
15-
import static org.hamcrest.Matchers.nullValue;
16-
import static org.hamcrest.core.Is.is;
1715

1816
public class DataDescriptionTests extends AbstractXContentTestCase<DataDescription> {
1917

@@ -22,122 +20,13 @@ public void testDefault() {
2220
assertThat(dataDescription.getFormat(), equalTo(DataFormat.XCONTENT));
2321
assertThat(dataDescription.getTimeField(), equalTo("time"));
2422
assertThat(dataDescription.getTimeFormat(), equalTo("epoch_ms"));
25-
assertThat(dataDescription.getFieldDelimiter(), is(nullValue()));
26-
assertThat(dataDescription.getQuoteCharacter(), is(nullValue()));
27-
}
28-
29-
public void testDefaultDelimited() {
30-
DataDescription.Builder dataDescriptionBuilder = new DataDescription.Builder();
31-
dataDescriptionBuilder.setFormat(DataFormat.DELIMITED);
32-
DataDescription dataDescription = dataDescriptionBuilder.build();
33-
34-
assertThat(dataDescription.getFormat(), equalTo(DataFormat.DELIMITED));
35-
assertThat(dataDescription.getTimeField(), equalTo("time"));
36-
assertThat(dataDescription.getTimeFormat(), equalTo("epoch_ms"));
37-
assertThat(dataDescription.getFieldDelimiter(), is('\t'));
38-
assertThat(dataDescription.getQuoteCharacter(), is('"'));
39-
}
40-
41-
public void testEquals_GivenDifferentDateFormat() {
42-
DataDescription.Builder description1 = new DataDescription.Builder();
43-
description1.setFormat(DataFormat.XCONTENT);
44-
description1.setQuoteCharacter('"');
45-
description1.setTimeField("timestamp");
46-
description1.setTimeFormat("epoch");
47-
description1.setFieldDelimiter(',');
48-
49-
DataDescription.Builder description2 = new DataDescription.Builder();
50-
description2.setFormat(DataFormat.DELIMITED);
51-
description2.setQuoteCharacter('"');
52-
description2.setTimeField("timestamp");
53-
description2.setTimeFormat("epoch");
54-
description2.setFieldDelimiter(',');
55-
56-
assertFalse(description1.build().equals(description2.build()));
57-
assertFalse(description2.build().equals(description1.build()));
58-
}
59-
60-
public void testEquals_GivenDifferentQuoteCharacter() {
61-
DataDescription.Builder description1 = new DataDescription.Builder();
62-
description1.setFormat(DataFormat.XCONTENT);
63-
description1.setQuoteCharacter('"');
64-
description1.setTimeField("timestamp");
65-
description1.setTimeFormat("epoch");
66-
description1.setFieldDelimiter(',');
67-
68-
DataDescription.Builder description2 = new DataDescription.Builder();
69-
description2.setFormat(DataFormat.XCONTENT);
70-
description2.setQuoteCharacter('\'');
71-
description2.setTimeField("timestamp");
72-
description2.setTimeFormat("epoch");
73-
description2.setFieldDelimiter(',');
74-
75-
assertFalse(description1.build().equals(description2.build()));
76-
assertFalse(description2.build().equals(description1.build()));
77-
}
78-
79-
public void testEquals_GivenDifferentTimeField() {
80-
DataDescription.Builder description1 = new DataDescription.Builder();
81-
description1.setFormat(DataFormat.XCONTENT);
82-
description1.setQuoteCharacter('"');
83-
description1.setTimeField("timestamp");
84-
description1.setTimeFormat("epoch");
85-
description1.setFieldDelimiter(',');
86-
87-
DataDescription.Builder description2 = new DataDescription.Builder();
88-
description2.setFormat(DataFormat.XCONTENT);
89-
description2.setQuoteCharacter('"');
90-
description2.setTimeField("time");
91-
description2.setTimeFormat("epoch");
92-
description2.setFieldDelimiter(',');
93-
94-
assertFalse(description1.build().equals(description2.build()));
95-
assertFalse(description2.build().equals(description1.build()));
96-
}
97-
98-
public void testEquals_GivenDifferentTimeFormat() {
99-
DataDescription.Builder description1 = new DataDescription.Builder();
100-
description1.setFormat(DataFormat.XCONTENT);
101-
description1.setQuoteCharacter('"');
102-
description1.setTimeField("timestamp");
103-
description1.setTimeFormat("epoch");
104-
description1.setFieldDelimiter(',');
105-
106-
DataDescription.Builder description2 = new DataDescription.Builder();
107-
description2.setFormat(DataFormat.XCONTENT);
108-
description2.setQuoteCharacter('"');
109-
description2.setTimeField("timestamp");
110-
description2.setTimeFormat("epoch_ms");
111-
description2.setFieldDelimiter(',');
112-
113-
assertFalse(description1.build().equals(description2.build()));
114-
assertFalse(description2.build().equals(description1.build()));
115-
}
116-
117-
public void testEquals_GivenDifferentFieldDelimiter() {
118-
DataDescription.Builder description1 = new DataDescription.Builder();
119-
description1.setFormat(DataFormat.XCONTENT);
120-
description1.setQuoteCharacter('"');
121-
description1.setTimeField("timestamp");
122-
description1.setTimeFormat("epoch");
123-
description1.setFieldDelimiter(',');
124-
125-
DataDescription.Builder description2 = new DataDescription.Builder();
126-
description2.setFormat(DataFormat.XCONTENT);
127-
description2.setQuoteCharacter('"');
128-
description2.setTimeField("timestamp");
129-
description2.setTimeFormat("epoch");
130-
description2.setFieldDelimiter(';');
131-
132-
assertFalse(description1.build().equals(description2.build()));
133-
assertFalse(description2.build().equals(description1.build()));
13423
}
13524

13625
@Override
13726
protected DataDescription createTestInstance() {
13827
DataDescription.Builder dataDescription = new DataDescription.Builder();
13928
if (randomBoolean()) {
140-
dataDescription.setFormat(randomFrom(DataFormat.values()));
29+
dataDescription.setFormat(DataFormat.XCONTENT);
14130
}
14231
if (randomBoolean()) {
14332
dataDescription.setTimeField(randomAlphaOfLengthBetween(1, 20));
@@ -153,12 +42,6 @@ protected DataDescription createTestInstance() {
15342
}
15443
dataDescription.setTimeFormat(format);
15544
}
156-
if (randomBoolean()) {
157-
dataDescription.setFieldDelimiter(randomAlphaOfLength(1).charAt(0));
158-
}
159-
if (randomBoolean()) {
160-
dataDescription.setQuoteCharacter(randomAlphaOfLength(1).charAt(0));
161-
}
16245
return dataDescription.build();
16346
}
16447

x-pack/plugin/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ tasks.named("yamlRestCompatTest").configure {
137137
'ml/datafeeds_crud/Test update datafeed to point to job already attached to another datafeed',
138138
'ml/datafeeds_crud/Test update datafeed to point to missing job',
139139
'ml/job_cat_apis/Test cat anomaly detector jobs',
140+
'ml/jobs_crud/Test create job with delimited format',
140141
'ml/jobs_crud/Test update job',
141142
'ml/jobs_get_stats/Test get job stats after uploading data prompting the creation of some stats',
142143
'ml/jobs_get_stats/Test get job stats for closed job',

0 commit comments

Comments
 (0)