Skip to content

[BUG] Java high-level REST client bulk() is not respecting the bulkRequest.requireAlias(true) method call #12958

@olfuerniss

Description

@olfuerniss

Describe the bug

The Java high-level REST client bulk(BulkRequest bulkRequest, RequestOptions options) is not respecting the bulkRequest.requireAlias(true) method call. It automatically creates an index with the name of the alias which should not happen when the require alias flag is set.

Related component

Clients

To Reproduce

Following are 4 examples of how the require alias flag can be set and should be respected.

Fail 1: Auto creates the index testindex-1

private RestHighLevelClient osClient;

@Test  
public void t0010_bulkWithRequireAliasUsingGlobalIndex() {  
    String indexAliasName = "testindex-1";  
    try {  
        BulkRequest bulkRequest = new BulkRequest(indexAliasName);  
        bulkRequest.requireAlias(true);  
        bulkRequest.add(new IndexRequest().id("1").source("{ \"name\": \"Biden\" }", XContentType.JSON));  
        bulkRequest.add(new IndexRequest().id("2").source("{ \"name\": \"Trump\" }", XContentType.JSON));  
  
        BulkResponse bulkResponse = osClient.bulk(bulkRequest, RequestOptions.DEFAULT);  
  
        assertFalse(existsIndex(indexAliasName), "Should not auto-create the index.");  
        assertTrue(bulkResponse.hasFailures(), "Bulk response must have failures.");  
    } catch (Exception ex) {  
        Assert.fail("Must not throw an exception");  
    }  
}

Fail 2: Auto creates the index testindex-2

private RestHighLevelClient osClient;

@Test  
public void t0020_bulkWithRequireAliasUsingIndexOnEachRequest() {  
    String indexAliasName = "testindex-2";  
    try {  
        BulkRequest bulkRequest = new BulkRequest();  
        bulkRequest.requireAlias(true);  
        bulkRequest.add(new IndexRequest().index(indexAliasName).id("1").source("{ \"name\": \"Biden\" }", XContentType.JSON));  
        bulkRequest.add(new IndexRequest().index(indexAliasName).id("2").source("{ \"name\": \"Trump\" }", XContentType.JSON));  
  
        BulkResponse bulkResponse = osClient.bulk(bulkRequest, RequestOptions.DEFAULT);  
  
        assertFalse(existsIndex(indexAliasName), "Should not auto-create the index.");  
        assertTrue(bulkResponse.hasFailures(), "Bulk response must have failures.");  
    } catch (Exception ex) {  
        Assert.fail("Must not throw an exception");  
    }  
}

Fail 3: Auto creates the index testindex-3

private RestHighLevelClient osClient;

@Test  
public void t0030_bulkWithRequireAliasOnEachRequestUsingGlobalIndex() {  
    String indexAliasName = "testindex-3";  
    try {  
        BulkRequest bulkRequest = new BulkRequest(indexAliasName);  
        bulkRequest.add(new IndexRequest().id("1").setRequireAlias(true).source("{ \"name\": \"Biden\" }", XContentType.JSON));  
        bulkRequest.add(new IndexRequest().id("2").setRequireAlias(true).source("{ \"name\": \"Trump\" }", XContentType.JSON));  
  
        BulkResponse bulkResponse = osClient.bulk(bulkRequest, RequestOptions.DEFAULT);  
  
        assertFalse(existsIndex(indexAliasName), "Should not auto-create the index.");  
        assertTrue(bulkResponse.hasFailures(), "Bulk response must have failures.");  
    } catch (Exception ex) {  
        Assert.fail("Must not throw an exception");  
    }  
}

Fail 4: Auto creates the index testindex-4

private RestHighLevelClient osClient;

@Test  
public void t0040_bulkWithRequireAliasOnEachRequest() {  
    String indexAliasName = "testindex-4";  
    try {  
        BulkRequest bulkRequest = new BulkRequest();  
        bulkRequest.add(new IndexRequest().index(indexAliasName).id("1").setRequireAlias(true).source("{ \"name\": \"Biden\" }", XContentType.JSON));  
        bulkRequest.add(new IndexRequest().index(indexAliasName).id("2").setRequireAlias(true).source("{ \"name\": \"Trump\" }", XContentType.JSON));  
  
        BulkResponse bulkResponse = osClient.bulk(bulkRequest, RequestOptions.DEFAULT);  
  
        assertFalse(existsIndex(indexAliasName), "Should not auto-create the index.");  
        assertTrue(bulkResponse.hasFailures(), "Bulk response must have failures.");  
    } catch (Exception ex) {  
        Assert.fail("Must not throw an exception");  
    }  
}

Expected behavior

At the moment the 'require alias' flag does not get transferred from the high-level REST client to OpenSearch and OpenSearch automatically creates the index with the name of the alias. This should not happen. It should fail in case there is no index with the alias.

Logged call from the first example (Fail 1):

[TRACE] 2024-03-28 07:34:52.579 [main] tracer - curl -iX POST 'http://localhost:32787/_bulk?timeout=1m' -d '{"index":{"_index":"testindex-1","_id":"1"}}
{"name":"Biden"}
{"index":{"_index":"testindex-1","_id":"2"}}
{"name":"Trump"}
'
# HTTP/1.1 200 OK
# content-type: application/json; charset=UTF-8
# content-length: 373
#
# {"took":192,"errors":false,"items":[{"index":{"_index":"testindex-1","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1,"status":201}},{"index":{"_index":"testindex-1","_id":"2","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":1,"_primary_term":1,"status":201}}]}

Additional Details

Belongs to OpenSearch 2.12.0.

Btw. require alias works fine for single IndexRequest calls, thanks to this fix: #1528

private RestHighLevelClient osClient;

@Test  
public void t0060_singleIndexRequest() {  
    String indexAliasName = "testindex-5";  
    try {  
        IndexRequest indexRequest = new IndexRequest(indexAliasName)  
                .id("1")  
                .setRequireAlias(true)  
                .source("{ \"name\": \"Biden\" }", XContentType.JSON);  
  
        IndexResponse indexResponse = osClient.index(indexRequest, RequestOptions.DEFAULT);  
        Assert.fail("Must throw an exception in the line above.");  
    } catch (OpenSearchStatusException ex) {  
        assertEquals(RestStatus.NOT_FOUND, ex.status(), "Index must not found (= must not automatically created)");  
    } catch (Exception ex) {  
        Assert.fail("Must not throw this kind of exception");  
    }  
}

or when the bulk request gets called by hand

private RestHighLevelClient osClient;

@Test  
public void t0050_byHandBulkWithRequireAlias() {  
    String indexAliasName = "testindex-6";  
    try {  
        String jsonString = """  
			{ "index" : { "_id" : "1" } }                    
			{ "name": "Biden" }
			{ "index" : { "_id" : "2" } }
			{ "name": "Trump" }
		""";  
  
        Request request = new Request("PUT", "/" + indexAliasName + "/_bulk");  
        request.addParameter("require_alias", "true");  
        request.setJsonEntity(jsonString);  
  
        Response bulkResponse = osClient.getLowLevelClient().performRequest(request);  
  
        assertFalse(existsIndex(indexAliasName), "Should not auto-create the index.");  
		String responseString = EntityUtils.toString(bulkResponse.getEntity());  
		assertTrue(responseString.contains("[require_alias]"));
	} catch (Exception ex) {  
        Assert.fail("Must not throw an exception");  
    }  
}

Example content from 'responseString'

{"took":2,"errors":true,"items":[{"index":{"_index":"testindex-6","_id":"1","status":404,"error":{"type":"index_not_found_exception","reason":"no such index [testindex-6] and [require_alias] request flag is [true] and [testindex-6] is not an alias","index":"testindex-6","index_uuid":"_na_"}}},{"index":{"_index":"testindex-6","_id":"2","status":404,"error":{"type":"index_not_found_exception","reason":"no such index [testindex-6] and [require_alias] request flag is [true] and [testindex-6] is not an alias","index":"testindex-6","index_uuid":"_na_"}}}]}

Metadata

Metadata

Assignees

Labels

ClientsClients within the Core repository such as High level Rest client and low level clientbugSomething isn't workinggood first issueGood for newcomersv2.15.0Issues and PRs related to version 2.15.0v3.0.0Issues and PRs related to version 3.0.0

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions