Fix reindex-from-remote for parent/child from <2.0

Versions before 2.0 needed to be told to return interesting fields
like `_parent`, `_routing`, `_ttl`, and `_timestamp`. And they come
back inside a `fields` block which we need to parse.

Closes #21044
This commit is contained in:
Nik Everett 2016-10-21 11:09:54 -04:00
parent 904dcc7127
commit 18393a06f3
5 changed files with 84 additions and 6 deletions

View File

@ -89,6 +89,10 @@ final class RemoteRequestBuilders {
params.put("sort", sorts.toString());
}
}
if (remoteVersion.before(Version.V_2_0_0)) {
// Versions before 2.0.0 need prompting to return interesting fields. Note that timestamp isn't available at all....
searchRequest.source().storedField("_parent").storedField("_routing").storedField("_ttl");
}
if (searchRequest.source().storedFields() != null && false == searchRequest.source().storedFields().fieldNames().isEmpty()) {
StringBuilder fields = new StringBuilder(searchRequest.source().storedFields().fieldNames().get(0));
for (int i = 1; i < searchRequest.source().storedFields().fieldNames().size(); i++) {
@ -97,6 +101,8 @@ final class RemoteRequestBuilders {
String storedFieldsParamName = remoteVersion.before(Version.V_5_0_0_alpha4) ? "fields" : "stored_fields";
params.put(storedFieldsParamName, fields.toString());
}
// We always want the _source document and this will force it to be returned.
params.put("_source", "true");
return params;
}

View File

@ -83,10 +83,28 @@ final class RemoteResponseParsers {
throw new ParsingException(p.getTokenLocation(), "[hit] failed to parse [_source]", e);
}
}, new ParseField("_source"));
HIT_PARSER.declareString(BasicHit::setRouting, new ParseField("_routing"));
HIT_PARSER.declareString(BasicHit::setParent, new ParseField("_parent"));
HIT_PARSER.declareLong(BasicHit::setTTL, new ParseField("_ttl"));
ParseField routingField = new ParseField("_routing");
ParseField parentField = new ParseField("_parent");
ParseField ttlField = new ParseField("_ttl");
HIT_PARSER.declareString(BasicHit::setRouting, routingField);
HIT_PARSER.declareString(BasicHit::setParent, parentField);
HIT_PARSER.declareLong(BasicHit::setTTL, ttlField);
HIT_PARSER.declareLong(BasicHit::setTimestamp, new ParseField("_timestamp"));
// Pre-2.0.0 parent and routing come back in "fields"
class Fields {
String routing;
String parent;
long ttl;
}
ObjectParser<Fields, ParseFieldMatcherSupplier> fieldsParser = new ObjectParser<>("fields", Fields::new);
HIT_PARSER.declareObject((hit, fields) -> {
hit.setRouting(fields.routing);
hit.setParent(fields.parent);
hit.setTTL(fields.ttl);
}, fieldsParser, new ParseField("fields"));
fieldsParser.declareString((fields, routing) -> fields.routing = routing, routingField);
fieldsParser.declareString((fields, parent) -> fields.parent = parent, parentField);
fieldsParser.declareLong((fields, ttl) -> fields.ttl = ttl, ttlField);
}
/**

View File

@ -113,7 +113,7 @@ public class RemoteRequestBuildersTests extends ESTestCase {
SearchRequest searchRequest = new SearchRequest().source(new SearchSourceBuilder());
// Test request without any fields
Version remoteVersion = Version.fromId(between(0, Version.CURRENT.id));
Version remoteVersion = Version.fromId(between(Version.V_2_0_0_beta1_ID, Version.CURRENT.id));
assertThat(initialSearchParams(searchRequest, remoteVersion),
not(either(hasKey("stored_fields")).or(hasKey("fields"))));
@ -125,8 +125,12 @@ public class RemoteRequestBuildersTests extends ESTestCase {
assertThat(initialSearchParams(searchRequest, remoteVersion), hasEntry("stored_fields", "_source,_id"));
// Test fields for versions that support it
remoteVersion = Version.fromId(between(0, Version.V_5_0_0_alpha4_ID - 1));
remoteVersion = Version.fromId(between(Version.V_2_0_0_beta1_ID, Version.V_5_0_0_alpha4_ID - 1));
assertThat(initialSearchParams(searchRequest, remoteVersion), hasEntry("fields", "_source,_id"));
// Test extra fields for versions that need it
remoteVersion = Version.fromId(between(0, Version.V_2_0_0_beta1_ID - 1));
assertThat(initialSearchParams(searchRequest, remoteVersion), hasEntry("fields", "_source,_id,_parent,_routing,_ttl"));
}
public void testInitialSearchParamsMisc() {
@ -151,6 +155,7 @@ public class RemoteRequestBuildersTests extends ESTestCase {
assertThat(params, scroll == null ? not(hasKey("scroll")) : hasEntry("scroll", scroll.toString()));
assertThat(params, hasEntry("size", Integer.toString(size)));
assertThat(params, fetchVersion == null || fetchVersion == true ? hasEntry("version", null) : not(hasEntry("version", null)));
assertThat(params, hasEntry("_source", "true"));
}
public void testInitialSearchEntity() throws IOException {

View File

@ -192,7 +192,7 @@ public class RemoteScrollableHitSourceTests extends ESTestCase {
}
/**
* Test for parsing _ttl, _timestamp, and _routing.
* Test for parsing _ttl, _timestamp, _routing, and _parent.
*/
public void testParseScrollFullyLoaded() throws Exception {
AtomicBoolean called = new AtomicBoolean();
@ -208,6 +208,24 @@ public class RemoteScrollableHitSourceTests extends ESTestCase {
assertTrue(called.get());
}
/**
* Test for parsing _ttl, _routing, and _parent. _timestamp isn't available.
*/
public void testParseScrollFullyLoadedFrom1_7() throws Exception {
AtomicBoolean called = new AtomicBoolean();
sourceWithMockedRemoteCall("scroll_fully_loaded_1_7.json").doStartNextScroll("", timeValueMillis(0), r -> {
assertEquals("AVToMiDL50DjIiBO3yKA", r.getHits().get(0).getId());
assertEquals("{\"test\":\"test3\"}", r.getHits().get(0).getSource().utf8ToString());
assertEquals((Long) 1234L, r.getHits().get(0).getTTL());
assertNull(r.getHits().get(0).getTimestamp()); // Not available from 1.7
assertEquals("testrouting", r.getHits().get(0).getRouting());
assertEquals("testparent", r.getHits().get(0).getParent());
called.set(true);
});
assertTrue(called.get());
}
/**
* Versions of Elasticsearch before 2.1.0 don't support sort:_doc and instead need to use search_type=scan. Scan doesn't return
* documents the first iteration but reindex doesn't like that. So we jump start strait to the next iteration.

View File

@ -0,0 +1,31 @@
{
"_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAfakescroll",
"took" : 3,
"timed_out" : false,
"terminated_early" : true,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 4,
"max_score" : null,
"hits" : [ {
"_index" : "test",
"_type" : "test",
"_id" : "AVToMiDL50DjIiBO3yKA",
"_version" : 1,
"_score" : null,
"_source" : {
"test" : "test3"
},
"sort" : [ 0 ],
"fields" : {
"_routing" : "testrouting",
"_ttl" : 1234,
"_parent" : "testparent"
}
} ]
}
}