@@ -90,11 +90,49 @@ public Result prepare(UpdateRequest request, IndexShard indexShard) {
90
90
if (request .upsertRequest () == null && !request .docAsUpsert ()) {
91
91
throw new DocumentMissingException (new ShardId (request .index (), request .shardId ()), request .type (), request .id ());
92
92
}
93
+ Long ttl = null ;
93
94
IndexRequest indexRequest = request .docAsUpsert () ? request .doc () : request .upsertRequest ();
95
+ if (request .scriptedUpsert () && (request .script () != null )) {
96
+ // Run the script to perform the create logic
97
+ IndexRequest upsert = request .upsertRequest ();
98
+ Map <String , Object > upsertDoc = upsert .sourceAsMap ();
99
+ Map <String , Object > ctx = new HashMap <>(2 );
100
+ // Tell the script that this is a create and not an update
101
+ ctx .put ("op" , "create" );
102
+ ctx .put ("_source" , upsertDoc );
103
+ try {
104
+ ExecutableScript script = scriptService .executable (request .scriptLang , request .script , request .scriptType , request .scriptParams );
105
+ script .setNextVar ("ctx" , ctx );
106
+ script .run ();
107
+ // we need to unwrap the ctx...
108
+ ctx = (Map <String , Object >) script .unwrap (ctx );
109
+ } catch (Exception e ) {
110
+ throw new ElasticsearchIllegalArgumentException ("failed to execute script" , e );
111
+ }
112
+ //Allow the script to set TTL using ctx._ttl
113
+ ttl = getTTLFromScriptContext (ctx );
114
+ //Allow the script to abort the create by setting "op" to "none"
115
+ String scriptOpChoice = (String ) ctx .get ("op" );
116
+
117
+ // Only valid options for an upsert script are "create"
118
+ // (the default) or "none", meaning abort upsert
119
+ if (!"create" .equals (scriptOpChoice )) {
120
+ if (!"none" .equals (scriptOpChoice )) {
121
+ logger .warn ("Used upsert operation [{}] for script [{}], doing nothing..." , scriptOpChoice , request .script );
122
+ }
123
+ UpdateResponse update = new UpdateResponse (getResult .getIndex (), getResult .getType (), getResult .getId (),
124
+ getResult .getVersion (), false );
125
+ update .setGetResult (getResult );
126
+ return new Result (update , Operation .NONE , upsertDoc , XContentType .JSON );
127
+ }
128
+ indexRequest .source ((Map )ctx .get ("_source" ));
129
+ }
130
+
94
131
indexRequest .index (request .index ()).type (request .type ()).id (request .id ())
95
132
// it has to be a "create!"
96
- .create (true )
133
+ .create (true )
97
134
.routing (request .routing ())
135
+ .ttl (ttl )
98
136
.refresh (request .refresh ())
99
137
.replicationType (request .replicationType ()).consistencyLevel (request .consistencyLevel ());
100
138
indexRequest .operationThreaded (false );
@@ -121,7 +159,6 @@ public Result prepare(UpdateRequest request, IndexShard indexShard) {
121
159
String operation = null ;
122
160
String timestamp = null ;
123
161
Long ttl = null ;
124
- Object fetchedTTL = null ;
125
162
final Map <String , Object > updatedSourceAsMap ;
126
163
final XContentType updateSourceContentType = sourceAndContent .v1 ();
127
164
String routing = getResult .getFields ().containsKey (RoutingFieldMapper .NAME ) ? getResult .field (RoutingFieldMapper .NAME ).getValue ().toString () : null ;
@@ -164,15 +201,8 @@ public Result prepare(UpdateRequest request, IndexShard indexShard) {
164
201
operation = (String ) ctx .get ("op" );
165
202
timestamp = (String ) ctx .get ("_timestamp" );
166
203
167
- fetchedTTL = ctx .get ("_ttl" );
168
- if (fetchedTTL != null ) {
169
- if (fetchedTTL instanceof Number ) {
170
- ttl = ((Number ) fetchedTTL ).longValue ();
171
- } else {
172
- ttl = TimeValue .parseTimeValue ((String ) fetchedTTL , null ).millis ();
173
- }
174
- }
175
-
204
+ ttl = getTTLFromScriptContext (ctx );
205
+
176
206
updatedSourceAsMap = (Map <String , Object >) ctx .get ("_source" );
177
207
}
178
208
@@ -211,6 +241,19 @@ public Result prepare(UpdateRequest request, IndexShard indexShard) {
211
241
}
212
242
}
213
243
244
+ private Long getTTLFromScriptContext (Map <String , Object > ctx ) {
245
+ Long ttl = null ;
246
+ Object fetchedTTL = ctx .get ("_ttl" );
247
+ if (fetchedTTL != null ) {
248
+ if (fetchedTTL instanceof Number ) {
249
+ ttl = ((Number ) fetchedTTL ).longValue ();
250
+ } else {
251
+ ttl = TimeValue .parseTimeValue ((String ) fetchedTTL , null ).millis ();
252
+ }
253
+ }
254
+ return ttl ;
255
+ }
256
+
214
257
/**
215
258
* Extracts the fields from the updated document to be returned in a update response
216
259
*/
0 commit comments