forked from opensearch-project/OpenSearch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDerivedFieldScript.java
157 lines (136 loc) · 4.87 KB
/
DerivedFieldScript.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
package org.opensearch.script;
import org.apache.lucene.index.LeafReaderContext;
import org.opensearch.common.collect.Tuple;
import org.opensearch.index.fielddata.ScriptDocValues;
import org.opensearch.search.lookup.LeafSearchLookup;
import org.opensearch.search.lookup.SearchLookup;
import org.opensearch.search.lookup.SourceLookup;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* Definition of Script for DerivedField.
* It will be used to execute scripts defined against derived fields of any type
*
* @opensearch.internal
*/
public abstract class DerivedFieldScript {
public static final String[] PARAMETERS = {};
public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>("derived_field", Factory.class);
private static final int MAX_BYTE_SIZE = 1024 * 1024; // Maximum allowed byte size (1 MB)
private static final Map<String, Function<Object, Object>> PARAMS_FUNCTIONS = Map.of(
"doc",
value -> value,
"_source",
value -> ((SourceLookup) value).loadSourceIfNeeded()
);
/**
* The generic runtime parameters for the script.
*/
private final Map<String, Object> params;
/**
* A leaf lookup for the bound segment this script will operate on.
*/
private final LeafSearchLookup leafLookup;
/**
* The field values emitted from the script.
*/
private List<Object> emittedValues;
private int totalByteSize;
public DerivedFieldScript(Map<String, Object> params, SearchLookup lookup, LeafReaderContext leafContext) {
Map<String, Object> parameters = new HashMap<>(params);
this.leafLookup = lookup.getLeafSearchLookup(leafContext);
parameters.putAll(leafLookup.asMap());
this.params = new DynamicMap(parameters, PARAMS_FUNCTIONS);
this.emittedValues = new ArrayList<>();
this.totalByteSize = 0;
}
public DerivedFieldScript() {
this.params = null;
this.leafLookup = null;
this.emittedValues = new ArrayList<>();
this.totalByteSize = 0;
}
/**
* Return the parameters for this script.
*/
public Map<String, Object> getParams() {
return params;
}
/**
* The doc lookup for the Lucene segment this script was created for.
*/
public Map<String, ScriptDocValues<?>> getDoc() {
return leafLookup.doc();
}
/**
* Return the emitted values from the script execution.
*/
public List<Object> getEmittedValues() {
return emittedValues;
}
/**
* Set the current document to run the script on next.
* Clears the emittedValues as well since they should be scoped per document.
*/
public void setDocument(int docid) {
this.emittedValues = new ArrayList<>();
this.totalByteSize = 0;
leafLookup.setDocument(docid);
}
public void addEmittedValue(Object o) {
int byteSize = getObjectByteSize(o);
int newTotalByteSize = totalByteSize + byteSize;
if (newTotalByteSize <= MAX_BYTE_SIZE) {
emittedValues.add(o);
totalByteSize = newTotalByteSize;
} else {
throw new IllegalStateException("Exceeded maximum allowed byte size for emitted values");
}
}
private int getObjectByteSize(Object obj) {
if (obj instanceof String) {
return ((String) obj).getBytes(StandardCharsets.UTF_8).length;
} else if (obj instanceof Integer) {
return Integer.BYTES;
} else if (obj instanceof Long) {
return Long.BYTES;
} else if (obj instanceof Double) {
return Double.BYTES;
} else if (obj instanceof Boolean) {
return Byte.BYTES; // Assuming 1 byte for boolean
} else if (obj instanceof Tuple) {
// Assuming each element in the tuple is a double for GeoPoint case
return Double.BYTES * 2;
} else {
throw new IllegalArgumentException("Unsupported object type passed in emit()");
}
}
public void execute() {}
/**
* A factory to construct {@link DerivedFieldScript} instances.
*
* @opensearch.internal
*/
public interface LeafFactory {
DerivedFieldScript newInstance(LeafReaderContext ctx) throws IOException;
}
/**
* A factory to construct stateful {@link DerivedFieldScript} factories for a specific index.
* @opensearch.internal
*/
public interface Factory extends ScriptFactory {
LeafFactory newFactory(Map<String, Object> params, SearchLookup lookup);
}
}