mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-28 09:28:55 -04:00
Synonyms API - Add refresh parameter to check synonyms index and reload analyzers (#126935)
* Add timeout to SynonymsManagementAPIService put synonyms
* Remove replicas 0, as that may impact serverless
* Add timeout to put synonyms action, fix tests
* Fix number of replicas
* Remove cluster.health checks for synonyms index
* Revert debugging
* Add integration test for timeouts
* Use TimeValue instead of an int
* Add YAML tests and REST API specs
* Fix a validation bug in put synonym rule
* Spotless
* Update docs/changelog/126314.yaml
* Remove unnecessary checks for null
* Fix equals / HashCode
* Checks that timeout is passed correctly to the check health method
* Use correctly the default timeout
* spotless
* Add monitor cluster privilege to internal synonyms user
* [CI] Auto commit changes from spotless
* Add capabilities to avoid failing on bwc tests
* Replace timeout for refresh param
* Add param to specs
* Add YAML tests
* Fix changelog
* [CI] Auto commit changes from spotless
* Use BWC serialization tests
* Fix bug in test parser
* Spotless
* Delete doesn't need reloading 🤦 removing it
* Revert "Delete doesn't need reloading 🤦 removing it"
This reverts commit 9c8e0b62be
.
* [CI] Auto commit changes from spotless
* Fix refresh for delete synonym rule
* Fix tests
* Update docs/changelog/126935.yaml
* Add reload analyzers test
* reload_analyzers is not available on serverless
---------
Co-authored-by: elasticsearchmachine <infra-root+elasticsearchmachine@elastic.co>
This commit is contained in:
parent
2ea04a9fed
commit
4d4b962fd1
35 changed files with 719 additions and 191 deletions
6
docs/changelog/126314.yaml
Normal file
6
docs/changelog/126314.yaml
Normal file
|
@ -0,0 +1,6 @@
|
|||
pr: 126314
|
||||
summary: Add refresh to synonyms put / delete APIs to wait for synonyms to be accessible and reload analyzers
|
||||
area: Analysis
|
||||
type: bug
|
||||
issues:
|
||||
- 121441
|
6
docs/changelog/126935.yaml
Normal file
6
docs/changelog/126935.yaml
Normal file
|
@ -0,0 +1,6 @@
|
|||
pr: 126935
|
||||
summary: Synonyms API - Add refresh parameter to check synonyms index and reload analyzers
|
||||
area: Analysis
|
||||
type: enhancement
|
||||
issues:
|
||||
- 121441
|
|
@ -33,6 +33,12 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"refresh": {
|
||||
"type": "boolean",
|
||||
"description": "Refresh search analyzers to update synonyms"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"refresh": {
|
||||
"type": "boolean",
|
||||
"description": "Refresh search analyzers to update synonyms"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"description": "Synonyms set rules",
|
||||
"required": true
|
||||
|
|
|
@ -34,6 +34,12 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"refresh": {
|
||||
"type": "boolean",
|
||||
"description": "Refresh search analyzers to update synonyms"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"description": "Synonym rule",
|
||||
"required": true
|
||||
|
|
|
@ -15,11 +15,6 @@ setup:
|
|||
|
||||
- match: { result: "created" }
|
||||
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
- do:
|
||||
synonyms.get_synonym:
|
||||
id: test-update-synonyms
|
||||
|
@ -63,11 +58,6 @@ setup:
|
|||
|
||||
- match: { result: "created" }
|
||||
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
- do:
|
||||
synonyms.get_synonym:
|
||||
id: test-empty-synonyms
|
||||
|
@ -75,6 +65,31 @@ setup:
|
|||
- match: { count: 0 }
|
||||
- match: { synonyms_set: [] }
|
||||
|
||||
---
|
||||
"Refresh can be specified":
|
||||
|
||||
- requires:
|
||||
test_runner_features: [ capabilities ]
|
||||
capabilities:
|
||||
- method: PUT
|
||||
path: /_synonyms/{rule_id}
|
||||
capabilities: [ synonyms_refresh_param ]
|
||||
reason: "synonyms refresh param capability needed"
|
||||
|
||||
- do:
|
||||
synonyms.put_synonym:
|
||||
id: test-update-synonyms
|
||||
refresh: false
|
||||
body:
|
||||
synonyms_set:
|
||||
- synonyms: "hello, hi"
|
||||
- synonyms: "bye => goodbye"
|
||||
id: "test-id"
|
||||
|
||||
- match: { result: "created" }
|
||||
# Reload analyzers info is not included
|
||||
- not_exists: reload_analyzers_details
|
||||
|
||||
---
|
||||
"Validation fails tests":
|
||||
- do:
|
||||
|
@ -116,3 +131,4 @@ setup:
|
|||
body:
|
||||
synonyms_set:
|
||||
- synonyms: "bye, goodbye, "
|
||||
|
||||
|
|
|
@ -11,12 +11,6 @@ setup:
|
|||
synonyms_set:
|
||||
synonyms: "foo => bar, baz"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
- do:
|
||||
indices.create:
|
||||
index: test_index
|
||||
|
@ -372,13 +366,6 @@ setup:
|
|||
synonyms_set:
|
||||
synonyms: "foo => bar, baz"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
|
||||
- do:
|
||||
indices.stats: { index: test_index }
|
||||
|
||||
|
@ -441,12 +428,6 @@ setup:
|
|||
synonyms_set:
|
||||
synonyms: "foo => bar, baz"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
- do:
|
||||
# Warning issued in previous versions
|
||||
allowed_warnings:
|
||||
|
|
|
@ -14,12 +14,6 @@ setup:
|
|||
- synonyms: "test => check"
|
||||
id: "test-id-3"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
---
|
||||
"Get synonyms set":
|
||||
- do:
|
||||
|
|
|
@ -12,12 +12,6 @@ setup:
|
|||
- synonyms: "bye => goodbye"
|
||||
id: "test-id-2"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
---
|
||||
"Delete synonyms set":
|
||||
- do:
|
||||
|
@ -77,7 +71,6 @@ setup:
|
|||
settings:
|
||||
index:
|
||||
number_of_shards: 1
|
||||
number_of_replicas: 0
|
||||
analysis:
|
||||
filter:
|
||||
my_synonym_filter:
|
||||
|
|
|
@ -10,12 +10,6 @@ setup:
|
|||
- synonyms: "hello, hi"
|
||||
- synonyms: "goodbye, bye"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
- do:
|
||||
synonyms.put_synonym:
|
||||
id: test-synonyms-1
|
||||
|
|
|
@ -14,12 +14,6 @@ setup:
|
|||
- synonyms: "test => check"
|
||||
id: "test-id-3"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
---
|
||||
"Update a synonyms rule":
|
||||
- do:
|
||||
|
@ -85,3 +79,68 @@ setup:
|
|||
rule_id: "test-id-0"
|
||||
body:
|
||||
synonyms: "i-phone, iphone"
|
||||
|
||||
---
|
||||
"Refresh can be specified":
|
||||
|
||||
- requires:
|
||||
test_runner_features: [ capabilities ]
|
||||
capabilities:
|
||||
- method: PUT
|
||||
path: /_synonyms/{rule_id}
|
||||
capabilities: [ synonyms_refresh_param ]
|
||||
reason: "synonyms refresh param capability needed"
|
||||
|
||||
- do:
|
||||
synonyms.put_synonym_rule:
|
||||
refresh: false
|
||||
set_id: "test-synonyms"
|
||||
rule_id: "test-id-2"
|
||||
body:
|
||||
synonyms: "bye, goodbye, seeya"
|
||||
|
||||
- match: { result: "updated" }
|
||||
# Reload analyzers info is not included
|
||||
- not_exists: reload_analyzers_details
|
||||
|
||||
---
|
||||
"Validation failure tests":
|
||||
- do:
|
||||
catch: /\[synonyms\] field can't be empty/
|
||||
synonyms.put_synonym_rule:
|
||||
set_id: "test-synonyms"
|
||||
rule_id: "test-id-0"
|
||||
body:
|
||||
synonyms: ""
|
||||
|
||||
- do:
|
||||
catch: /More than one explicit mapping specified in the same synonyms rule/
|
||||
synonyms.put_synonym_rule:
|
||||
set_id: "test-synonyms"
|
||||
rule_id: "test-id-0"
|
||||
body:
|
||||
synonyms: "bye => => goodbye"
|
||||
|
||||
- do:
|
||||
catch: /Incorrect syntax for \[synonyms\]/
|
||||
synonyms.put_synonym_rule:
|
||||
set_id: "test-synonyms"
|
||||
rule_id: "test-id-0"
|
||||
body:
|
||||
synonyms: " => goodbye"
|
||||
|
||||
- do:
|
||||
catch: /Incorrect syntax for \[synonyms\]/
|
||||
synonyms.put_synonym_rule:
|
||||
set_id: "test-synonyms"
|
||||
rule_id: "test-id-0"
|
||||
body:
|
||||
synonyms: "bye => "
|
||||
|
||||
- do:
|
||||
catch: /Incorrect syntax for \[synonyms\]/
|
||||
synonyms.put_synonym_rule:
|
||||
set_id: "test-synonyms"
|
||||
rule_id: "test-id-0"
|
||||
body:
|
||||
synonyms: "bye, goodbye, "
|
||||
|
|
|
@ -14,12 +14,6 @@ setup:
|
|||
- synonyms: "test => check"
|
||||
id: "test-id-3"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
---
|
||||
"Get a synonym rule":
|
||||
- do:
|
||||
|
|
|
@ -14,12 +14,6 @@ setup:
|
|||
- synonyms: "test => check"
|
||||
id: "test-id-3"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
---
|
||||
"Delete synonym rule":
|
||||
- do:
|
||||
|
@ -50,6 +44,27 @@ setup:
|
|||
- synonyms: "test => check"
|
||||
id: "test-id-3"
|
||||
|
||||
---
|
||||
"Refresh can be specified":
|
||||
|
||||
- requires:
|
||||
test_runner_features: [ capabilities ]
|
||||
capabilities:
|
||||
- method: PUT
|
||||
path: /_synonyms/{rule_id}
|
||||
capabilities: [ synonyms_refresh_param ]
|
||||
reason: "synonyms refresh param capability needed"
|
||||
|
||||
- do:
|
||||
synonyms.delete_synonym_rule:
|
||||
set_id: test-synonyms
|
||||
rule_id: test-id-2
|
||||
refresh: false
|
||||
|
||||
- match: { result: "deleted" }
|
||||
# Reload analyzers info is not included
|
||||
- not_exists: reload_analyzers_details
|
||||
|
||||
---
|
||||
"Delete synonym rule - missing synonym set":
|
||||
- do:
|
||||
|
|
|
@ -13,12 +13,6 @@ setup:
|
|||
- synonyms: "bye => goodbye"
|
||||
id: "synonym-rule-2"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
# Create an index with synonym_filter that uses that synonyms set
|
||||
- do:
|
||||
indices.create:
|
||||
|
|
|
@ -14,12 +14,6 @@ setup:
|
|||
- synonyms: "bye => goodbye"
|
||||
id: "synonym-rule-2"
|
||||
|
||||
# This is to ensure that all index shards (write and read) are available. In serverless this can take some time.
|
||||
- do:
|
||||
cluster.health:
|
||||
index: .synonyms
|
||||
wait_for_status: green
|
||||
|
||||
# Create synonyms synonyms_set2
|
||||
- do:
|
||||
synonyms.put_synonym:
|
||||
|
@ -156,3 +150,62 @@ setup:
|
|||
my_field:
|
||||
query: salute
|
||||
- match: { hits.total.value: 0 }
|
||||
|
||||
---
|
||||
"Reload analyzers with refresh false":
|
||||
- requires:
|
||||
test_runner_features: [ capabilities ]
|
||||
capabilities:
|
||||
- method: PUT
|
||||
path: /_synonyms/{rule_id}
|
||||
capabilities: [ synonyms_refresh_param ]
|
||||
reason: "synonyms refresh param capability needed"
|
||||
|
||||
- do:
|
||||
synonyms.put_synonym:
|
||||
id: synonyms_set1
|
||||
refresh: false
|
||||
body:
|
||||
synonyms_set:
|
||||
- synonyms: "hello, salute"
|
||||
|
||||
- match: { result: "updated" }
|
||||
- not_exists: reload_analyzers_details
|
||||
|
||||
# Confirm that the index analyzers are not reloaded for my_index1
|
||||
- do:
|
||||
search:
|
||||
index: my_index1
|
||||
body:
|
||||
query:
|
||||
match:
|
||||
my_field:
|
||||
query: salute
|
||||
- match: { hits.total.value: 0 }
|
||||
|
||||
# Reloading analyzers makes synonyms refresh
|
||||
- do:
|
||||
synonyms.put_synonym:
|
||||
id: synonyms_set1
|
||||
refresh: true
|
||||
body:
|
||||
synonyms_set:
|
||||
- synonyms: "hello, salute"
|
||||
- synonyms: "ciao => goodbye"
|
||||
|
||||
- match: { result: "updated" }
|
||||
- gt: { reload_analyzers_details._shards.total: 0 }
|
||||
- gt: { reload_analyzers_details._shards.successful: 0 }
|
||||
- length: { reload_analyzers_details.reload_details: 1 }
|
||||
|
||||
- do:
|
||||
search:
|
||||
index: my_index1
|
||||
body:
|
||||
query:
|
||||
match:
|
||||
my_field:
|
||||
query: salute
|
||||
|
||||
- match: { hits.total.value: 1 }
|
||||
|
||||
|
|
|
@ -11,8 +11,12 @@ package org.elasticsearch.synonyms;
|
|||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.index.mapper.extras.MapperExtrasPlugin;
|
||||
import org.elasticsearch.indices.IndexCreationException;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.reindex.ReindexPlugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
|
@ -50,22 +54,29 @@ public class SynonymsManagementAPIServiceIT extends ESIntegTestCase {
|
|||
public void testCreateManySynonyms() throws Exception {
|
||||
CountDownLatch putLatch = new CountDownLatch(1);
|
||||
String synonymSetId = randomIdentifier();
|
||||
boolean refresh = randomBoolean();
|
||||
int rulesNumber = randomIntBetween(maxSynonymSets / 2, maxSynonymSets);
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, randomSynonymsSet(rulesNumber, rulesNumber), new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
assertEquals(
|
||||
SynonymsManagementAPIService.UpdateSynonymsResultStatus.CREATED,
|
||||
synonymsReloadResult.synonymsOperationResult()
|
||||
);
|
||||
putLatch.countDown();
|
||||
}
|
||||
synonymsManagementAPIService.putSynonymsSet(
|
||||
synonymSetId,
|
||||
randomSynonymsSet(rulesNumber, rulesNumber),
|
||||
refresh,
|
||||
new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
assertEquals(
|
||||
SynonymsManagementAPIService.UpdateSynonymsResultStatus.CREATED,
|
||||
synonymsReloadResult.synonymsOperationResult()
|
||||
);
|
||||
assertEquals(refresh, synonymsReloadResult.reloadAnalyzersResponse() != null);
|
||||
putLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
fail(e);
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
putLatch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
|
@ -95,6 +106,7 @@ public class SynonymsManagementAPIServiceIT extends ESIntegTestCase {
|
|||
synonymsManagementAPIService.putSynonymsSet(
|
||||
randomIdentifier(),
|
||||
randomSynonymsSet(maxSynonymSets + 1, maxSynonymSets * 2),
|
||||
randomBoolean(),
|
||||
new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
|
@ -120,67 +132,73 @@ public class SynonymsManagementAPIServiceIT extends ESIntegTestCase {
|
|||
int rulesToUpdate = randomIntBetween(1, 10);
|
||||
int synonymsToCreate = maxSynonymSets - rulesToUpdate;
|
||||
String synonymSetId = randomIdentifier();
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, randomSynonymsSet(synonymsToCreate), new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
// Create as many rules as should fail
|
||||
SynonymRule[] rules = randomSynonymsSet(atLeast(rulesToUpdate + 1));
|
||||
CountDownLatch updatedRulesLatch = new CountDownLatch(rulesToUpdate);
|
||||
for (int i = 0; i < rulesToUpdate; i++) {
|
||||
synonymsManagementAPIService.putSynonymRule(synonymSetId, rules[i], new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
updatedRulesLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
try {
|
||||
updatedRulesLatch.await(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
fail(e);
|
||||
}
|
||||
|
||||
// Updating more rules fails
|
||||
int rulesToInsert = rules.length - rulesToUpdate;
|
||||
CountDownLatch insertRulesLatch = new CountDownLatch(rulesToInsert);
|
||||
for (int i = rulesToUpdate; i < rulesToInsert; i++) {
|
||||
synonymsManagementAPIService.putSynonymRule(
|
||||
// Error here
|
||||
synonymSetId,
|
||||
rules[i],
|
||||
new ActionListener<>() {
|
||||
synonymsManagementAPIService.putSynonymsSet(
|
||||
synonymSetId,
|
||||
randomSynonymsSet(synonymsToCreate),
|
||||
randomBoolean(),
|
||||
new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
// Create as many rules as should fail
|
||||
SynonymRule[] rules = randomSynonymsSet(atLeast(rulesToUpdate + 1));
|
||||
CountDownLatch updatedRulesLatch = new CountDownLatch(rulesToUpdate);
|
||||
for (int i = 0; i < rulesToUpdate; i++) {
|
||||
synonymsManagementAPIService.putSynonymRule(synonymSetId, rules[i], true, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
fail("Shouldn't have been able to update a rule");
|
||||
updatedRulesLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
if (e instanceof IllegalArgumentException == false) {
|
||||
fail(e);
|
||||
}
|
||||
updatedRulesLatch.countDown();
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
try {
|
||||
updatedRulesLatch.await(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
fail(e);
|
||||
}
|
||||
|
||||
// Updating more rules fails
|
||||
int rulesToInsert = rules.length - rulesToUpdate;
|
||||
CountDownLatch insertRulesLatch = new CountDownLatch(rulesToInsert);
|
||||
for (int i = rulesToUpdate; i < rulesToInsert; i++) {
|
||||
synonymsManagementAPIService.putSynonymRule(
|
||||
// Error here
|
||||
synonymSetId,
|
||||
rules[i],
|
||||
randomBoolean(),
|
||||
new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
fail("Shouldn't have been able to update a rule");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
if (e instanceof IllegalArgumentException == false) {
|
||||
fail(e);
|
||||
}
|
||||
updatedRulesLatch.countDown();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
try {
|
||||
insertRulesLatch.await(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
insertRulesLatch.await(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
latch.await(5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
@ -189,13 +207,14 @@ public class SynonymsManagementAPIServiceIT extends ESIntegTestCase {
|
|||
CountDownLatch latch = new CountDownLatch(1);
|
||||
String synonymSetId = randomIdentifier();
|
||||
SynonymRule[] synonymsSet = randomSynonymsSet(maxSynonymSets, maxSynonymSets);
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, synonymsSet, new ActionListener<>() {
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, synonymsSet, true, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
// Updating a rule fails
|
||||
synonymsManagementAPIService.putSynonymRule(
|
||||
synonymSetId,
|
||||
synonymsSet[randomIntBetween(0, maxSynonymSets - 1)],
|
||||
randomBoolean(),
|
||||
new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
|
@ -224,11 +243,11 @@ public class SynonymsManagementAPIServiceIT extends ESIntegTestCase {
|
|||
String synonymSetId = randomIdentifier();
|
||||
String ruleId = randomIdentifier();
|
||||
SynonymRule[] synonymsSet = randomSynonymsSet(maxSynonymSets, maxSynonymSets);
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, synonymsSet, new ActionListener<>() {
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, synonymsSet, randomBoolean(), new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
// Updating a rule fails
|
||||
synonymsManagementAPIService.putSynonymRule(synonymSetId, randomSynonymRule(ruleId), new ActionListener<>() {
|
||||
synonymsManagementAPIService.putSynonymRule(synonymSetId, randomSynonymRule(ruleId), true, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
fail("Should not create a new rule that does not exist when at max capacity");
|
||||
|
@ -289,4 +308,113 @@ public class SynonymsManagementAPIServiceIT extends ESIntegTestCase {
|
|||
readLatch.await(5, TimeUnit.SECONDS);
|
||||
verify(logger).warn(anyString(), eq(synonymSetId));
|
||||
}
|
||||
|
||||
public void testCreateSynonymsWithYellowSynonymsIndex() throws Exception {
|
||||
|
||||
// Override health method check to simulate a timeout in checking the synonyms index
|
||||
synonymsManagementAPIService = new SynonymsManagementAPIService(client()) {
|
||||
@Override
|
||||
void checkSynonymsIndexHealth(ActionListener<ClusterHealthResponse> listener) {
|
||||
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).build();
|
||||
ClusterHealthResponse response = new ClusterHealthResponse(
|
||||
randomIdentifier(),
|
||||
new String[] { SynonymsManagementAPIService.SYNONYMS_INDEX_CONCRETE_NAME },
|
||||
clusterState
|
||||
);
|
||||
response.setTimedOut(true);
|
||||
listener.onResponse(response);
|
||||
}
|
||||
};
|
||||
|
||||
// Create a rule fails
|
||||
CountDownLatch putLatch = new CountDownLatch(1);
|
||||
String synonymSetId = randomIdentifier();
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, randomSynonymsSet(1, 1), true, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
fail("Shouldn't have been able to create synonyms with refresh in synonyms index health");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// Expected
|
||||
assertTrue(e instanceof IndexCreationException);
|
||||
assertTrue(e.getMessage().contains("synonyms index [.synonyms] is not searchable"));
|
||||
putLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
putLatch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
// Update a rule fails
|
||||
CountDownLatch updateLatch = new CountDownLatch(1);
|
||||
String synonymRuleId = randomIdentifier();
|
||||
synonymsManagementAPIService.putSynonymRule(synonymSetId, randomSynonymRule(synonymRuleId), true, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
fail("Shouldn't have been able to update synonyms with refresh in synonyms index health");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// Expected
|
||||
assertTrue(e instanceof IndexCreationException);
|
||||
assertTrue(e.getMessage().contains("synonyms index [.synonyms] is not searchable"));
|
||||
updateLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
updateLatch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
// Delete a rule does not fail
|
||||
CountDownLatch deleteLatch = new CountDownLatch(1);
|
||||
synonymsManagementAPIService.deleteSynonymRule(synonymSetId, synonymRuleId, true, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
updateLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// Expected
|
||||
fail("Should have been able to delete a synonym rule");
|
||||
}
|
||||
});
|
||||
|
||||
deleteLatch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
// But, we can still create a synonyms set without refresh
|
||||
CountDownLatch putNoRefreshLatch = new CountDownLatch(1);
|
||||
synonymsManagementAPIService.putSynonymsSet(synonymSetId, randomSynonymsSet(1, 1), false, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
// Expected
|
||||
putLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
});
|
||||
|
||||
putNoRefreshLatch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
// Same for update
|
||||
CountDownLatch putRuleNoRefreshLatch = new CountDownLatch(1);
|
||||
synonymsManagementAPIService.putSynonymRule(synonymSetId, randomSynonymRule(synonymRuleId), false, new ActionListener<>() {
|
||||
@Override
|
||||
public void onResponse(SynonymsManagementAPIService.SynonymsReloadResult synonymsReloadResult) {
|
||||
// Expected
|
||||
putRuleNoRefreshLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
fail(e);
|
||||
}
|
||||
});
|
||||
|
||||
putRuleNoRefreshLatch.await(5, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,6 +232,7 @@ public class TransportVersions {
|
|||
public static final TransportVersion BATCHED_QUERY_EXECUTION_DELAYABLE_WRITABLE = def(9_057_0_00);
|
||||
public static final TransportVersion SEARCH_INCREMENTAL_TOP_DOCS_NULL = def(9_058_0_00);
|
||||
public static final TransportVersion COMPRESS_DELAYABLE_WRITEABLE = def(9_059_0_00);
|
||||
public static final TransportVersion SYNONYMS_REFRESH_PARAM = def(9_060_0_00);
|
||||
|
||||
/*
|
||||
* STOP! READ THIS FIRST! No, really,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
package org.elasticsearch.action.synonyms;
|
||||
|
||||
import org.elasticsearch.TransportVersions;
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ActionType;
|
||||
|
@ -31,18 +32,24 @@ public class DeleteSynonymRuleAction extends ActionType<SynonymUpdateResponse> {
|
|||
|
||||
public static class Request extends ActionRequest {
|
||||
private final String synonymsSetId;
|
||||
|
||||
private final String synonymRuleId;
|
||||
private final boolean refresh;
|
||||
|
||||
public Request(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
this.synonymsSetId = in.readString();
|
||||
this.synonymRuleId = in.readString();
|
||||
if (in.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
this.refresh = in.readBoolean();
|
||||
} else {
|
||||
this.refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Request(String synonymsSetId, String synonymRuleId) {
|
||||
public Request(String synonymsSetId, String synonymRuleId, boolean refresh) {
|
||||
this.synonymsSetId = synonymsSetId;
|
||||
this.synonymRuleId = synonymRuleId;
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,6 +70,9 @@ public class DeleteSynonymRuleAction extends ActionType<SynonymUpdateResponse> {
|
|||
super.writeTo(out);
|
||||
out.writeString(synonymsSetId);
|
||||
out.writeString(synonymRuleId);
|
||||
if (out.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
out.writeBoolean(refresh);
|
||||
}
|
||||
}
|
||||
|
||||
public String synonymsSetId() {
|
||||
|
@ -73,6 +83,10 @@ public class DeleteSynonymRuleAction extends ActionType<SynonymUpdateResponse> {
|
|||
return synonymRuleId;
|
||||
}
|
||||
|
||||
public boolean refresh() {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
package org.elasticsearch.action.synonyms;
|
||||
|
||||
import org.elasticsearch.TransportVersions;
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ActionType;
|
||||
|
@ -40,8 +41,8 @@ public class PutSynonymRuleAction extends ActionType<SynonymUpdateResponse> {
|
|||
|
||||
public static class Request extends ActionRequest {
|
||||
private final String synonymsSetId;
|
||||
|
||||
private final SynonymRule synonymRule;
|
||||
private final boolean refresh;
|
||||
|
||||
public static final ParseField SYNONYMS_FIELD = new ParseField(SynonymsManagementAPIService.SYNONYMS_FIELD);
|
||||
private static final ConstructingObjectParser<SynonymRule, String> PARSER = new ConstructingObjectParser<>(
|
||||
|
@ -58,20 +59,28 @@ public class PutSynonymRuleAction extends ActionType<SynonymUpdateResponse> {
|
|||
super(in);
|
||||
this.synonymsSetId = in.readString();
|
||||
this.synonymRule = new SynonymRule(in);
|
||||
if (in.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
this.refresh = in.readBoolean();
|
||||
} else {
|
||||
this.refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Request(String synonymsSetId, String synonymRuleId, BytesReference content, XContentType contentType) throws IOException {
|
||||
public Request(String synonymsSetId, String synonymRuleId, boolean refresh, BytesReference content, XContentType contentType)
|
||||
throws IOException {
|
||||
this.synonymsSetId = synonymsSetId;
|
||||
try (XContentParser parser = XContentHelper.createParser(XContentParserConfiguration.EMPTY, content, contentType)) {
|
||||
this.synonymRule = PARSER.apply(parser, synonymRuleId);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Failed to parse: " + content.utf8ToString(), e);
|
||||
}
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
Request(String synonymsSetId, SynonymRule synonymRule) {
|
||||
Request(String synonymsSetId, SynonymRule synonymRule, boolean refresh) {
|
||||
this.synonymsSetId = synonymsSetId;
|
||||
this.synonymRule = synonymRule;
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,6 +105,9 @@ public class PutSynonymRuleAction extends ActionType<SynonymUpdateResponse> {
|
|||
super.writeTo(out);
|
||||
out.writeString(synonymsSetId);
|
||||
synonymRule.writeTo(out);
|
||||
if (out.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
out.writeBoolean(refresh);
|
||||
}
|
||||
}
|
||||
|
||||
public String synonymsSetId() {
|
||||
|
@ -106,17 +118,23 @@ public class PutSynonymRuleAction extends ActionType<SynonymUpdateResponse> {
|
|||
return synonymRule;
|
||||
}
|
||||
|
||||
public boolean refresh() {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Request request = (Request) o;
|
||||
return Objects.equals(synonymsSetId, request.synonymsSetId) && Objects.equals(synonymRule, request.synonymRule);
|
||||
return Objects.equals(refresh, request.refresh)
|
||||
&& Objects.equals(synonymsSetId, request.synonymsSetId)
|
||||
&& Objects.equals(synonymRule, request.synonymRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(synonymsSetId, synonymRule);
|
||||
return Objects.hash(synonymsSetId, synonymRule, refresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
package org.elasticsearch.action.synonyms;
|
||||
|
||||
import org.elasticsearch.TransportVersions;
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ActionType;
|
||||
|
@ -43,6 +44,7 @@ public class PutSynonymsAction extends ActionType<SynonymUpdateResponse> {
|
|||
public static class Request extends ActionRequest {
|
||||
private final String synonymsSetId;
|
||||
private final SynonymRule[] synonymRules;
|
||||
private final boolean refresh;
|
||||
|
||||
public static final ParseField SYNONYMS_SET_FIELD = new ParseField(SynonymsManagementAPIService.SYNONYMS_SET_FIELD);
|
||||
private static final ConstructingObjectParser<SynonymRule[], Void> PARSER = new ConstructingObjectParser<>("synonyms_set", args -> {
|
||||
|
@ -59,10 +61,16 @@ public class PutSynonymsAction extends ActionType<SynonymUpdateResponse> {
|
|||
super(in);
|
||||
this.synonymsSetId = in.readString();
|
||||
this.synonymRules = in.readArray(SynonymRule::new, SynonymRule[]::new);
|
||||
if (in.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
this.refresh = in.readBoolean();
|
||||
} else {
|
||||
this.refresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
public Request(String synonymsSetId, BytesReference content, XContentType contentType) throws IOException {
|
||||
public Request(String synonymsSetId, boolean refresh, BytesReference content, XContentType contentType) throws IOException {
|
||||
this.synonymsSetId = synonymsSetId;
|
||||
this.refresh = refresh;
|
||||
try (XContentParser parser = XContentHelper.createParser(XContentParserConfiguration.EMPTY, content, contentType)) {
|
||||
this.synonymRules = PARSER.apply(parser, null);
|
||||
} catch (Exception e) {
|
||||
|
@ -70,9 +78,10 @@ public class PutSynonymsAction extends ActionType<SynonymUpdateResponse> {
|
|||
}
|
||||
}
|
||||
|
||||
Request(String synonymsSetId, SynonymRule[] synonymRules) {
|
||||
Request(String synonymsSetId, SynonymRule[] synonymRules, boolean refresh) {
|
||||
this.synonymsSetId = synonymsSetId;
|
||||
this.synonymRules = synonymRules;
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,12 +104,19 @@ public class PutSynonymsAction extends ActionType<SynonymUpdateResponse> {
|
|||
super.writeTo(out);
|
||||
out.writeString(synonymsSetId);
|
||||
out.writeArray(synonymRules);
|
||||
if (out.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
out.writeBoolean(refresh);
|
||||
}
|
||||
}
|
||||
|
||||
public String synonymsSetId() {
|
||||
return synonymsSetId;
|
||||
}
|
||||
|
||||
public boolean refresh() {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
public SynonymRule[] synonymRules() {
|
||||
return synonymRules;
|
||||
}
|
||||
|
@ -110,12 +126,14 @@ public class PutSynonymsAction extends ActionType<SynonymUpdateResponse> {
|
|||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Request request = (Request) o;
|
||||
return Objects.equals(synonymsSetId, request.synonymsSetId) && Arrays.equals(synonymRules, request.synonymRules);
|
||||
return Objects.equals(refresh, request.refresh)
|
||||
&& Objects.equals(synonymsSetId, request.synonymsSetId)
|
||||
&& Arrays.equals(synonymRules, request.synonymRules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(synonymsSetId, Arrays.hashCode(synonymRules));
|
||||
return Objects.hash(synonymsSetId, Arrays.hashCode(synonymRules), refresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
package org.elasticsearch.action.synonyms;
|
||||
|
||||
import org.elasticsearch.TransportVersions;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
|
@ -20,17 +21,27 @@ import org.elasticsearch.xcontent.ToXContentObject;
|
|||
import org.elasticsearch.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SynonymUpdateResponse extends ActionResponse implements ToXContentObject {
|
||||
|
||||
public static final String RESULT_FIELD = "result";
|
||||
public static final String RELOAD_ANALYZERS_DETAILS_FIELD = "reload_analyzers_details";
|
||||
static final ReloadAnalyzersResponse EMPTY_RELOAD_ANALYZER_RESPONSE = new ReloadAnalyzersResponse(0, 0, 0, List.of(), Map.of());
|
||||
|
||||
private final UpdateSynonymsResultStatus updateStatus;
|
||||
private final ReloadAnalyzersResponse reloadAnalyzersResponse;
|
||||
|
||||
public SynonymUpdateResponse(StreamInput in) throws IOException {
|
||||
this.updateStatus = in.readEnum(UpdateSynonymsResultStatus.class);
|
||||
this.reloadAnalyzersResponse = new ReloadAnalyzersResponse(in);
|
||||
if (in.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
this.reloadAnalyzersResponse = in.readOptionalWriteable(ReloadAnalyzersResponse::new);
|
||||
} else {
|
||||
this.reloadAnalyzersResponse = new ReloadAnalyzersResponse(in);
|
||||
}
|
||||
}
|
||||
|
||||
public SynonymUpdateResponse(SynonymsReloadResult synonymsReloadResult) {
|
||||
|
@ -38,7 +49,6 @@ public class SynonymUpdateResponse extends ActionResponse implements ToXContentO
|
|||
UpdateSynonymsResultStatus updateStatus = synonymsReloadResult.synonymsOperationResult();
|
||||
Objects.requireNonNull(updateStatus, "Update status must not be null");
|
||||
ReloadAnalyzersResponse reloadResponse = synonymsReloadResult.reloadAnalyzersResponse();
|
||||
Objects.requireNonNull(reloadResponse, "Reload analyzers response must not be null");
|
||||
|
||||
this.updateStatus = updateStatus;
|
||||
this.reloadAnalyzersResponse = reloadResponse;
|
||||
|
@ -48,9 +58,11 @@ public class SynonymUpdateResponse extends ActionResponse implements ToXContentO
|
|||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
{
|
||||
builder.field("result", updateStatus.name().toLowerCase(Locale.ENGLISH));
|
||||
builder.field("reload_analyzers_details");
|
||||
reloadAnalyzersResponse.toXContent(builder, params);
|
||||
builder.field(RESULT_FIELD, updateStatus.name().toLowerCase(Locale.ENGLISH));
|
||||
if (reloadAnalyzersResponse != null) {
|
||||
builder.field(RELOAD_ANALYZERS_DETAILS_FIELD);
|
||||
reloadAnalyzersResponse.toXContent(builder, params);
|
||||
}
|
||||
}
|
||||
builder.endObject();
|
||||
|
||||
|
@ -60,7 +72,16 @@ public class SynonymUpdateResponse extends ActionResponse implements ToXContentO
|
|||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeEnum(updateStatus);
|
||||
reloadAnalyzersResponse.writeTo(out);
|
||||
if (out.getTransportVersion().onOrAfter(TransportVersions.SYNONYMS_REFRESH_PARAM)) {
|
||||
out.writeOptionalWriteable(reloadAnalyzersResponse);
|
||||
} else {
|
||||
if (reloadAnalyzersResponse == null) {
|
||||
// Nulls will be written as empty reload analyzer responses for older versions
|
||||
EMPTY_RELOAD_ANALYZER_RESPONSE.writeTo(out);
|
||||
} else {
|
||||
reloadAnalyzersResponse.writeTo(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RestStatus status() {
|
||||
|
@ -70,6 +91,14 @@ public class SynonymUpdateResponse extends ActionResponse implements ToXContentO
|
|||
};
|
||||
}
|
||||
|
||||
UpdateSynonymsResultStatus updateStatus() {
|
||||
return updateStatus;
|
||||
}
|
||||
|
||||
ReloadAnalyzersResponse reloadAnalyzersResponse() {
|
||||
return reloadAnalyzersResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -41,6 +41,7 @@ public class TransportDeleteSynonymRuleAction extends HandledTransportAction<Del
|
|||
synonymsManagementAPIService.deleteSynonymRule(
|
||||
request.synonymsSetId(),
|
||||
request.synonymRuleId(),
|
||||
request.refresh(),
|
||||
listener.map(SynonymUpdateResponse::new)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ public class TransportPutSynonymRuleAction extends HandledTransportAction<PutSyn
|
|||
synonymsManagementAPIService.putSynonymRule(
|
||||
request.synonymsSetId(),
|
||||
request.synonymRule(),
|
||||
listener.map(updateResponse -> new SynonymUpdateResponse(updateResponse))
|
||||
request.refresh(),
|
||||
listener.map(SynonymUpdateResponse::new)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ public class TransportPutSynonymsAction extends HandledTransportAction<PutSynony
|
|||
synonymsManagementAPIService.putSynonymsSet(
|
||||
request.synonymsSetId(),
|
||||
request.synonymRules(),
|
||||
request.refresh(),
|
||||
listener.map(SynonymUpdateResponse::new)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.elasticsearch.rest.action.RestToXContentListener;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
|
||||
|
||||
|
@ -39,8 +40,14 @@ public class RestDeleteSynonymRuleAction extends BaseRestHandler {
|
|||
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
|
||||
DeleteSynonymRuleAction.Request request = new DeleteSynonymRuleAction.Request(
|
||||
restRequest.param("synonymsSet"),
|
||||
restRequest.param("synonymRuleId")
|
||||
restRequest.param("synonymRuleId"),
|
||||
restRequest.paramAsBoolean("refresh", true)
|
||||
);
|
||||
return channel -> client.execute(DeleteSynonymRuleAction.INSTANCE, request, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedCapabilities() {
|
||||
return SynonymCapabilities.CAPABILITIES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.elasticsearch.rest.action.RestToXContentListener;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
||||
|
||||
|
@ -41,6 +42,7 @@ public class RestPutSynonymRuleAction extends BaseRestHandler {
|
|||
PutSynonymRuleAction.Request request = new PutSynonymRuleAction.Request(
|
||||
restRequest.param("synonymsSet"),
|
||||
restRequest.param("synonymRuleId"),
|
||||
restRequest.paramAsBoolean("refresh", true),
|
||||
restRequest.content(),
|
||||
restRequest.getXContentType()
|
||||
);
|
||||
|
@ -50,4 +52,9 @@ public class RestPutSynonymRuleAction extends BaseRestHandler {
|
|||
new RestToXContentListener<>(channel, SynonymUpdateResponse::status, r -> null)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedCapabilities() {
|
||||
return SynonymCapabilities.CAPABILITIES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.elasticsearch.rest.action.RestToXContentListener;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
||||
|
||||
|
@ -40,6 +41,7 @@ public class RestPutSynonymsAction extends BaseRestHandler {
|
|||
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
|
||||
PutSynonymsAction.Request request = new PutSynonymsAction.Request(
|
||||
restRequest.param("synonymsSet"),
|
||||
restRequest.paramAsBoolean("refresh", true),
|
||||
restRequest.content(),
|
||||
restRequest.getXContentType()
|
||||
);
|
||||
|
@ -49,4 +51,9 @@ public class RestPutSynonymsAction extends BaseRestHandler {
|
|||
new RestToXContentListener<>(channel, SynonymUpdateResponse::status, r -> null)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> supportedCapabilities() {
|
||||
return SynonymCapabilities.CAPABILITIES;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
package org.elasticsearch.rest.action.synonyms;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link Set} of "capabilities" supported by the {@link RestPutSynonymsAction} and {@link RestPutSynonymRuleAction}.
|
||||
*/
|
||||
public final class SynonymCapabilities {
|
||||
|
||||
private SynonymCapabilities() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
private static final String SYNONYMS_REFRESH_PARAM = "synonyms_refresh_param";
|
||||
|
||||
public static final Set<String> CAPABILITIES = Set.of(SYNONYMS_REFRESH_PARAM);
|
||||
}
|
|
@ -19,6 +19,9 @@ import org.elasticsearch.action.ActionListener;
|
|||
import org.elasticsearch.action.DelegatingActionListener;
|
||||
import org.elasticsearch.action.DocWriteRequest;
|
||||
import org.elasticsearch.action.DocWriteResponse;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.admin.cluster.health.TransportClusterHealthAction;
|
||||
import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersRequest;
|
||||
import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse;
|
||||
import org.elasticsearch.action.admin.indices.analyze.TransportReloadAnalyzersAction;
|
||||
|
@ -36,12 +39,14 @@ import org.elasticsearch.client.internal.OriginSettingClient;
|
|||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||
import org.elasticsearch.cluster.routing.Preference;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.core.TimeValue;
|
||||
import org.elasticsearch.index.IndexNotFoundException;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.reindex.BulkByScrollResponse;
|
||||
import org.elasticsearch.index.reindex.DeleteByQueryAction;
|
||||
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||
import org.elasticsearch.indices.IndexCreationException;
|
||||
import org.elasticsearch.indices.SystemIndexDescriptor;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.search.aggregations.BucketOrder;
|
||||
|
@ -72,7 +77,7 @@ public class SynonymsManagementAPIService {
|
|||
|
||||
private static final String SYNONYMS_INDEX_NAME_PATTERN = ".synonyms-*";
|
||||
private static final int SYNONYMS_INDEX_FORMAT = 2;
|
||||
private static final String SYNONYMS_INDEX_CONCRETE_NAME = ".synonyms-" + SYNONYMS_INDEX_FORMAT;
|
||||
static final String SYNONYMS_INDEX_CONCRETE_NAME = ".synonyms-" + SYNONYMS_INDEX_FORMAT;
|
||||
private static final String SYNONYMS_ALIAS_NAME = ".synonyms";
|
||||
public static final String SYNONYMS_FEATURE_NAME = "synonyms";
|
||||
// Stores the synonym set the rule belongs to
|
||||
|
@ -90,6 +95,7 @@ public class SynonymsManagementAPIService {
|
|||
private static final String SYNONYM_RULE_ID_FIELD = SynonymRule.ID_FIELD.getPreferredName();
|
||||
private static final String SYNONYM_SETS_AGG_NAME = "synonym_sets_aggr";
|
||||
private static final int SYNONYMS_INDEX_MAPPINGS_VERSION = 1;
|
||||
public static final int INDEX_SEARCHABLE_TIMEOUT_SECONDS = 30;
|
||||
private final int maxSynonymsSets;
|
||||
|
||||
// Package private for testing
|
||||
|
@ -301,7 +307,12 @@ public class SynonymsManagementAPIService {
|
|||
});
|
||||
}
|
||||
|
||||
public void putSynonymsSet(String synonymSetId, SynonymRule[] synonymsSet, ActionListener<SynonymsReloadResult> listener) {
|
||||
public void putSynonymsSet(
|
||||
String synonymSetId,
|
||||
SynonymRule[] synonymsSet,
|
||||
boolean refresh,
|
||||
ActionListener<SynonymsReloadResult> listener
|
||||
) {
|
||||
if (synonymsSet.length > maxSynonymsSets) {
|
||||
listener.onFailure(
|
||||
new IllegalArgumentException("The number of synonyms rules in a synonym set cannot exceed " + maxSynonymsSets)
|
||||
|
@ -343,7 +354,13 @@ public class SynonymsManagementAPIService {
|
|||
? UpdateSynonymsResultStatus.CREATED
|
||||
: UpdateSynonymsResultStatus.UPDATED;
|
||||
|
||||
reloadAnalyzers(synonymSetId, false, bulkInsertResponseListener, updateSynonymsResultStatus);
|
||||
checkIndexSearchableAndReloadAnalyzers(
|
||||
synonymSetId,
|
||||
refresh,
|
||||
false,
|
||||
updateSynonymsResultStatus,
|
||||
bulkInsertResponseListener
|
||||
);
|
||||
})
|
||||
);
|
||||
}));
|
||||
|
@ -366,7 +383,12 @@ public class SynonymsManagementAPIService {
|
|||
bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).execute(listener);
|
||||
}
|
||||
|
||||
public void putSynonymRule(String synonymsSetId, SynonymRule synonymRule, ActionListener<SynonymsReloadResult> listener) {
|
||||
public void putSynonymRule(
|
||||
String synonymsSetId,
|
||||
SynonymRule synonymRule,
|
||||
boolean refresh,
|
||||
ActionListener<SynonymsReloadResult> listener
|
||||
) {
|
||||
checkSynonymSetExists(synonymsSetId, listener.delegateFailureAndWrap((l1, obj) -> {
|
||||
// Count synonym rules to check if we're at maximum
|
||||
BoolQueryBuilder queryFilter = QueryBuilders.boolQuery()
|
||||
|
@ -388,14 +410,18 @@ public class SynonymsManagementAPIService {
|
|||
new IllegalArgumentException("The number of synonym rules in a synonyms set cannot exceed " + maxSynonymsSets)
|
||||
);
|
||||
} else {
|
||||
indexSynonymRule(synonymsSetId, synonymRule, searchListener);
|
||||
indexSynonymRule(synonymsSetId, synonymRule, refresh, searchListener);
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
private void indexSynonymRule(String synonymsSetId, SynonymRule synonymRule, ActionListener<SynonymsReloadResult> listener)
|
||||
throws IOException {
|
||||
private void indexSynonymRule(
|
||||
String synonymsSetId,
|
||||
SynonymRule synonymRule,
|
||||
boolean refresh,
|
||||
ActionListener<SynonymsReloadResult> listener
|
||||
) throws IOException {
|
||||
IndexRequest indexRequest = createSynonymRuleIndexRequest(synonymsSetId, synonymRule).setRefreshPolicy(
|
||||
WriteRequest.RefreshPolicy.IMMEDIATE
|
||||
);
|
||||
|
@ -404,7 +430,7 @@ public class SynonymsManagementAPIService {
|
|||
? UpdateSynonymsResultStatus.CREATED
|
||||
: UpdateSynonymsResultStatus.UPDATED;
|
||||
|
||||
reloadAnalyzers(synonymsSetId, false, l2, updateStatus);
|
||||
checkIndexSearchableAndReloadAnalyzers(synonymsSetId, refresh, false, updateStatus, l2);
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -424,7 +450,12 @@ public class SynonymsManagementAPIService {
|
|||
);
|
||||
}
|
||||
|
||||
public void deleteSynonymRule(String synonymsSetId, String synonymRuleId, ActionListener<SynonymsReloadResult> listener) {
|
||||
public void deleteSynonymRule(
|
||||
String synonymsSetId,
|
||||
String synonymRuleId,
|
||||
boolean refresh,
|
||||
ActionListener<SynonymsReloadResult> listener
|
||||
) {
|
||||
client.prepareDelete(SYNONYMS_ALIAS_NAME, internalSynonymRuleId(synonymsSetId, synonymRuleId))
|
||||
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
|
||||
.execute(new DelegatingIndexNotFoundActionListener<>(synonymsSetId, listener, (l, deleteResponse) -> {
|
||||
|
@ -443,7 +474,11 @@ public class SynonymsManagementAPIService {
|
|||
return;
|
||||
}
|
||||
|
||||
reloadAnalyzers(synonymsSetId, false, listener, UpdateSynonymsResultStatus.DELETED);
|
||||
if (refresh) {
|
||||
reloadAnalyzers(synonymsSetId, false, UpdateSynonymsResultStatus.DELETED, listener);
|
||||
} else {
|
||||
listener.onResponse(new SynonymsReloadResult(UpdateSynonymsResultStatus.DELETED, null));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -501,7 +536,7 @@ public class SynonymsManagementAPIService {
|
|||
public void deleteSynonymsSet(String synonymSetId, ActionListener<AcknowledgedResponse> listener) {
|
||||
|
||||
// Previews reloading the resource to understand its usage on indices
|
||||
reloadAnalyzers(synonymSetId, true, listener.delegateFailure((reloadListener, reloadResult) -> {
|
||||
reloadAnalyzers(synonymSetId, true, null, listener.delegateFailure((reloadListener, reloadResult) -> {
|
||||
Map<String, ReloadAnalyzersResponse.ReloadDetails> reloadDetails = reloadResult.reloadAnalyzersResponse.getReloadDetails();
|
||||
if (reloadDetails.isEmpty() == false) {
|
||||
Set<String> indices = reloadDetails.entrySet()
|
||||
|
@ -538,14 +573,48 @@ public class SynonymsManagementAPIService {
|
|||
|
||||
deleteObjectsListener.onResponse(AcknowledgedResponse.of(true));
|
||||
}));
|
||||
}), null);
|
||||
}));
|
||||
}
|
||||
|
||||
private <T> void reloadAnalyzers(
|
||||
private <T> void checkIndexSearchableAndReloadAnalyzers(
|
||||
String synonymSetId,
|
||||
boolean refresh,
|
||||
boolean preview,
|
||||
UpdateSynonymsResultStatus synonymsOperationResult,
|
||||
ActionListener<SynonymsReloadResult> listener
|
||||
) {
|
||||
|
||||
if (refresh == false) {
|
||||
// If not refreshing, we don't need to reload analyzers
|
||||
listener.onResponse(new SynonymsReloadResult(synonymsOperationResult, null));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check synonyms index is searchable before reloading, to ensure analyzers are able to load the changed information
|
||||
checkSynonymsIndexHealth(listener.delegateFailure((l, response) -> {
|
||||
if (response.isTimedOut()) {
|
||||
l.onFailure(
|
||||
new IndexCreationException(
|
||||
"synonyms index ["
|
||||
+ SYNONYMS_ALIAS_NAME
|
||||
+ "] is not searchable. "
|
||||
+ response.getActiveShardsPercent()
|
||||
+ "% shards are active",
|
||||
null
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
reloadAnalyzers(synonymSetId, preview, synonymsOperationResult, listener);
|
||||
}));
|
||||
}
|
||||
|
||||
private void reloadAnalyzers(
|
||||
String synonymSetId,
|
||||
boolean preview,
|
||||
ActionListener<SynonymsReloadResult> listener,
|
||||
UpdateSynonymsResultStatus synonymsOperationResult
|
||||
UpdateSynonymsResultStatus synonymsOperationResult,
|
||||
ActionListener<SynonymsReloadResult> listener
|
||||
) {
|
||||
// auto-reload all reloadable analyzers (currently only those that use updateable synonym or keyword_marker filters)
|
||||
ReloadAnalyzersRequest reloadAnalyzersRequest = new ReloadAnalyzersRequest(synonymSetId, preview, "*");
|
||||
|
@ -556,13 +625,23 @@ public class SynonymsManagementAPIService {
|
|||
);
|
||||
}
|
||||
|
||||
// Allows checking failures in tests
|
||||
void checkSynonymsIndexHealth(ActionListener<ClusterHealthResponse> listener) {
|
||||
ClusterHealthRequest healthRequest = new ClusterHealthRequest(
|
||||
TimeValue.timeValueSeconds(INDEX_SEARCHABLE_TIMEOUT_SECONDS),
|
||||
SYNONYMS_ALIAS_NAME
|
||||
).waitForGreenStatus();
|
||||
|
||||
client.execute(TransportClusterHealthAction.TYPE, healthRequest, listener);
|
||||
}
|
||||
|
||||
// Retrieves the internal synonym rule ID to store it in the index. As the same synonym rule ID
|
||||
// can be used in different synonym sets, we prefix the ID with the synonym set to avoid collisions
|
||||
private static String internalSynonymRuleId(String synonymsSetId, String synonymRuleId) {
|
||||
return synonymsSetId + SYNONYM_RULE_ID_SEPARATOR + synonymRuleId;
|
||||
}
|
||||
|
||||
static Settings settings() {
|
||||
private static Settings settings() {
|
||||
return Settings.builder()
|
||||
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
||||
.put(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS, "0-1")
|
||||
|
|
|
@ -31,7 +31,7 @@ import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg
|
|||
public class ReloadAnalyzersResponseTests extends AbstractBroadcastResponseTestCase<ReloadAnalyzersResponse> {
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
private static final ConstructingObjectParser<ReloadAnalyzersResponse, Void> PARSER = new ConstructingObjectParser<>(
|
||||
public static final ConstructingObjectParser<ReloadAnalyzersResponse, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"reload_analyzer",
|
||||
true,
|
||||
arg -> {
|
||||
|
@ -67,8 +67,8 @@ public class ReloadAnalyzersResponseTests extends AbstractBroadcastResponseTestC
|
|||
declareBroadcastFields(PARSER);
|
||||
PARSER.declareObjectArray(constructorArg(), ENTRY_PARSER, ReloadAnalyzersResponse.RELOAD_DETAILS_FIELD);
|
||||
ENTRY_PARSER.declareString(constructorArg(), ReloadAnalyzersResponse.INDEX_FIELD);
|
||||
ENTRY_PARSER.declareStringArray(constructorArg(), ReloadAnalyzersResponse.RELOADED_ANALYZERS_FIELD);
|
||||
ENTRY_PARSER.declareStringArray(constructorArg(), ReloadAnalyzersResponse.RELOADED_NODE_IDS_FIELD);
|
||||
ENTRY_PARSER.declareStringArray(constructorArg(), ReloadAnalyzersResponse.RELOADED_ANALYZERS_FIELD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,7 +23,7 @@ public class DeleteSynonymRuleActionRequestSerializingTests extends AbstractWire
|
|||
|
||||
@Override
|
||||
protected DeleteSynonymRuleAction.Request createTestInstance() {
|
||||
return new DeleteSynonymRuleAction.Request(randomIdentifier(), randomIdentifier());
|
||||
return new DeleteSynonymRuleAction.Request(randomIdentifier(), randomIdentifier(), randomBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,7 +22,7 @@ public class PutSynonymRuleActionRequestSerializingTests extends AbstractWireSer
|
|||
|
||||
@Override
|
||||
protected PutSynonymRuleAction.Request createTestInstance() {
|
||||
return new PutSynonymRuleAction.Request(randomIdentifier(), SynonymsTestUtils.randomSynonymRule());
|
||||
return new PutSynonymRuleAction.Request(randomIdentifier(), SynonymsTestUtils.randomSynonymRule(), randomBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,7 +25,7 @@ public class PutSynonymsActionRequestSerializingTests extends AbstractWireSerial
|
|||
|
||||
@Override
|
||||
protected PutSynonymsAction.Request createTestInstance() {
|
||||
return new PutSynonymsAction.Request(randomIdentifier(), randomSynonymsSet());
|
||||
return new PutSynonymsAction.Request(randomIdentifier(), randomSynonymsSet(), randomBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,23 +9,54 @@
|
|||
|
||||
package org.elasticsearch.action.synonyms;
|
||||
|
||||
import org.elasticsearch.TransportVersion;
|
||||
import org.elasticsearch.TransportVersions;
|
||||
import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponse;
|
||||
import org.elasticsearch.action.admin.indices.analyze.ReloadAnalyzersResponseTests;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.synonyms.SynonymsManagementAPIService;
|
||||
import org.elasticsearch.synonyms.SynonymsManagementAPIService.SynonymsReloadResult;
|
||||
import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
||||
import org.elasticsearch.test.AbstractBWCSerializationTestCase;
|
||||
import org.elasticsearch.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.xcontent.ParseField;
|
||||
import org.elasticsearch.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.action.synonyms.SynonymUpdateResponse.EMPTY_RELOAD_ANALYZER_RESPONSE;
|
||||
import static org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResultStatus.CREATED;
|
||||
import static org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResultStatus.DELETED;
|
||||
import static org.elasticsearch.synonyms.SynonymsManagementAPIService.UpdateSynonymsResultStatus.UPDATED;
|
||||
import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
|
||||
public class SynonymUpdateResponseSerializingTests extends AbstractWireSerializingTestCase<SynonymUpdateResponse> {
|
||||
public class SynonymUpdateResponseSerializingTests extends AbstractBWCSerializationTestCase<SynonymUpdateResponse> {
|
||||
|
||||
private static final ConstructingObjectParser<SynonymUpdateResponse, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"synonyms_update_response",
|
||||
true,
|
||||
arg -> {
|
||||
SynonymsManagementAPIService.UpdateSynonymsResultStatus status = SynonymsManagementAPIService.UpdateSynonymsResultStatus
|
||||
.valueOf(((String) arg[0]).toUpperCase(Locale.ROOT));
|
||||
ReloadAnalyzersResponse reloadAnalyzersResponse = (ReloadAnalyzersResponse) arg[1];
|
||||
return new SynonymUpdateResponse(new SynonymsReloadResult(status, reloadAnalyzersResponse));
|
||||
}
|
||||
);
|
||||
|
||||
static {
|
||||
PARSER.declareString(constructorArg(), new ParseField(SynonymUpdateResponse.RESULT_FIELD));
|
||||
PARSER.declareObjectOrNull(
|
||||
optionalConstructorArg(),
|
||||
(p, c) -> ReloadAnalyzersResponseTests.PARSER.parse(p, null),
|
||||
null,
|
||||
new ParseField(SynonymUpdateResponse.RELOAD_ANALYZERS_DETAILS_FIELD)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Writeable.Reader<SynonymUpdateResponse> instanceReader() {
|
||||
|
@ -34,9 +65,22 @@ public class SynonymUpdateResponseSerializingTests extends AbstractWireSerializi
|
|||
|
||||
@Override
|
||||
protected SynonymUpdateResponse createTestInstance() {
|
||||
Map<String, ReloadAnalyzersResponse.ReloadDetails> reloadedIndicesDetails = ReloadAnalyzersResponseTests
|
||||
.createRandomReloadDetails();
|
||||
ReloadAnalyzersResponse reloadAnalyzersResponse = new ReloadAnalyzersResponse(10, 10, 0, null, reloadedIndicesDetails);
|
||||
return createTestInstance(randomBoolean());
|
||||
}
|
||||
|
||||
private SynonymUpdateResponse createTestInstance(boolean includeReloadInfo) {
|
||||
ReloadAnalyzersResponse reloadAnalyzersResponse = null;
|
||||
if (includeReloadInfo) {
|
||||
Map<String, ReloadAnalyzersResponse.ReloadDetails> reloadedIndicesDetails = ReloadAnalyzersResponseTests
|
||||
.createRandomReloadDetails();
|
||||
reloadAnalyzersResponse = new ReloadAnalyzersResponse(
|
||||
randomIntBetween(0, 10),
|
||||
randomIntBetween(0, 10),
|
||||
randomIntBetween(0, 5),
|
||||
null,
|
||||
reloadedIndicesDetails
|
||||
);
|
||||
}
|
||||
return new SynonymUpdateResponse(new SynonymsReloadResult(randomFrom(CREATED, UPDATED, DELETED), reloadAnalyzersResponse));
|
||||
}
|
||||
|
||||
|
@ -45,6 +89,17 @@ public class SynonymUpdateResponseSerializingTests extends AbstractWireSerializi
|
|||
return randomValueOtherThan(instance, this::createTestInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SynonymUpdateResponse mutateInstanceForVersion(SynonymUpdateResponse instance, TransportVersion version) {
|
||||
|
||||
if (version.before(TransportVersions.SYNONYMS_REFRESH_PARAM) && instance.reloadAnalyzersResponse() == null) {
|
||||
// Nulls will be written as empty reload analyzer responses for older versions
|
||||
return new SynonymUpdateResponse(new SynonymsReloadResult(instance.updateStatus(), EMPTY_RELOAD_ANALYZER_RESPONSE));
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void testToXContent() throws IOException {
|
||||
Map<String, ReloadAnalyzersResponse.ReloadDetails> reloadedIndicesNodes = Collections.singletonMap(
|
||||
"index",
|
||||
|
@ -73,4 +128,18 @@ public class SynonymUpdateResponseSerializingTests extends AbstractWireSerializi
|
|||
}
|
||||
}"""), output);
|
||||
}
|
||||
|
||||
public void testToXContentWithNoReloadResult() throws IOException {
|
||||
SynonymUpdateResponse response = new SynonymUpdateResponse(new SynonymsReloadResult(CREATED, null));
|
||||
String output = Strings.toString(response);
|
||||
assertEquals(XContentHelper.stripWhitespace("""
|
||||
{
|
||||
"result": "created"
|
||||
}"""), output);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SynonymUpdateResponse doParseInstance(XContentParser parser) throws IOException {
|
||||
return PARSER.apply(parser, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -282,7 +282,7 @@ public class InternalUsers {
|
|||
UsernamesField.SYNONYMS_USER_NAME,
|
||||
new RoleDescriptor(
|
||||
UsernamesField.SYNONYMS_ROLE_NAME,
|
||||
null,
|
||||
new String[] { "monitor" },
|
||||
new RoleDescriptor.IndicesPrivileges[] {
|
||||
RoleDescriptor.IndicesPrivileges.builder().indices(".synonyms*").privileges("all").allowRestrictedIndices(true).build(),
|
||||
RoleDescriptor.IndicesPrivileges.builder().indices("*").privileges(TransportReloadAnalyzersAction.TYPE.name()).build(), },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue