Skip to content

Commit b5fd4b9

Browse files
committed
New settings for derived field and object type
Signed-off-by: Rishabh Maurya <[email protected]>
1 parent b74c353 commit b5fd4b9

File tree

3 files changed

+168
-4
lines changed

3 files changed

+168
-4
lines changed

server/src/main/java/org/opensearch/index/mapper/DerivedField.java

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,21 @@
1818
import org.opensearch.script.Script;
1919

2020
import java.io.IOException;
21+
import java.util.Map;
2122
import java.util.Objects;
2223

2324
/**
2425
* DerivedField representation: expects a name, type and script.
2526
*/
2627
@PublicApi(since = "2.14.0")
2728
public class DerivedField implements Writeable, ToXContentFragment {
28-
2929
private final String name;
3030
private final String type;
3131
private final Script script;
32+
private String sourceIndexedField;
33+
private Map<String, String> properties;
34+
private Boolean ignoreMalformed;
35+
private String format;
3236

3337
public DerivedField(String name, String type, Script script) {
3438
this.name = name;
@@ -40,20 +44,47 @@ public DerivedField(StreamInput in) throws IOException {
4044
name = in.readString();
4145
type = in.readString();
4246
script = new Script(in);
47+
if (in.readBoolean()) {
48+
properties = in.readMap(StreamInput::readString, StreamInput::readString);
49+
}
50+
sourceIndexedField = in.readOptionalString();
51+
format = in.readOptionalString();
52+
ignoreMalformed = in.readOptionalBoolean();
4353
}
4454

4555
@Override
4656
public void writeTo(StreamOutput out) throws IOException {
4757
out.writeString(name);
4858
out.writeString(type);
4959
script.writeTo(out);
60+
if (properties == null) {
61+
out.writeBoolean(false);
62+
} else {
63+
out.writeBoolean(true);
64+
out.writeMap(properties, StreamOutput::writeString, StreamOutput::writeString);
65+
}
66+
out.writeOptionalString(sourceIndexedField);
67+
out.writeOptionalString(format);
68+
out.writeOptionalBoolean(ignoreMalformed);
5069
}
5170

5271
@Override
5372
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
5473
builder.startObject(name);
5574
builder.field("type", type);
5675
builder.field("script", script);
76+
if (properties != null) {
77+
builder.field("properties", properties);
78+
}
79+
if (sourceIndexedField != null) {
80+
builder.field("source_indexed_field", sourceIndexedField);
81+
}
82+
if (format != null) {
83+
builder.field("format", format);
84+
}
85+
if (ignoreMalformed != null) {
86+
builder.field("ignore_malformed", ignoreMalformed);
87+
}
5788
builder.endObject();
5889
return builder;
5990
}
@@ -70,9 +101,41 @@ public Script getScript() {
70101
return script;
71102
}
72103

104+
public Map<String, String> getProperties() {
105+
return properties;
106+
}
107+
108+
public String getSourceIndexedField() {
109+
return sourceIndexedField;
110+
}
111+
112+
public String getFormat() {
113+
return format;
114+
}
115+
116+
public boolean getIgnoreMalformed() {
117+
return Boolean.TRUE.equals(ignoreMalformed);
118+
}
119+
120+
public void setProperties(Map<String, String> properties) {
121+
this.properties = properties;
122+
}
123+
124+
public void setSourceIndexedField(String sourceIndexedField) {
125+
this.sourceIndexedField = sourceIndexedField;
126+
}
127+
128+
public void setFormat(String format) {
129+
this.format = format;
130+
}
131+
132+
public void setIgnoreMalformed(boolean ignoreMalformed) {
133+
this.ignoreMalformed = ignoreMalformed;
134+
}
135+
73136
@Override
74137
public int hashCode() {
75-
return Objects.hash(name, type, script);
138+
return Objects.hash(name, type, script, sourceIndexedField, properties, ignoreMalformed, format);
76139
}
77140

78141
@Override
@@ -84,7 +147,12 @@ public boolean equals(Object obj) {
84147
return false;
85148
}
86149
DerivedField other = (DerivedField) obj;
87-
return Objects.equals(name, other.name) && Objects.equals(type, other.type) && Objects.equals(script, other.script);
150+
return Objects.equals(name, other.name)
151+
&& Objects.equals(type, other.type)
152+
&& Objects.equals(script, other.script)
153+
&& Objects.equals(sourceIndexedField, other.sourceIndexedField)
154+
&& Objects.equals(properties, other.properties)
155+
&& Objects.equals(ignoreMalformed, other.ignoreMalformed)
156+
&& Objects.equals(format, other.format);
88157
}
89-
90158
}

server/src/main/java/org/opensearch/search/builder/SearchSourceBuilder.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.opensearch.core.xcontent.XContentParser;
5454
import org.opensearch.index.mapper.DerivedField;
5555
import org.opensearch.index.mapper.DerivedFieldMapper;
56+
import org.opensearch.index.mapper.DerivedFieldSupportedTypes;
5657
import org.opensearch.index.query.QueryBuilder;
5758
import org.opensearch.index.query.QueryRewriteContext;
5859
import org.opensearch.index.query.Rewriteable;
@@ -1004,6 +1005,37 @@ public SearchSourceBuilder derivedField(String name, String type, Script script)
10041005
return this;
10051006
}
10061007

1008+
/**
1009+
* Adds a derived field with the given name with provided type, script and other parameters
1010+
* @param name name of the derived field
1011+
* @param type type of the derived field
1012+
* @param script script associated with derived field
1013+
* @param properties map of field name and type of field for nested fields within object derived field
1014+
* @param sourceIndexedField source text field which is indexed to filter documents for better performance
1015+
* @param format date format
1016+
* @param ignoreMalformed ignores malformed fields instead of failing search request
1017+
*/
1018+
public SearchSourceBuilder derivedField(
1019+
String name,
1020+
String type,
1021+
Script script,
1022+
Map<String, String> properties,
1023+
String sourceIndexedField,
1024+
String format,
1025+
Boolean ignoreMalformed
1026+
) {
1027+
if (derivedFields == null) {
1028+
derivedFields = new ArrayList<>();
1029+
}
1030+
DerivedField derivedField = new DerivedField(name, type, script);
1031+
derivedField.setProperties(properties);
1032+
derivedField.setSourceIndexedField(sourceIndexedField);
1033+
derivedField.setFormat(format);
1034+
derivedField.setIgnoreMalformed(ignoreMalformed);
1035+
derivedFields.add(derivedField);
1036+
return this;
1037+
}
1038+
10071039
/**
10081040
* Sets the boost a specific index or alias will receive when the query is executed
10091041
* against it.

server/src/test/java/org/opensearch/search/builder/SearchSourceBuilderTests.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,70 @@ public void testDerivedFieldsParsingAndSerialization() throws IOException {
357357

358358
}
359359

360+
public void testDerivedFieldsParsingAndSerializationObjectType() throws IOException {
361+
{
362+
String restContent = "{\n"
363+
+ " \"derived\": {\n"
364+
+ " \"duration\": {\n"
365+
+ " \"type\": \"long\",\n"
366+
+ " \"script\": \"emit(doc['test'])\"\n"
367+
+ " },\n"
368+
+ " \"ip_from_message\": {\n"
369+
+ " \"type\": \"keyword\",\n"
370+
+ " \"script\": \"emit(doc['message'])\"\n"
371+
+ " },\n"
372+
+ " \"object\": {\n"
373+
+ " \"type\": \"object\",\n"
374+
+ " \"script\": \"emit(doc['test'])\",\n"
375+
+ " \"format\": \"dd-MM-yyyy\",\n"
376+
+ " \"source_indexed_field\": \"test\",\n"
377+
+ " \"ignore_malformed\": true,\n"
378+
+ " \"properties\": {\n"
379+
+ " \"sub_field\": \"text\"\n"
380+
+ " }\n"
381+
+ " }\n"
382+
+ " },\n"
383+
+ " \"query\" : {\n"
384+
+ " \"match\": { \"content\": { \"query\": \"foo bar\" }}\n"
385+
+ " }\n"
386+
+ "}";
387+
388+
String expectedContent =
389+
"{\"query\":{\"match\":{\"content\":{\"query\":\"foo bar\",\"operator\":\"OR\",\"prefix_length\":0,\"max_expansions\":50,\"fuzzy_transpositions\":true,\"lenient\":false,\"zero_terms_query\":\"NONE\",\"auto_generate_synonyms_phrase_query\":true,\"boost\":1.0}}},\"derived\":{\"duration\":{\"type\":\"long\",\"script\":\"emit(doc['test'])\"},\"ip_from_message\":{\"type\":\"keyword\",\"script\":\"emit(doc['message'])\"},\"object\":{\"format\":\"dd-MM-yyyy\",\"source_indexed_field\":\"test\",\"ignore_malformed\":true,\"type\":\"object\",\"script\":\"emit(doc['test'])\",\"properties\":{\"sub_field\":\"text\"}},\"derived_field\":{\"type\":\"object\",\"script\":{\"source\":\"emit(doc['message']\",\"lang\":\"painless\"},\"properties\":{\"sub_field_2\":\"keyword\"},\"source_indexed_field\":\"message\",\"format\":\"dd-MM-yyyy\",\"ignore_malformed\":true}}}";
390+
391+
try (XContentParser parser = createParser(JsonXContent.jsonXContent, restContent)) {
392+
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.fromXContent(parser);
393+
searchSourceBuilder.derivedField(
394+
"derived_field",
395+
"object",
396+
new Script("emit(doc['message']"),
397+
Map.of("sub_field_2", "keyword"),
398+
"message",
399+
"dd-MM-yyyy",
400+
true
401+
);
402+
searchSourceBuilder = rewrite(searchSourceBuilder);
403+
assertEquals(3, searchSourceBuilder.getDerivedFieldsObject().size());
404+
assertEquals(1, searchSourceBuilder.getDerivedFields().size());
405+
assertEquals(1, searchSourceBuilder.getDerivedFields().get(0).getProperties().size());
406+
assertEquals("message", searchSourceBuilder.getDerivedFields().get(0).getSourceIndexedField());
407+
assertEquals("dd-MM-yyyy", searchSourceBuilder.getDerivedFields().get(0).getFormat());
408+
assertTrue(searchSourceBuilder.getDerivedFields().get(0).getIgnoreMalformed());
409+
410+
try (BytesStreamOutput output = new BytesStreamOutput()) {
411+
searchSourceBuilder.writeTo(output);
412+
try (StreamInput in = new NamedWriteableAwareStreamInput(output.bytes().streamInput(), namedWriteableRegistry)) {
413+
SearchSourceBuilder deserializedBuilder = new SearchSourceBuilder(in);
414+
String actualContent = deserializedBuilder.toString();
415+
assertEquals(expectedContent, actualContent);
416+
assertEquals(searchSourceBuilder.hashCode(), deserializedBuilder.hashCode());
417+
assertNotSame(searchSourceBuilder, deserializedBuilder);
418+
}
419+
}
420+
}
421+
}
422+
}
423+
360424
public void testAggsParsing() throws IOException {
361425
{
362426
String restContent = "{\n"

0 commit comments

Comments
 (0)