Skip to content

Commit 3cc222e

Browse files
author
Christoph Büscher
authored
Return reloaded analyzers in _reload_search_ananlyzer response (#43813)
Currently the repsonse of the "_reload_search_analyzer" endpoint contains the index names and nodeIds of indices were analyzers reloading was triggered. This change add the names of the search-time analyzers that were reloaded. Closes #43804
1 parent 217b875 commit 3cc222e

File tree

7 files changed

+155
-58
lines changed

7 files changed

+155
-58
lines changed

docs/reference/indices/apis/reload-analyzers.asciidoc

+30-1
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,33 @@ reload to ensure the new state of the file is reflected everywhere in the cluste
6969
POST /my_index/_reload_search_analyzers
7070
--------------------------------------------------
7171
// CONSOLE
72-
// TEST[s/^/PUT my_index\n/]
72+
// TEST[continued]
73+
74+
The reload request returns information about the nodes it was executed on and the
75+
analyzers that were reloaded:
76+
77+
[source,js]
78+
--------------------------------------------------
79+
{
80+
"_shards" : {
81+
"total" : 2,
82+
"successful" : 2,
83+
"failed" : 0
84+
},
85+
"reload_details" : [
86+
{
87+
"index" : "my_index",
88+
"reloaded_analyzers" : [
89+
"my_synonyms"
90+
],
91+
"reloaded_node_ids" : [
92+
"mfdqTXn_T7SGr2Ho2KT8uw"
93+
]
94+
}
95+
]
96+
}
97+
--------------------------------------------------
98+
// TEST[continued]
99+
// TESTRESPONSE[s/"total" : 2/"total" : $body._shards.total/]
100+
// TESTRESPONSE[s/"successful" : 2/"successful" : $body._shards.successful/]
101+
// TESTRESPONSE[s/mfdqTXn_T7SGr2Ho2KT8uw/$body.reload_details.0.reloaded_node_ids.0/]

server/src/main/java/org/elasticsearch/index/mapper/MapperService.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import com.carrotsearch.hppc.ObjectHashSet;
2323
import com.carrotsearch.hppc.cursors.ObjectCursor;
24+
2425
import org.apache.logging.log4j.LogManager;
2526
import org.apache.logging.log4j.message.ParameterizedMessage;
2627
import org.apache.lucene.analysis.Analyzer;
@@ -847,19 +848,23 @@ protected Analyzer getWrappedAnalyzer(String fieldName) {
847848
}
848849
}
849850

850-
public synchronized void reloadSearchAnalyzers(AnalysisRegistry registry) throws IOException {
851+
public synchronized List<String> reloadSearchAnalyzers(AnalysisRegistry registry) throws IOException {
851852
logger.info("reloading search analyzers");
852853
// refresh indexAnalyzers and search analyzers
853854
final Map<String, TokenizerFactory> tokenizerFactories = registry.buildTokenizerFactories(indexSettings);
854855
final Map<String, CharFilterFactory> charFilterFactories = registry.buildCharFilterFactories(indexSettings);
855856
final Map<String, TokenFilterFactory> tokenFilterFactories = registry.buildTokenFilterFactories(indexSettings);
856857
final Map<String, Settings> settings = indexSettings.getSettings().getGroups("index.analysis.analyzer");
858+
final List<String> reloadedAnalyzers = new ArrayList<>();
857859
for (NamedAnalyzer namedAnalyzer : indexAnalyzers.getAnalyzers().values()) {
858860
if (namedAnalyzer.analyzer() instanceof ReloadableCustomAnalyzer) {
859861
ReloadableCustomAnalyzer analyzer = (ReloadableCustomAnalyzer) namedAnalyzer.analyzer();
860-
Settings analyzerSettings = settings.get(namedAnalyzer.name());
861-
analyzer.reload(namedAnalyzer.name(), analyzerSettings, tokenizerFactories, charFilterFactories, tokenFilterFactories);
862+
String analyzerName = namedAnalyzer.name();
863+
Settings analyzerSettings = settings.get(analyzerName);
864+
analyzer.reload(analyzerName, analyzerSettings, tokenizerFactories, charFilterFactories, tokenFilterFactories);
865+
reloadedAnalyzers.add(analyzerName);
862866
}
863867
}
868+
return reloadedAnalyzers;
864869
}
865870
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/ReloadAnalyzersResponse.java

+63-20
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@
88
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
99
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
1010
import org.elasticsearch.common.ParseField;
11-
import org.elasticsearch.common.collect.Tuple;
1211
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
1312
import org.elasticsearch.common.xcontent.XContentBuilder;
1413
import org.elasticsearch.common.xcontent.XContentParser;
14+
import org.elasticsearch.xpack.core.action.TransportReloadAnalyzersAction.ReloadResult;
1515

1616
import java.io.IOException;
1717
import java.util.Arrays;
1818
import java.util.Collections;
1919
import java.util.HashMap;
20+
import java.util.HashSet;
2021
import java.util.List;
2122
import java.util.Map;
2223
import java.util.Map.Entry;
24+
import java.util.Set;
2325

2426
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
2527

@@ -28,28 +30,39 @@
2830
*/
2931
public class ReloadAnalyzersResponse extends BroadcastResponse {
3032

31-
private final Map<String, List<String>> reloadedIndicesNodes;
33+
private final Map<String, ReloadDetails> reloadDetails;
34+
private static final ParseField RELOAD_DETAILS_FIELD = new ParseField("reload_details");
35+
private static final ParseField INDEX_FIELD = new ParseField("index");
36+
private static final ParseField RELOADED_ANALYZERS_FIELD = new ParseField("reloaded_analyzers");
37+
private static final ParseField RELOADED_NODE_IDS_FIELD = new ParseField("reloaded_node_ids");
38+
3239

3340
public ReloadAnalyzersResponse() {
34-
reloadedIndicesNodes = Collections.emptyMap();
41+
reloadDetails = Collections.emptyMap();
3542
}
3643

3744
public ReloadAnalyzersResponse(int totalShards, int successfulShards, int failedShards,
38-
List<DefaultShardOperationFailedException> shardFailures, Map<String, List<String>> reloadedIndicesNodes) {
45+
List<DefaultShardOperationFailedException> shardFailures, Map<String, ReloadDetails> reloadedIndicesNodes) {
3946
super(totalShards, successfulShards, failedShards, shardFailures);
40-
this.reloadedIndicesNodes = reloadedIndicesNodes;
47+
this.reloadDetails = reloadedIndicesNodes;
48+
}
49+
50+
public final Map<String, ReloadDetails> getReloadDetails() {
51+
return this.reloadDetails;
4152
}
4253

4354
/**
4455
* Override in subclass to add custom fields following the common `_shards` field
4556
*/
4657
@Override
4758
protected void addCustomXContentFields(XContentBuilder builder, Params params) throws IOException {
48-
builder.startArray("reloaded_nodes");
49-
for (Entry<String, List<String>> indexNodesReloaded : reloadedIndicesNodes.entrySet()) {
59+
builder.startArray(RELOAD_DETAILS_FIELD.getPreferredName());
60+
for (Entry<String, ReloadDetails> indexDetails : reloadDetails.entrySet()) {
5061
builder.startObject();
51-
builder.field("index", indexNodesReloaded.getKey());
52-
builder.field("reloaded_node_ids", indexNodesReloaded.getValue());
62+
ReloadDetails value = indexDetails.getValue();
63+
builder.field(INDEX_FIELD.getPreferredName(), value.getIndexName());
64+
builder.field(RELOADED_ANALYZERS_FIELD.getPreferredName(), value.getReloadedAnalyzers());
65+
builder.field(RELOADED_NODE_IDS_FIELD.getPreferredName(), value.getReloadedIndicesNodes());
5366
builder.endObject();
5467
}
5568
builder.endArray();
@@ -59,31 +72,61 @@ protected void addCustomXContentFields(XContentBuilder builder, Params params) t
5972
private static final ConstructingObjectParser<ReloadAnalyzersResponse, Void> PARSER = new ConstructingObjectParser<>("reload_analyzer",
6073
true, arg -> {
6174
BroadcastResponse response = (BroadcastResponse) arg[0];
62-
List<Tuple<String, List<String>>> results = (List<Tuple<String, List<String>>>) arg[1];
63-
Map<String, List<String>> reloadedNodeIds = new HashMap<>();
64-
for (Tuple<String, List<String>> result : results) {
65-
reloadedNodeIds.put(result.v1(), result.v2());
75+
List<ReloadDetails> results = (List<ReloadDetails>) arg[1];
76+
Map<String, ReloadDetails> reloadedNodeIds = new HashMap<>();
77+
for (ReloadDetails result : results) {
78+
reloadedNodeIds.put(result.getIndexName(), result);
6679
}
6780
return new ReloadAnalyzersResponse(response.getTotalShards(), response.getSuccessfulShards(), response.getFailedShards(),
6881
Arrays.asList(response.getShardFailures()), reloadedNodeIds);
6982
});
7083

7184
@SuppressWarnings({ "unchecked" })
72-
private static final ConstructingObjectParser<Tuple<String, List<String>>, Void> ENTRY_PARSER = new ConstructingObjectParser<>(
85+
private static final ConstructingObjectParser<ReloadDetails, Void> ENTRY_PARSER = new ConstructingObjectParser<>(
7386
"reload_analyzer.entry", true, arg -> {
74-
String index = (String) arg[0];
75-
List<String> nodeIds = (List<String>) arg[1];
76-
return new Tuple<>(index, nodeIds);
87+
return new ReloadDetails((String) arg[0], new HashSet<>((List<String>) arg[1]), new HashSet<>((List<String>) arg[2]));
7788
});
7889

7990
static {
8091
declareBroadcastFields(PARSER);
81-
PARSER.declareObjectArray(constructorArg(), ENTRY_PARSER, new ParseField("reloaded_nodes"));
82-
ENTRY_PARSER.declareString(constructorArg(), new ParseField("index"));
83-
ENTRY_PARSER.declareStringArray(constructorArg(), new ParseField("reloaded_node_ids"));
92+
PARSER.declareObjectArray(constructorArg(), ENTRY_PARSER, RELOAD_DETAILS_FIELD);
93+
ENTRY_PARSER.declareString(constructorArg(), INDEX_FIELD);
94+
ENTRY_PARSER.declareStringArray(constructorArg(), RELOADED_ANALYZERS_FIELD);
95+
ENTRY_PARSER.declareStringArray(constructorArg(), RELOADED_NODE_IDS_FIELD);
8496
}
8597

8698
public static ReloadAnalyzersResponse fromXContent(XContentParser parser) {
8799
return PARSER.apply(parser, null);
88100
}
101+
102+
public static class ReloadDetails {
103+
104+
private final String indexName;
105+
private final Set<String> reloadedIndicesNodes;
106+
private final Set<String> reloadedAnalyzers;
107+
108+
ReloadDetails(String name, Set<String> reloadedIndicesNodes, Set<String> reloadedAnalyzers) {
109+
this.indexName = name;
110+
this.reloadedIndicesNodes = reloadedIndicesNodes;
111+
this.reloadedAnalyzers = reloadedAnalyzers;
112+
}
113+
114+
public String getIndexName() {
115+
return indexName;
116+
}
117+
118+
public Set<String> getReloadedIndicesNodes() {
119+
return reloadedIndicesNodes;
120+
}
121+
122+
public Set<String> getReloadedAnalyzers() {
123+
return reloadedAnalyzers;
124+
}
125+
126+
void merge(ReloadResult other) {
127+
assert this.indexName == other.index;
128+
this.reloadedAnalyzers.addAll(other.reloadedSearchAnalyzers);
129+
this.reloadedIndicesNodes.add(other.nodeId);
130+
}
131+
}
89132
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/TransportReloadAnalyzersAction.java

+17-12
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.indices.IndicesService;
3030
import org.elasticsearch.threadpool.ThreadPool;
3131
import org.elasticsearch.transport.TransportService;
32+
import org.elasticsearch.xpack.core.action.ReloadAnalyzersResponse.ReloadDetails;
3233
import org.elasticsearch.xpack.core.action.TransportReloadAnalyzersAction.ReloadResult;
3334

3435
import java.io.IOException;
@@ -67,18 +68,18 @@ protected ReloadResult readShardResult(StreamInput in) throws IOException {
6768
@Override
6869
protected ReloadAnalyzersResponse newResponse(ReloadAnalyzersRequest request, int totalShards, int successfulShards, int failedShards,
6970
List<ReloadResult> responses, List<DefaultShardOperationFailedException> shardFailures, ClusterState clusterState) {
70-
Map<String, List<String>> reloadedIndicesNodes = new HashMap<String, List<String>>();
71+
Map<String, ReloadDetails> reloadedIndicesDetails = new HashMap<String, ReloadDetails>();
7172
for (ReloadResult result : responses) {
72-
if (reloadedIndicesNodes.containsKey(result.index)) {
73-
List<String> nodes = reloadedIndicesNodes.get(result.index);
74-
nodes.add(result.nodeId);
73+
if (reloadedIndicesDetails.containsKey(result.index)) {
74+
reloadedIndicesDetails.get(result.index).merge(result);;
7575
} else {
76-
List<String> nodes = new ArrayList<>();
77-
nodes.add(result.nodeId);
78-
reloadedIndicesNodes.put(result.index, nodes);
76+
HashSet<String> nodeIds = new HashSet<String>();
77+
nodeIds.add(result.nodeId);
78+
ReloadDetails details = new ReloadDetails(result.index, nodeIds, new HashSet<String>(result.reloadedSearchAnalyzers));
79+
reloadedIndicesDetails.put(result.index, details);
7980
}
8081
}
81-
return new ReloadAnalyzersResponse(totalShards, successfulShards, failedShards, shardFailures, reloadedIndicesNodes);
82+
return new ReloadAnalyzersResponse(totalShards, successfulShards, failedShards, shardFailures, reloadedIndicesDetails);
8283
}
8384

8485
@Override
@@ -92,17 +93,19 @@ protected ReloadAnalyzersRequest readRequestFrom(StreamInput in) throws IOExcept
9293
protected ReloadResult shardOperation(ReloadAnalyzersRequest request, ShardRouting shardRouting) throws IOException {
9394
logger.info("reloading analyzers for index shard " + shardRouting);
9495
IndexService indexService = indicesService.indexService(shardRouting.index());
95-
indexService.mapperService().reloadSearchAnalyzers(indicesService.getAnalysis());
96-
return new ReloadResult(shardRouting.index().getName(), shardRouting.currentNodeId());
96+
List<String> reloadedSearchAnalyzers = indexService.mapperService().reloadSearchAnalyzers(indicesService.getAnalysis());
97+
return new ReloadResult(shardRouting.index().getName(), shardRouting.currentNodeId(), reloadedSearchAnalyzers);
9798
}
9899

99-
public static final class ReloadResult implements Streamable {
100+
static final class ReloadResult implements Streamable {
100101
String index;
101102
String nodeId;
103+
List<String> reloadedSearchAnalyzers;
102104

103-
private ReloadResult(String index, String nodeId) {
105+
private ReloadResult(String index, String nodeId, List<String> reloadedSearchAnalyzers) {
104106
this.index = index;
105107
this.nodeId = nodeId;
108+
this.reloadedSearchAnalyzers = reloadedSearchAnalyzers;
106109
}
107110

108111
private ReloadResult() {
@@ -112,12 +115,14 @@ private ReloadResult() {
112115
public void readFrom(StreamInput in) throws IOException {
113116
this.index = in.readString();
114117
this.nodeId = in.readString();
118+
this.reloadedSearchAnalyzers = in.readStringList();
115119
}
116120

117121
@Override
118122
public void writeTo(StreamOutput out) throws IOException {
119123
out.writeString(index);
120124
out.writeString(nodeId);
125+
out.writeStringCollection(this.reloadedSearchAnalyzers);
121126
}
122127
}
123128

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/action/ReloadAnalyzersResponseTests.java

+12-7
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,31 @@
99
import org.elasticsearch.common.Strings;
1010
import org.elasticsearch.common.xcontent.XContentParser;
1111
import org.elasticsearch.test.AbstractBroadcastResponseTestCase;
12-
import org.elasticsearch.xpack.core.action.ReloadAnalyzersResponse;
12+
import org.elasticsearch.xpack.core.action.ReloadAnalyzersResponse.ReloadDetails;
1313

1414
import java.io.IOException;
1515
import java.util.Arrays;
1616
import java.util.Collections;
1717
import java.util.HashMap;
18+
import java.util.HashSet;
1819
import java.util.List;
1920
import java.util.Map;
21+
import java.util.Set;
2022

2123
public class ReloadAnalyzersResponseTests extends AbstractBroadcastResponseTestCase<ReloadAnalyzersResponse> {
2224

2325
@Override
2426
protected ReloadAnalyzersResponse createTestInstance(int totalShards, int successfulShards, int failedShards,
2527
List<DefaultShardOperationFailedException> failures) {
26-
Map<String, List<String>> reloadedIndicesNodes = new HashMap<>();
28+
Map<String, ReloadDetails> reloadedIndicesDetails = new HashMap<>();
2729
int randomIndices = randomIntBetween(0, 5);
2830
for (int i = 0; i < randomIndices; i++) {
29-
List<String> randomNodeIds = Arrays.asList(generateRandomStringArray(5, 5, false, true));
30-
reloadedIndicesNodes.put(randomAlphaOfLengthBetween(5, 10), randomNodeIds);
31+
String name = randomAlphaOfLengthBetween(5, 10);
32+
Set<String> reloadedIndicesNodes = new HashSet<>(Arrays.asList(generateRandomStringArray(5, 5, false, true)));
33+
Set<String> reloadedAnalyzers = new HashSet<>(Arrays.asList(generateRandomStringArray(5, 5, false, true)));
34+
reloadedIndicesDetails.put(name, new ReloadDetails(name, reloadedIndicesNodes, reloadedAnalyzers));
3135
}
32-
return new ReloadAnalyzersResponse(totalShards, successfulShards, failedShards, failures, reloadedIndicesNodes);
36+
return new ReloadAnalyzersResponse(totalShards, successfulShards, failedShards, failures, reloadedIndicesDetails);
3337
}
3438

3539
@Override
@@ -39,12 +43,13 @@ protected ReloadAnalyzersResponse doParseInstance(XContentParser parser) throws
3943

4044
@Override
4145
public void testToXContent() {
42-
Map<String, List<String>> reloadedIndicesNodes = Collections.singletonMap("index", Collections.singletonList("nodeId"));
46+
Map<String, ReloadDetails> reloadedIndicesNodes = Collections.singletonMap("index",
47+
new ReloadDetails("index", Collections.singleton("nodeId"), Collections.singleton("my_analyzer")));
4348
ReloadAnalyzersResponse response = new ReloadAnalyzersResponse(10, 5, 5, null, reloadedIndicesNodes);
4449
String output = Strings.toString(response);
4550
assertEquals(
4651
"{\"_shards\":{\"total\":10,\"successful\":5,\"failed\":5},"
47-
+ "\"reloaded_nodes\":[{\"index\":\"index\",\"reloaded_node_ids\":[\"nodeId\"]}]"
52+
+ "\"reload_details\":[{\"index\":\"index\",\"reloaded_analyzers\":[\"my_analyzer\"],\"reloaded_node_ids\":[\"nodeId\"]}]"
4853
+ "}",
4954
output);
5055
}

0 commit comments

Comments
 (0)