Skip to content

Commit f72b893

Browse files
authored
Adding new require_alias option to indexing requests (#58917)
This commit adds the `require_alias` flag to requests that create new documents. This flag, when `true` prevents the request from automatically creating an index. Instead, the destination of the request MUST be an alias. When the flag is not set, or `false`, the behavior defaults to the `action.auto_create_index` settings. This is useful when an alias is required instead of a concrete index. closes #55267
1 parent 42377c7 commit f72b893

File tree

30 files changed

+447
-33
lines changed

30 files changed

+447
-33
lines changed

client/client-benchmark-noop-api-plugin/src/main/java/org/elasticsearch/plugin/noop/action/bulk/RestNoopBulkAction.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
6565
String defaultIndex = request.param("index");
6666
String defaultRouting = request.param("routing");
6767
String defaultPipeline = request.param("pipeline");
68+
Boolean defaultRequireAlias = request.paramAsBoolean("require_alias", null);
6869

6970
String waitForActiveShards = request.param("wait_for_active_shards");
7071
if (waitForActiveShards != null) {
@@ -73,7 +74,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
7374
bulkRequest.timeout(request.paramAsTime("timeout", BulkShardRequest.DEFAULT_TIMEOUT));
7475
bulkRequest.setRefreshPolicy(request.param("refresh"));
7576
bulkRequest.add(request.requiredContent(), defaultIndex, defaultRouting,
76-
null, defaultPipeline, true, request.getXContentType());
77+
null, defaultPipeline, defaultRequireAlias, true, request.getXContentType());
7778

7879
// short circuit the call to the transport layer
7980
return channel -> {

docs/reference/docs/index_.asciidoc

+5-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ and <<update-delete-docs-in-a-backing-index>>.
2525

2626
`POST /<target>/_create/<_id>`
2727

28-
IMPORTANT: You cannot add new documents to a data stream using the
29-
`PUT /<target>/_doc/<_id>` request format. To specify a document ID, use the
30-
`PUT /<target>/_create/<_id>` format instead. See
28+
IMPORTANT: You cannot add new documents to a data stream using the
29+
`PUT /<target>/_doc/<_id>` request format. To specify a document ID, use the
30+
`PUT /<target>/_create/<_id>` format instead. See
3131
<<add-documents-to-a-data-stream>>.
3232

3333
[[docs-index-api-path-params]]
@@ -94,6 +94,8 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=version_type]
9494

9595
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=wait_for_active_shards]
9696

97+
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=require-alias]
98+
9799
[[docs-index-api-request-body]]
98100
==== {api-request-body-title}
99101

docs/reference/docs/update.asciidoc

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=if_primary_term]
5353
`lang`::
5454
(Optional, string) The script language. Default: `painless`.
5555

56+
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=require-alias]
57+
5658
include::{es-repo-dir}/rest-api/common-parms.asciidoc[tag=refresh]
5759

5860
`retry_on_conflict`::

docs/reference/rest-api/common-parms.asciidoc

+6
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,12 @@ such as `1264`.
570570
A value of `-1` indicates {es} was unable to compute this number.
571571
end::memory[]
572572

573+
tag::require-alias[]
574+
`require_alias`::
575+
(Optional, boolean) When true, this requires the destination to be an alias.
576+
Defaults to false.
577+
end::require-alias[]
578+
573579
tag::node-filter[]
574580
`<node_filter>`::
575581
(Optional, string)

modules/ingest-common/src/yamlRestTest/resources/rest-api-spec/test/ingest/270_set_processor.yml

+48
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,51 @@ teardown:
5353
index: test
5454
id: 2
5555
- match: { _source.foo: "hello" }
56+
---
57+
"Test set processor with index change and require_alias":
58+
- do:
59+
ingest.put_pipeline:
60+
id: "1"
61+
body: >
62+
{
63+
"processors": [
64+
{
65+
"set" : {
66+
"field" : "_index",
67+
"value" : "new_require_alias_index"
68+
}
69+
}
70+
]
71+
}
72+
- match: { acknowledged: true }
73+
- do:
74+
catch: missing
75+
index:
76+
index: test_require_alias
77+
pipeline: 1
78+
require_alias: true
79+
body: { foo: bar }
80+
81+
- do:
82+
catch: missing
83+
indices.get:
84+
index: test_require_alias
85+
- do:
86+
catch: missing
87+
indices.get:
88+
index: new_require_alias_index
89+
90+
- do:
91+
indices.create:
92+
index: backing_index
93+
body:
94+
mappings: {}
95+
aliases:
96+
new_require_alias_index: {}
97+
98+
- do:
99+
index:
100+
index: test_require_alias
101+
pipeline: 1
102+
require_alias: true
103+
body: { foo: bar }

modules/reindex/src/main/java/org/elasticsearch/index/reindex/ReindexValidator.java

+10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.lucene.util.automaton.MinimizationOperations;
2626
import org.apache.lucene.util.automaton.Operations;
2727
import org.elasticsearch.action.ActionRequestValidationException;
28+
import org.elasticsearch.action.DocWriteRequest;
2829
import org.elasticsearch.action.index.IndexRequest;
2930
import org.elasticsearch.action.search.SearchRequest;
3031
import org.elasticsearch.action.support.AutoCreateIndex;
@@ -35,6 +36,7 @@
3536
import org.elasticsearch.common.logging.DeprecationLogger;
3637
import org.elasticsearch.common.regex.Regex;
3738
import org.elasticsearch.common.settings.Settings;
39+
import org.elasticsearch.index.IndexNotFoundException;
3840
import org.elasticsearch.search.builder.SearchSourceBuilder;
3941

4042
import java.util.List;
@@ -111,6 +113,14 @@ static void validateAgainstAliases(SearchRequest source, IndexRequest destinatio
111113
return;
112114
}
113115
String target = destination.index();
116+
if (destination.isRequireAlias() && (false == clusterState.getMetadata().hasAlias(target))) {
117+
throw new IndexNotFoundException("["
118+
+ DocWriteRequest.REQUIRE_ALIAS
119+
+ "] request flag is [true] and ["
120+
+ target
121+
+ "] is not an alias",
122+
target);
123+
}
114124
if (false == autoCreateIndex.shouldAutoCreate(target, clusterState)) {
115125
/*
116126
* If we're going to autocreate the index we don't need to resolve

modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestReindexAction.java

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.index.reindex;
2121

22+
import org.elasticsearch.action.DocWriteRequest;
2223
import org.elasticsearch.client.node.NodeClient;
2324
import org.elasticsearch.common.xcontent.XContentParser;
2425
import org.elasticsearch.rest.RestRequest;
@@ -68,6 +69,9 @@ protected ReindexRequest buildRequest(RestRequest request) throws IOException {
6869
if (request.hasParam("scroll")) {
6970
internal.setScroll(parseTimeValue(request.param("scroll"), "scroll"));
7071
}
72+
if (request.hasParam(DocWriteRequest.REQUIRE_ALIAS)) {
73+
internal.setRequireAlias(request.paramAsBoolean(DocWriteRequest.REQUIRE_ALIAS, false));
74+
}
7175

7276
return internal;
7377
}

rest-api-spec/src/main/resources/rest-api-spec/api/bulk.json

+4
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@
8787
"pipeline":{
8888
"type":"string",
8989
"description":"The pipeline id to preprocess incoming documents with"
90+
},
91+
"require_alias": {
92+
"type": "boolean",
93+
"description": "Sets require_alias for all incoming documents. Defaults to unset (false)"
9094
}
9195
},
9296
"body":{

rest-api-spec/src/main/resources/rest-api-spec/api/index.json

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@
9292
"pipeline":{
9393
"type":"string",
9494
"description":"The pipeline id to preprocess incoming documents with"
95+
},
96+
"require_alias": {
97+
"type": "boolean",
98+
"description": "When true, requires destination to be an alias. Default is false"
9599
}
96100
},
97101
"body":{

rest-api-spec/src/main/resources/rest-api-spec/api/update.json

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@
9999
"if_primary_term":{
100100
"type":"number",
101101
"description":"only perform the update operation if the last operation that has changed the document has the specified primary term"
102+
},
103+
"require_alias": {
104+
"type": "boolean",
105+
"description": "When true, requires destination is an alias. Default is false"
102106
}
103107
},
104108
"body":{

rest-api-spec/src/main/resources/rest-api-spec/test/bulk/10_basic.yml

+85
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,88 @@
116116
{"index": {"_index": "test_index", "_id": "test_id"}}
117117
{"f1": "v1", "f2": 42}
118118
{}
119+
120+
---
121+
"When setting require_alias flag per request":
122+
- skip:
123+
# TODO adjust after backport
124+
version: " - 7.99.99"
125+
reason: "require_alias flag was added in version 7.9"
126+
127+
- do:
128+
indices.create:
129+
index: backing_index
130+
body:
131+
mappings: {}
132+
aliases:
133+
test_require_alias: {}
134+
- do:
135+
bulk:
136+
refresh: true
137+
body:
138+
- index:
139+
_index: new_index_not_created
140+
require_alias: true
141+
- f: 1
142+
- index:
143+
_index: new_index_created
144+
- f: 2
145+
- index:
146+
_index: test_require_alias
147+
require_alias: true
148+
- f: 3
149+
- create:
150+
_index: test_require_alias
151+
- f: 4
152+
- match: { errors: true }
153+
- match: { items.0.index.status: 404 }
154+
- match: { items.0.index.error.type: index_not_found_exception }
155+
- match: { items.0.index.error.reason: "no such index [new_index_not_created] and [require_alias] request flag is [true] and [new_index_not_created] is not an alias" }
156+
- match: { items.1.index.result: created }
157+
- match: { items.2.index.result: created }
158+
- match: { items.3.create.result: created }
159+
160+
- do:
161+
catch: missing
162+
indices.get:
163+
index: new_index_not_created
164+
---
165+
"When setting require_alias flag":
166+
- skip:
167+
# TODO adjust after backport
168+
version: " - 7.99.99"
169+
reason: "require_alias flag was added in version 7.9"
170+
171+
- do:
172+
indices.create:
173+
index: backing_index
174+
body:
175+
mappings: {}
176+
aliases:
177+
test_require_alias: {}
178+
- do:
179+
bulk:
180+
refresh: true
181+
require_alias: true
182+
body:
183+
- index:
184+
_index: new_index_not_created
185+
- f: 1
186+
- index:
187+
_index: new_index_created
188+
require_alias: false
189+
- f: 2
190+
- index:
191+
_index: test_require_alias
192+
- f: 3
193+
- match: { errors: true }
194+
- match: { items.0.index.status: 404 }
195+
- match: { items.0.index.error.type: index_not_found_exception }
196+
- match: { items.0.index.error.reason: "no such index [new_index_not_created] and [require_alias] request flag is [true] and [new_index_not_created] is not an alias" }
197+
- match: { items.1.index.result: created }
198+
- match: { items.2.index.result: created }
199+
200+
- do:
201+
catch: missing
202+
indices.get:
203+
index: new_index_not_created
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
"Set require_alias flag":
3+
- skip:
4+
# TODO adjust after backport
5+
version: " - 7.99.99"
6+
reason: "require_alias flag added in 7.9+"
7+
- do:
8+
catch: missing
9+
index:
10+
index: test_require_alias
11+
require_alias: true
12+
body: { foo: bar }
13+
- do:
14+
catch: missing
15+
indices.get:
16+
index: test_require_alias
17+
18+
- do:
19+
indices.create:
20+
index: backing_index
21+
body:
22+
mappings: {}
23+
aliases:
24+
test_require_alias: {}
25+
26+
- do:
27+
index:
28+
index: test_require_alias
29+
require_alias: true
30+
body: { foo: bar }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
"Set require_alias flag":
3+
- skip:
4+
# TODO adjust after backport
5+
version: " - 7.99.99"
6+
reason: "require_alias flag added in 7.9+"
7+
- do:
8+
catch: missing
9+
update:
10+
index: test_require_alias
11+
id: 1
12+
require_alias: true
13+
body:
14+
doc: { foo: bar, count: 1 }
15+
doc_as_upsert: true
16+
- do:
17+
catch: missing
18+
indices.get:
19+
index: test_require_alias
20+
21+
- do:
22+
indices.create:
23+
index: backing_index
24+
body:
25+
mappings: {}
26+
aliases:
27+
test_require_alias: {}
28+
29+
- do:
30+
update:
31+
index: test_require_alias
32+
id: 1
33+
require_alias: true
34+
body:
35+
doc: { foo: bar, count: 1 }
36+
doc_as_upsert: true

server/src/main/java/org/elasticsearch/action/DocWriteRequest.java

+8
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
*/
4444
public interface DocWriteRequest<T> extends IndicesRequest, Accountable {
4545

46+
// Flag set for disallowing index auto creation for an individual write request.
47+
String REQUIRE_ALIAS = "require_alias";
48+
4649
/**
4750
* Set the index for this request
4851
* @return the Request
@@ -142,6 +145,11 @@ public interface DocWriteRequest<T> extends IndicesRequest, Accountable {
142145
*/
143146
OpType opType();
144147

148+
/**
149+
* Should this request override specifically require the destination to be an alias?
150+
* @return boolean flag, when true specifically requires an alias
151+
*/
152+
boolean isRequireAlias();
145153
/**
146154
* Requested operation type to perform on the document
147155
*/

server/src/main/java/org/elasticsearch/action/bulk/BulkProcessor.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ public BulkProcessor add(BytesReference data, @Nullable String defaultIndex,
393393
lock.lock();
394394
try {
395395
ensureOpen();
396-
bulkRequest.add(data, defaultIndex, null, null, defaultPipeline,
396+
bulkRequest.add(data, defaultIndex, null, null, defaultPipeline, null,
397397
true, xContentType);
398398
bulkRequestToExecute = newBulkRequestIfNeeded();
399399
} finally {

0 commit comments

Comments
 (0)