This is an automated email from the ASF dual-hosted git repository.
dsmiley pushed a commit to branch branch_9_0
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_9_0 by this push:
new 0c236d8 SOLR-15064: nested docs: _route_ shouldn't be a fallback for
a blank _root_ (#629)
0c236d8 is described below
commit 0c236d8281ab649403b558780a07606a4c5fdef8
Author: David Smiley <[email protected]>
AuthorDate: Sat Feb 19 00:24:08 2022 -0500
SOLR-15064: nested docs: _route_ shouldn't be a fallback for a blank
_root_ (#629)
Doing atomic updates for nested documents should not use/assume that the
_route_ parameter is a substitute for _root_ if that's not present. Thus
insist the user specify the _root_ field so as to leave no doubt that the
atomic update is a child and not itself a root document.
* Rename getChildIdStr -> getSelfOrNestedDocIdStr
---
solr/CHANGES.txt | 4 ++
.../org/apache/solr/update/AddUpdateCommand.java | 61 +++++--------------
.../apache/solr/update/DirectUpdateHandler2.java | 2 +-
.../src/java/org/apache/solr/update/UpdateLog.java | 8 ---
.../processor/AtomicUpdateDocumentMerger.java | 2 +-
.../processor/DistributedUpdateProcessor.java | 2 +-
.../solr/cloud/NestedShardedAtomicUpdateTest.java | 69 +++++++++++-----------
.../update/processor/NestedAtomicUpdateTest.java | 67 ++++++++++-----------
.../pages/partial-document-updates.adoc | 8 +--
.../pages/major-changes-in-solr-9.adoc | 2 +
10 files changed, 94 insertions(+), 131 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 537101a..7d1d186 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -534,6 +534,10 @@ and each individual module's jar will be included in its
directory's lib/ folder
* SOLR-15991: analysis-extras module tests shouldn't rely on log4j dependency
(Kevin Risden)
+* SOLR-15064: Atomic/partial updates to nested documents now _require_ the
`\_root_` field to
+ clearly show the document isn't a root document. Solr 8 would fallback on
the `\_route_` param but no longer.
+ (David Smiley)
+
* SOLR-15949: Docker: the official image now uses Java 17 provided by Eclipse
Temurin. Formerly it was Java 11 from OpenJDK.
(janhoy, David Smiley)
diff --git a/solr/core/src/java/org/apache/solr/update/AddUpdateCommand.java
b/solr/core/src/java/org/apache/solr/update/AddUpdateCommand.java
index 2de9e6b..068ba52 100644
--- a/solr/core/src/java/org/apache/solr/update/AddUpdateCommand.java
+++ b/solr/core/src/java/org/apache/solr/update/AddUpdateCommand.java
@@ -28,10 +28,7 @@ import org.apache.lucene.util.BytesRef;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;
-import org.apache.solr.common.cloud.DocRouter;
-import org.apache.solr.common.cloud.ImplicitDocRouter;
import org.apache.solr.common.params.CommonParams;
-import org.apache.solr.common.params.ShardParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
@@ -42,9 +39,6 @@ import org.apache.solr.schema.SchemaField;
*/
public class AddUpdateCommand extends UpdateCommand {
- /** In some limited circumstances of child docs, this holds the _route_
param. */
- final String useRouteAsRoot; // lets hope this goes away in SOLR-15064
-
/**
* Higher level SolrInputDocument, normally used to construct the Lucene
Document(s)
* to index.
@@ -70,35 +64,12 @@ public class AddUpdateCommand extends UpdateCommand {
public boolean isLastDocInBatch = false;
- // optional id in "internal" indexed form... if it is needed and not
supplied,
- // it will be obtained from the doc.
private BytesRef indexedId;
private String indexedIdStr;
- private String childDocIdStr;
+ private String selfOrNestedDocIdStr;
public AddUpdateCommand(SolrQueryRequest req) {
super(req);
-
- // Populate useRouteParamAsIndexedId.
- // This ought to be deprecated functionality that we remove in 9.0.
SOLR-15064
- String route = null;
- if (req != null) { // some tests use no req
- route = req.getParams().get(ShardParams._ROUTE_);
- if (route == null || !req.getSchema().isUsableForChildDocs()) {
- route = null;
- } else {
- // use route but there's one last exclusion: It's incompatible with
SolrCloud implicit router.
- String collectionName =
req.getCore().getCoreDescriptor().getCollectionName();
- if (collectionName != null) {
- DocRouter router =
req.getCore().getCoreContainer().getZkController().getClusterState()
- .getCollection(collectionName).getRouter();
- if (router instanceof ImplicitDocRouter) {
- route = null;
- }
- }
- }
- }
- useRouteAsRoot = route;
}
@Override
@@ -111,7 +82,7 @@ public class AddUpdateCommand extends UpdateCommand {
solrDoc = null;
indexedId = null;
indexedIdStr = null;
- childDocIdStr = null;
+ selfOrNestedDocIdStr = null;
updateTerm = null;
isLastDocInBatch = false;
version = 0;
@@ -140,7 +111,8 @@ public class AddUpdateCommand extends UpdateCommand {
}
/**
- * Returns the indexed ID for this document, or the root ID for nested
documents.
+ * Returns the indexed ID that we route this document on. Typically, this is
+ * for the unique key of the document but for a nested document, it's the ID
of the root.
*
* @return possibly null if there's no uniqueKey field
*/
@@ -150,8 +122,10 @@ public class AddUpdateCommand extends UpdateCommand {
}
/**
- * Returns the indexed ID for this document, or the root ID for nested
documents. The returned
- * BytesRef should be treated as immutable. It will not be re-used/modified
for additional docs.
+ * Returns the indexed ID that we route this document on. Typically, this is
+ * for the unique key of the document but for a nested document, it's the ID
of the root.
+ *
+ * BytesRef should be treated as immutable. It will not be re-used/modified
for additional docs.
*
* @return possibly null if there's no uniqueKey field
*/
@@ -166,9 +140,9 @@ public class AddUpdateCommand extends UpdateCommand {
*
* @return possibly null if there's no uniqueKey field
*/
- public String getChildDocIdStr() {
+ public String getSelfOrNestedDocIdStr() {
extractIdsIfNeeded();
- return childDocIdStr;
+ return selfOrNestedDocIdStr;
}
/** The ID for logging purposes. */
@@ -179,10 +153,10 @@ public class AddUpdateCommand extends UpdateCommand {
extractIdsIfNeeded();
if (indexedIdStr == null) {
return "(null)";
- } else if (indexedIdStr.equals(childDocIdStr)) {
+ } else if (indexedIdStr.equals(selfOrNestedDocIdStr)) {
return indexedIdStr;
} else {
- return childDocIdStr + " (root=" + indexedIdStr + ")";
+ return selfOrNestedDocIdStr + " (root=" + indexedIdStr + ")";
}
}
@@ -204,14 +178,11 @@ public class AddUpdateCommand extends UpdateCommand {
} else if (count > 1) {
throw new SolrException(
SolrException.ErrorCode.BAD_REQUEST,"Document contains multiple values for
uniqueKey field: " + field);
} else {
- this.childDocIdStr = field.getFirstValue().toString();
- // the root might be in _root_ field or _route_ param. If neither,
then uniqueKeyField.
+ this.selfOrNestedDocIdStr = field.getFirstValue().toString();
+ // the root might be in _root_ field; if not then uniqueKeyField.
this.indexedIdStr = (String)
solrDoc.getFieldValue(IndexSchema.ROOT_FIELD_NAME); // or here
if (this.indexedIdStr == null) {
- this.indexedIdStr = useRouteAsRoot;
- if (this.indexedIdStr == null) {
- this.indexedIdStr = childDocIdStr;
- }
+ this.indexedIdStr = selfOrNestedDocIdStr;
}
indexedId = schema.indexableUniqueKey(indexedIdStr);
}
@@ -223,7 +194,7 @@ public class AddUpdateCommand extends UpdateCommand {
public void setIndexedId(BytesRef indexedId) {
this.indexedId = indexedId;
this.indexedIdStr = indexedId.utf8ToString();
- this.childDocIdStr = indexedIdStr;
+ this.selfOrNestedDocIdStr = indexedIdStr;
}
/**
diff --git
a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
index 94b1c4a..7b1dd17 100644
--- a/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
+++ b/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
@@ -937,7 +937,7 @@ public class DirectUpdateHandler2 extends UpdateHandler
implements SolrCoreState
// can't use cmd.getIndexedId because it will be a root doc if this doc
is a child
Term updateTerm = new Term(idField.getName(),
- core.getLatestSchema().indexableUniqueKey(cmd.getChildDocIdStr()));
+
core.getLatestSchema().indexableUniqueKey(cmd.getSelfOrNestedDocIdStr()));
List<IndexableField> fields =
cmd.makeLuceneDocForInPlaceUpdate().getFields(); // skips uniqueKey and _root_
log.debug("updateDocValues({})", cmd);
writer.updateDocValues(updateTerm, fields.toArray(new
Field[fields.size()]));
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateLog.java
b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
index e27a166..ea8bf27 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateLog.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateLog.java
@@ -69,7 +69,6 @@ import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.response.SolrQueryResponse;
-import org.apache.solr.schema.IndexSchema;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.update.processor.DistributedUpdateProcessor;
import org.apache.solr.update.processor.UpdateRequestProcessor;
@@ -561,13 +560,6 @@ public class UpdateLog implements PluginInfoInitialized,
SolrMetricProducer {
// TODO: we currently need to log to maintain correct versioning, rtg, etc
// if ((cmd.getFlags() & UpdateCommand.REPLAY) != 0) return;
- // This hack could be removed after SOLR-15064 when we insist updates to
child docs include _root_.
- // Until then, if we're in a buffering mode, then the solrDoc won't have
the _root_ field.
- // Otherwise, it should already be there, placed by the client.
- if (usableForChildDocs && cmd.useRouteAsRoot != null &&
cmd.solrDoc.getField(IndexSchema.ROOT_FIELD_NAME) == null) {
- cmd.solrDoc.setField(IndexSchema.ROOT_FIELD_NAME, cmd.getIndexedIdStr());
- }
-
synchronized (this) {
if ((cmd.getFlags() & UpdateCommand.BUFFERING) != 0) {
ensureBufferTlog();
diff --git
a/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateDocumentMerger.java
b/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateDocumentMerger.java
index f2ac4cc..620a647 100644
---
a/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateDocumentMerger.java
+++
b/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateDocumentMerger.java
@@ -370,7 +370,7 @@ public class AtomicUpdateDocumentMerger {
public boolean doInPlaceUpdateMerge(AddUpdateCommand cmd, Set<String>
updatedFields) throws IOException {
SolrInputDocument inputDoc = cmd.getSolrInputDocument();
BytesRef rootIdBytes = cmd.getIndexedId();
- BytesRef idBytes = schema.indexableUniqueKey(cmd.getChildDocIdStr());
+ BytesRef idBytes =
schema.indexableUniqueKey(cmd.getSelfOrNestedDocIdStr());
updatedFields.add(CommonParams.VERSION_FIELD); // add the version field so
that it is fetched too
SolrInputDocument oldDocument = RealTimeGetComponent.getInputDocument
diff --git
a/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
b/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
index 4802134..72908fd 100644
---
a/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
+++
b/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
@@ -714,7 +714,7 @@ public class DistributedUpdateProcessor extends
UpdateRequestProcessor {
SolrInputDocument mergedDoc;
if (oldRootDocWithChildren == null) {
if (versionOnUpdate > 0
- || !rootDocIdString.equals(cmd.getChildDocIdStr())) {
+ || !rootDocIdString.equals(cmd.getSelfOrNestedDocIdStr())) {
// could just let the optimistic locking throw the error
throw new SolrException(ErrorCode.CONFLICT, "Document not found for
update. id=" + rootDocIdString);
}
diff --git
a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java
b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java
index 7e2ed1b..7b7e089 100644
---
a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java
+++
b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java
@@ -30,7 +30,6 @@ import
org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
-import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.Replica;
@@ -81,28 +80,26 @@ public class NestedShardedAtomicUpdateTest extends
SolrCloudTestCase { // used t
// for now, we know how ranges will be distributed to shards.
// may have to look it up in clusterstate if that assumption changes.
- SolrInputDocument doc = sdoc("id", "1", "level_s", "root");
+ SolrInputDocument doc = sdoc("id", "1", "_root_", "1", "level_s", "root");
- final SolrParams params = params("wt", "json", "_route_", "1");
-
- int which = (params.get("_route_").hashCode() & 0x7fffffff) %
clients.size();
+ int which = (doc.get("_root_").hashCode() & 0x7fffffff) % clients.size();
SolrClient aClient = clients.get(which);
- indexDoc(aClient, params, doc);
+ indexDoc(aClient, null, doc);
- doc = sdoc("id", "1", "children", map("add", sdocs(sdoc("id", "2",
"level_s", "child"))));
+ doc = sdoc("id", "1", "_root_", "1", "children", map("add",
sdocs(sdoc("id", "2", "level_s", "child"))));
- indexDoc(aClient, params, doc);
+ indexDoc(aClient, null, doc);
for(int idIndex = 0; idIndex < ids.length; ++idIndex) {
- doc = sdoc("id", "2", "grandChildren", map("add", sdocs(sdoc("id",
ids[idIndex], "level_s", "grand_child"))));
+ doc = sdoc("id", "2", "_root_", "1", "grandChildren", map("add",
sdocs(sdoc("id", ids[idIndex], "level_s", "grand_child"))));
- indexDocAndRandomlyCommit(getRandomSolrClient(), params, doc);
+ indexDocAndRandomlyCommit(getRandomSolrClient(), null, doc);
- doc = sdoc("id", "3", "inplace_updatable_int", map("inc", "1"));
+ doc = sdoc("id", "3", "_root_", "1", "inplace_updatable_int", map("inc",
"1"));
- indexDocAndRandomlyCommit(getRandomSolrClient(), params, doc);
+ indexDocAndRandomlyCommit(getRandomSolrClient(), null, doc);
// assert RTG request respects _route_ param
QueryResponse routeRsp = getRandomSolrClient().query(params("qt","/get",
"id","2", "_route_", "1"));
@@ -141,22 +138,20 @@ public class NestedShardedAtomicUpdateTest extends
SolrCloudTestCase { // used t
// for now, we know how ranges will be distributed to shards.
// may have to look it up in clusterstate if that assumption changes.
- SolrInputDocument doc = sdoc("id", "1", "level_s", "root");
-
- final SolrParams params = params("wt", "json", "_route_", "1");
+ SolrInputDocument doc = sdoc("id", "1", "_root_", "1", "level_s", "root");
- int which = (params.get("_route_").hashCode() & 0x7fffffff) %
clients.size();
+ int which = (doc.get("_root_").hashCode() & 0x7fffffff) % clients.size();
SolrClient aClient = clients.get(which);
- indexDocAndRandomlyCommit(aClient, params, doc);
+ indexDocAndRandomlyCommit(aClient, null, doc);
- doc = sdoc("id", "1", "children", map("add", sdocs(sdoc("id", "2",
"level_s", "child"))));
+ doc = sdoc("id", "1", "_root_", "1", "children", map("add",
sdocs(sdoc("id", "2", "level_s", "child"))));
- indexDocAndRandomlyCommit(aClient, params, doc);
+ indexDocAndRandomlyCommit(aClient, null, doc);
- doc = sdoc("id", "2", "grandChildren", map("add", sdocs(sdoc("id", ids[0],
"level_s", "grand_child"))));
+ doc = sdoc("id", "2", "_root_", "1", "grandChildren", map("add",
sdocs(sdoc("id", ids[0], "level_s", "grand_child"))));
- indexDocAndRandomlyCommit(aClient, params, doc);
+ indexDocAndRandomlyCommit(aClient, null, doc);
int id1InPlaceCounter = 0;
int id2InPlaceCounter = 0;
@@ -167,21 +162,21 @@ public class NestedShardedAtomicUpdateTest extends
SolrCloudTestCase { // used t
id1InPlaceCounter++;
indexDoc(
getRandomSolrClient(),
- params,
- sdoc("id", "1", "inplace_updatable_int", map("inc", "1")));
+ null,
+ sdoc("id", "1", "_root_", "1", "inplace_updatable_int", map("inc",
"1")));
}
if (random().nextBoolean()) {
id2InPlaceCounter++;
indexDoc(
getRandomSolrClient(),
- params,
- sdoc("id", "2", "inplace_updatable_int", map("inc", "1")));
+ null,
+ sdoc("id", "2", "_root_", "1", "inplace_updatable_int", map("inc",
"1")));
}
- if (random().nextBoolean()) {
+ if (random().nextBoolean()) { // TODO consider removing this now-useless
block?
id3InPlaceCounter++;
indexDoc(
getRandomSolrClient(),
- params, // add root merely to show it doesn't interfere
+ null,
sdoc("id", "3", "_root_", "1", "inplace_updatable_int", map("inc",
"1")));
}
if (random().nextBoolean()) {
@@ -240,30 +235,32 @@ public class NestedShardedAtomicUpdateTest extends
SolrCloudTestCase { // used t
SolrInputDocument doc = sdoc("id", rootId, "level_s", "root");
- final SolrParams wrongRootParams = params("wt", "json", "_route_", "c");
- final SolrParams rightParams = params("wt", "json", "_route_", rootId);
+ final SolrParams wrongRouteParams = params("_route_", "c");
+ final SolrParams rightParams = params("_route_", rootId);
int which = (rootId.hashCode() & 0x7fffffff) % clients.size();
SolrClient aClient = clients.get(which);
- indexDocAndRandomlyCommit(aClient, params("wt", "json", "_route_",
rootId), doc);
+ indexDocAndRandomlyCommit(aClient, null, doc);
final SolrInputDocument childDoc = sdoc("id", rootId, "children",
map("add", sdocs(sdoc("id", "2", "level_s", "child"))));
indexDocAndRandomlyCommit(aClient, rightParams, childDoc);
- final SolrInputDocument grandChildDoc = sdoc("id", "2", "grandChildren",
+ final SolrInputDocument grandChildDoc = sdoc("id", "2", "_root_", rootId,
+ "grandChildren",
map("add", sdocs(
sdoc("id", "3", "level_s", "grandChild")
)
)
);
- SolrException e = expectThrows(SolrException.class,
- "wrong \"_route_\" param should throw an exception",
- () -> indexDocAndRandomlyCommit(aClient, wrongRootParams,
grandChildDoc)
- );
- assertTrue(e.toString(), e.getMessage().contains("Document not found for
update"));
+ // despite the wrong param, it'll be routed correctly; we can find the doc
after.
+ // An error would have been okay too but routing correctly is also fine.
+ indexDoc(aClient, wrongRouteParams, grandChildDoc);
+ aClient.commit();
+
+ assertEquals(1, aClient.query(params("_route_", rootId, "q",
"id:3")).getResults().getNumFound());
}
private void indexDocAndRandomlyCommit(SolrClient client, SolrParams params,
SolrInputDocument sdoc) throws IOException, SolrServerException {
diff --git
a/solr/core/src/test/org/apache/solr/update/processor/NestedAtomicUpdateTest.java
b/solr/core/src/test/org/apache/solr/update/processor/NestedAtomicUpdateTest.java
index 4efed72..65d6bde 100644
---
a/solr/core/src/test/org/apache/solr/update/processor/NestedAtomicUpdateTest.java
+++
b/solr/core/src/test/org/apache/solr/update/processor/NestedAtomicUpdateTest.java
@@ -182,8 +182,8 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
List<SolrInputDocument> docs = IntStream.range(10, 20).mapToObj(x ->
sdoc("id", String.valueOf(x), "string_s",
"child", "inplace_updatable_int", "0")).collect(Collectors.toList());
- doc = sdoc("id", "1", "children", Collections.singletonMap("add", docs));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ doc = sdoc("id", "1", "_root_", "1", "children",
Collections.singletonMap("add", docs));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -198,28 +198,28 @@ public class NestedAtomicUpdateTest extends
SolrTestCaseJ4 {
);
for(int i = 10; i < 20; ++i) {
- doc = sdoc("id", String.valueOf(i), "inplace_updatable_int",
Collections.singletonMap("inc", "1"));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ doc = sdoc("id", String.valueOf(i), "_root_", "1",
"inplace_updatable_int", Collections.singletonMap("inc", "1"));
+ addAndGetVersion(doc, null);
assertU(commit());
}
for(int i = 10; i < 20; ++i) {
- doc = sdoc("id", String.valueOf(i), "inplace_updatable_int",
Collections.singletonMap("inc", "1"));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ doc = sdoc("id", String.valueOf(i), "_root_", "1",
"inplace_updatable_int", Collections.singletonMap("inc", "1"));
+ addAndGetVersion(doc, null);
assertU(commit());
}
// ensure updates work when block has more than 10 children
for(int i = 10; i < 20; ++i) {
docs = IntStream.range(i * 10, (i * 10) + 5).mapToObj(x -> sdoc("id",
String.valueOf(x), "string_s", "grandChild")).collect(Collectors.toList());
- doc = sdoc("id", String.valueOf(i), "grandChildren",
Collections.singletonMap("add", docs));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ doc = sdoc("id", String.valueOf(i), "_root_", "1", "grandChildren",
Collections.singletonMap("add", docs));
+ addAndGetVersion(doc, null);
assertU(commit());
}
for(int i =10; i < 20; ++i) {
- doc = sdoc("id", String.valueOf(i), "inplace_updatable_int",
Collections.singletonMap("inc", "1"));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ doc = sdoc("id", String.valueOf(i), "_root_", "1",
"inplace_updatable_int", Collections.singletonMap("inc", "1"));
+ addAndGetVersion(doc, null);
assertU(commit());
}
@@ -260,7 +260,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
List<SolrInputDocument> docs = IntStream.range(10, 20).mapToObj(x ->
sdoc("id", String.valueOf(x), "string_s",
"child")).collect(Collectors.toList());
doc = sdoc("id", "1", "children", Collections.singletonMap("add", docs));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -281,11 +281,11 @@ public class NestedAtomicUpdateTest extends
SolrTestCaseJ4 {
sdoc(
"id",
String.valueOf(i),
- "_root_", //shows we can specify the root field here instead of
params
+ "_root_",
"1",
"grandChildren",
Collections.singletonMap("add", docs));
- addAndGetVersion(doc, params("wt", "json")); // no _route_ with root
+ addAndGetVersion(doc, null);
assertU(commit());
}
@@ -312,7 +312,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
);
doc = sdoc("id", "1", "child1", Collections.singletonMap("add",
sdocs(sdoc("id", "3", "child_s", "child"))));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -324,9 +324,9 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
"/response/docs/[0]/child1/[0]/child_s=='child'"
);
- doc = sdoc("id", "2",
+ doc = sdoc("id", "2", "_root_", "1",
"grandChild", Collections.singletonMap("add", sdocs(sdoc("id", "4",
"child_s", "grandChild"), sdoc("id", "5", "child_s", "grandChild"))));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -343,7 +343,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
doc = sdoc("id", "1",
"child2", Collections.singletonMap("add", sdocs(sdoc("id", "8",
"child_s", "child"))));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -362,7 +362,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
doc = sdoc("id", "1",
"new_s", Collections.singletonMap("add", "new string"));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -420,7 +420,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
doc = sdoc("id", "1",
"cat_ss", Collections.singletonMap("add", "bbb"),
"child2", Collections.singletonMap("add", sdoc("id", "3", "cat_ss",
"child")));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertJQ(req("qt","/get", "id","1", "fl","id, cat_ss, child1, child2,
[child]")
@@ -442,8 +442,9 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
);
doc = sdoc("id", "2",
+ "_root_", "1",
"child3", Collections.singletonMap("add", sdoc("id", "4", "cat_ss",
"grandChild")));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ addAndGetVersion(doc, null);
assertJQ(req("qt","/get", "id","1", "fl","id, cat_ss, child1, child2,
child3, [child]")
,"=={'doc':{'id':'1'" +
@@ -460,9 +461,9 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
assertU(commit());
//add greatGrandChild
- doc = sdoc("id", "4",
+ doc = sdoc("id", "4", "_root_", "1",
"child4", Collections.singletonMap("add", sdoc("id", "5", "cat_ss",
"greatGrandChild")));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ addAndGetVersion(doc, null);
assertJQ(req("qt","/get", "id","1", "fl","id, cat_ss, child1, child2,
child3, child4, [child]")
,"=={'doc':{'id':'1'" +
@@ -479,9 +480,9 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
assertU(commit());
//add another greatGrandChild
- doc = sdoc("id", "4",
+ doc = sdoc("id", "4", "_root_", "1",
"child4", Collections.singletonMap("add", sdoc("id", "6", "cat_ss",
"greatGrandChild")));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -497,13 +498,13 @@ public class NestedAtomicUpdateTest extends
SolrTestCaseJ4 {
sdoc("id", "8", "cat_ss", "child")
))
);
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertU(commit());
doc = sdoc("id", "1",
"new_s", Collections.singletonMap("add", "new string"));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertU(commit());
@@ -578,10 +579,10 @@ public class NestedAtomicUpdateTest extends
SolrTestCaseJ4 {
" }}"
);
- doc = sdoc("id", "1",
+ doc = sdoc("id", "1", "_root_", "1",
"cat_ss", Collections.singletonMap("set", Arrays.asList("aaa", "bbb")),
"child1", Collections.singletonMap("set", sdoc("id", "3", "cat_ss",
"child")));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ addAndGetVersion(doc, null);
assertJQ(req("qt","/get", "id","1", "fl","id, cat_ss, child1, [child]")
@@ -600,9 +601,9 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
" }}"
);
- doc = sdoc("id", "3",
+ doc = sdoc("id", "3", "_root_", "1",
"child2", Collections.singletonMap("set", sdoc("id", "4", "cat_ss",
"child")));
- addAndGetVersion(doc, params("wt", "json", "_route_", "1"));
+ addAndGetVersion(doc, null);
assertJQ(req("qt","/get", "id","1", "fl","id, cat_ss, child1, child2,
[child]")
,"=={'doc':{'id':'1'" +
@@ -652,7 +653,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
doc = sdoc("id", "1",
"child1", Collections.singletonMap("add", sdoc("id", "2", "cat_ss",
"child")));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
// commit the changes
assertU(commit());
@@ -715,7 +716,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
doc = sdoc("id", "1",
"child1", Collections.singletonMap("remove", sdoc("id", "3", "cat_ss",
"child")));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertJQ(req("qt","/get", "id","1", "fl","id, cat_ss, child1, [child]")
@@ -793,7 +794,7 @@ public class NestedAtomicUpdateTest extends SolrTestCaseJ4 {
", cat_ss:[\"aaa\",\"ccc\"],
child1:[{\"id\":\"2\",\"cat_ss\":[\"child\"]},
{\"id\":\"3\",\"cat_ss\":[\"child\"]}]}}");
doc = sdoc("id", "1", "child1", Collections.singletonMap("set", empty ?
new ArrayList<>() : null));
- addAndGetVersion(doc, params("wt", "json"));
+ addAndGetVersion(doc, null);
assertJQ(req("qt", "/get", "id", "1", "fl", "id, latlon, cat_ss, child1,
[child]"),
"=={\"doc\":{'id':\"1\", \"latlon\":\"0,0\",
cat_ss:[\"aaa\",\"ccc\"]}}");
diff --git
a/solr/solr-ref-guide/modules/indexing-guide/pages/partial-document-updates.adoc
b/solr/solr-ref-guide/modules/indexing-guide/pages/partial-document-updates.adoc
index bd5dcb6..77b97e7 100644
---
a/solr/solr-ref-guide/modules/indexing-guide/pages/partial-document-updates.adoc
+++
b/solr/solr-ref-guide/modules/indexing-guide/pages/partial-document-updates.adoc
@@ -149,12 +149,8 @@ Solr offers two solutions to address this:
* Clients can use the (default) `compositeId` router's "prefix routing"
feature when indexing all documents to ensure that all child/descendent
documents in a Block use the same `id` prefix as the Root level document.
This will cause Solr's default routing logic to automatically send child
document updates to the correct shard.
-Furthermore, you _should_ (sometimes _must_) specify the Root document's ID in
the `\_root_`
-field of this partial update.
-This is how Solr understands that you are updating a child
-document, and not a Root document.
-Without it, Solr only guesses that the `\_route_` parameter is
-equivalent, but it may be absent or not equivalent (e.g., when using the
`implicit` router).
+Furthermore, you _must_ specify the Root document's ID in the `\_root_` field
of this partial update.
+This is how Solr understands that you are updating a child document, and not a
Root document.
All of the examples below use `id` prefixes, so no `\_route_` parameter will
be necessary for these examples.
====
diff --git
a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc
b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc
index a879b9b..019f04e 100644
---
a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc
+++
b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc
@@ -333,3 +333,5 @@ where they really belong: /admin/threads,
/admin/properties, /admin/logging
* SOLR-15949: Docker: the official image now uses Java 17 provided by Eclipse
Temurin. Formerly it was Java 11 from OpenJDK.
(janhoy, David Smiley)
+
+* Atomic/partial updates to nested documents now _require_ the `\_root_` field
to clearly show the document isn't a root document. Solr 8 would fallback on
the `\_route_` param but no longer.
\ No newline at end of file