Skip to content

Commit 7370362

Browse files
committed
High-level client: fix clusterAlias parsing in SearchHit (#32465)
When using cross-cluster search through the high-level REST client, the cluster alias from each search hit was not parsed correctly. It would be part of the index field initially, but overridden just a few lines later once setting the shard target (in case we have enough info to build it from the response). In any case, getClusterAlias returns `null` which is a bug. With this change we rather parse back clusterAliases from the index name, set its corresponding field and properly handle the two possible cases depending on whether we can or cannot build the shard target object.
1 parent b39f673 commit 7370362

File tree

3 files changed

+44
-24
lines changed

3 files changed

+44
-24
lines changed

server/src/main/java/org/elasticsearch/search/SearchHit.java

+38-19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@
1919

2020
package org.elasticsearch.search;
2121

22+
import java.io.IOException;
23+
import java.util.ArrayList;
24+
import java.util.Arrays;
25+
import java.util.Collections;
26+
import java.util.HashMap;
27+
import java.util.Iterator;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.Objects;
31+
2232
import org.apache.lucene.search.Explanation;
2333
import org.elasticsearch.ElasticsearchParseException;
2434
import org.elasticsearch.action.OriginalIndices;
@@ -51,16 +61,6 @@
5161
import org.elasticsearch.search.lookup.SourceLookup;
5262
import org.elasticsearch.transport.RemoteClusterAware;
5363

54-
import java.io.IOException;
55-
import java.util.ArrayList;
56-
import java.util.Arrays;
57-
import java.util.Collections;
58-
import java.util.HashMap;
59-
import java.util.Iterator;
60-
import java.util.List;
61-
import java.util.Map;
62-
import java.util.Objects;
63-
6464
import static java.util.Collections.emptyMap;
6565
import static java.util.Collections.singletonMap;
6666
import static java.util.Collections.unmodifiableMap;
@@ -107,6 +107,9 @@ public final class SearchHit implements Streamable, ToXContentObject, Iterable<D
107107
@Nullable
108108
private SearchShardTarget shard;
109109

110+
//These two fields normally get set when setting the shard target, so they hold the same values as the target thus don't get
111+
//serialized over the wire. When parsing hits back from xcontent though, in most of the cases (whenever explanation is disabled)
112+
//we can't rebuild the shard target object so we need to set these manually for users retrieval.
110113
private transient String index;
111114
private transient String clusterAlias;
112115

@@ -551,7 +554,26 @@ public static SearchHit createFromMap(Map<String, Object> values) {
551554
Map<String, DocumentField> fields = get(Fields.FIELDS, values, Collections.emptyMap());
552555

553556
SearchHit searchHit = new SearchHit(-1, id, type, nestedIdentity, fields);
554-
searchHit.index = get(Fields._INDEX, values, null);
557+
String index = get(Fields._INDEX, values, null);
558+
String clusterAlias = null;
559+
if (index != null) {
560+
int indexOf = index.indexOf(RemoteClusterAware.REMOTE_CLUSTER_INDEX_SEPARATOR);
561+
if (indexOf > 0) {
562+
clusterAlias = index.substring(0, indexOf);
563+
index = index.substring(indexOf + 1);
564+
}
565+
}
566+
ShardId shardId = get(Fields._SHARD, values, null);
567+
String nodeId = get(Fields._NODE, values, null);
568+
if (shardId != null && nodeId != null) {
569+
assert shardId.getIndexName().equals(index);
570+
searchHit.shard(new SearchShardTarget(nodeId, shardId, clusterAlias, OriginalIndices.NONE));
571+
} else {
572+
//these fields get set anyways when setting the shard target,
573+
//but we set them explicitly when we don't have enough info to rebuild the shard target
574+
searchHit.index = index;
575+
searchHit.clusterAlias = clusterAlias;
576+
}
555577
searchHit.score(get(Fields._SCORE, values, DEFAULT_SCORE));
556578
searchHit.version(get(Fields._VERSION, values, -1L));
557579
searchHit.sortValues(get(Fields.SORT, values, SearchSortValues.EMPTY));
@@ -561,12 +583,7 @@ public static SearchHit createFromMap(Map<String, Object> values) {
561583
searchHit.setInnerHits(get(Fields.INNER_HITS, values, null));
562584
List<String> matchedQueries = get(Fields.MATCHED_QUERIES, values, null);
563585
if (matchedQueries != null) {
564-
searchHit.matchedQueries(matchedQueries.toArray(new String[matchedQueries.size()]));
565-
}
566-
ShardId shardId = get(Fields._SHARD, values, null);
567-
String nodeId = get(Fields._NODE, values, null);
568-
if (shardId != null && nodeId != null) {
569-
searchHit.shard(new SearchShardTarget(nodeId, shardId, null, OriginalIndices.NONE));
586+
searchHit.matchedQueries(matchedQueries.toArray(new String[0]));
570587
}
571588
return searchHit;
572589
}
@@ -842,13 +859,15 @@ public boolean equals(Object obj) {
842859
&& Arrays.equals(matchedQueries, other.matchedQueries)
843860
&& Objects.equals(explanation, other.explanation)
844861
&& Objects.equals(shard, other.shard)
845-
&& Objects.equals(innerHits, other.innerHits);
862+
&& Objects.equals(innerHits, other.innerHits)
863+
&& Objects.equals(index, other.index)
864+
&& Objects.equals(clusterAlias, other.clusterAlias);
846865
}
847866

848867
@Override
849868
public int hashCode() {
850869
return Objects.hash(id, type, nestedIdentity, version, source, fields, getHighlightFields(), Arrays.hashCode(matchedQueries),
851-
explanation, shard, innerHits);
870+
explanation, shard, innerHits, index, clusterAlias);
852871
}
853872

854873
/**

server/src/main/java/org/elasticsearch/search/SearchShardTarget.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.search;
2121

22+
import java.io.IOException;
23+
2224
import org.elasticsearch.Version;
2325
import org.elasticsearch.action.OriginalIndices;
2426
import org.elasticsearch.common.Nullable;
@@ -30,16 +32,14 @@
3032
import org.elasticsearch.index.shard.ShardId;
3133
import org.elasticsearch.transport.RemoteClusterAware;
3234

33-
import java.io.IOException;
34-
3535
/**
3636
* The target that the search request was executed on.
3737
*/
3838
public final class SearchShardTarget implements Writeable, Comparable<SearchShardTarget> {
3939

4040
private final Text nodeId;
4141
private final ShardId shardId;
42-
//original indices and cluster alias are only needed in the coordinating node throughout the search request execution.
42+
//original indices are only needed in the coordinating node throughout the search request execution.
4343
//no need to serialize them as part of SearchShardTarget.
4444
private final transient OriginalIndices originalIndices;
4545
private final String clusterAlias;

server/src/test/java/org/elasticsearch/search/SearchHitTests.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,10 @@ public static SearchHit createTestItem(boolean withOptionalInnerHits) {
119119
hit.setInnerHits(innerHits);
120120
}
121121
if (randomBoolean()) {
122+
String index = randomAlphaOfLengthBetween(5, 10);
123+
String clusterAlias = randomBoolean() ? null : randomAlphaOfLengthBetween(5, 10);
122124
hit.shard(new SearchShardTarget(randomAlphaOfLengthBetween(5, 10),
123-
new ShardId(new Index(randomAlphaOfLengthBetween(5, 10), randomAlphaOfLengthBetween(5, 10)), randomInt()), null,
124-
OriginalIndices.NONE));
125+
new ShardId(new Index(index, randomAlphaOfLengthBetween(5, 10)), randomInt()), clusterAlias, OriginalIndices.NONE));
125126
}
126127
return hit;
127128
}

0 commit comments

Comments
 (0)