You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by mk...@apache.org on 2023/03/08 09:11:54 UTC
[solr] branch main updated: SOLR-16681: Throw exception when attempting to replace uniqueKey via fl in distributed request (#1384)
This is an automated email from the ASF dual-hosted git repository.
mkhl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 3baf1804df7 SOLR-16681: Throw exception when attempting to replace uniqueKey via fl in distributed request (#1384)
3baf1804df7 is described below
commit 3baf1804df7b2b6f50ff151eba518b3e7f1e70cf
Author: Mikhail Khludnev <mk...@users.noreply.github.com>
AuthorDate: Wed Mar 8 12:11:48 2023 +0300
SOLR-16681: Throw exception when attempting to replace uniqueKey via fl in distributed request (#1384)
* fl=newid->id seems doesn't work in cloud
---
solr/CHANGES.txt | 3 +
.../solr/handler/component/QueryComponent.java | 31 ++++++++--
.../solr/cloud/TestCloudPseudoReturnFields.java | 71 +++++++++++++++++++---
.../org/apache/solr/search/ReturnFieldsTest.java | 11 +++-
.../apache/solr/search/TestPseudoReturnFields.java | 34 ++++++++---
5 files changed, 124 insertions(+), 26 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 27839bb509c..f5be3131cf0 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -334,6 +334,9 @@ Other Changes
* SOLR-16684: Keep solr's opennlp-tools version in sync with Lucene (janhoy)
+* SOLR-16681: Throw exception when attempting to replace uniqueKey via fl in distributed request,
+ e.g. fl=old_id:id,id:new_id (Mikhail Khludnev)
+
================== 9.1.1 ==================
Bug Fixes
diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
index eba85c48a4c..5efde4786ce 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
@@ -1272,13 +1272,15 @@ public class QueryComponent extends SearchComponent {
if ((sreq.purpose & ShardRequest.PURPOSE_GET_FIELDS) != 0) {
boolean returnScores = (rb.getFieldFlags() & SolrIndexSearcher.GET_SCORES) != 0;
- String keyFieldName = rb.req.getSchema().getUniqueKeyField().getName();
+ final String uniqueKey = rb.req.getSchema().getUniqueKeyField().getName();
+ String keyFieldName = uniqueKey;
boolean removeKeyField = !rb.rsp.getReturnFields().wantsField(keyFieldName);
if (rb.rsp.getReturnFields().getFieldRenames().get(keyFieldName) != null) {
// if id was renamed we need to use the new name
keyFieldName = rb.rsp.getReturnFields().getFieldRenames().get(keyFieldName);
}
-
+ String lastKeyString = "<empty>";
+ Boolean shardDocFoundInResults = null;
for (ShardResponse srsp : sreq.responses) {
if (srsp.getException() != null) {
// Don't try to get the documents if there was an exception in the shard
@@ -1323,9 +1325,11 @@ public class QueryComponent extends SearchComponent {
(SolrDocumentList)
SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "response", false));
for (SolrDocument doc : docs) {
- Object id = doc.getFieldValue(keyFieldName);
- ShardDoc sdoc = rb.resultIds.get(id.toString());
+ final Object id = doc.getFieldValue(keyFieldName);
+ lastKeyString = id.toString();
+ final ShardDoc sdoc = rb.resultIds.get(lastKeyString);
if (sdoc != null) {
+ shardDocFoundInResults = Boolean.TRUE;
if (returnScores) {
doc.setField("score", sdoc.score);
} else {
@@ -1338,9 +1342,28 @@ public class QueryComponent extends SearchComponent {
doc.removeFields(keyFieldName);
}
rb.getResponseDocs().set(sdoc.positionInResponse, doc);
+ } else {
+ if (shardDocFoundInResults == null) {
+ shardDocFoundInResults = Boolean.FALSE;
+ }
}
}
}
+ if (Objects.equals(shardDocFoundInResults, Boolean.FALSE) && !rb.resultIds.isEmpty()) {
+ String keyMsg =
+ !uniqueKey.equals(keyFieldName)
+ ? "(either " + uniqueKey + " or " + keyFieldName + ")"
+ : uniqueKey;
+ throw new SolrException(
+ SolrException.ErrorCode.BAD_REQUEST,
+ "Unable to merge shard response. Perhaps uniqueKey "
+ + keyMsg
+ + " was erased by renaming via fl parameters."
+ + " Expecting:"
+ + rb.resultIds.keySet()
+ + ", a sample of keys received:"
+ + lastKeyString);
+ }
}
}
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java
index 885fa843764..c439cf9166c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudPseudoReturnFields.java
@@ -23,6 +23,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Random;
import org.apache.lucene.tests.util.TestUtil;
@@ -35,6 +36,7 @@ import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.schema.SchemaResponse.FieldResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
@@ -43,6 +45,7 @@ import org.apache.solr.search.TestPseudoReturnFields;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Test;
/**
* @see TestPseudoReturnFields
@@ -91,27 +94,27 @@ public class TestCloudPseudoReturnFields extends SolrCloudTestCase {
assertEquals(
0,
CLOUD_CLIENT
- .add(sdoc("id", "42", "val_i", "1", "ssto", "X", "subject", "aaa"))
+ .add(sdoc("id", "42", "newid", "420", "val_i", "1", "ssto", "X", "subject", "aaa"))
.getStatus());
assertEquals(
0,
CLOUD_CLIENT
- .add(sdoc("id", "43", "val_i", "9", "ssto", "X", "subject", "bbb"))
+ .add(sdoc("id", "43", "newid", "430", "val_i", "9", "ssto", "X", "subject", "bbb"))
.getStatus());
assertEquals(
0,
CLOUD_CLIENT
- .add(sdoc("id", "44", "val_i", "4", "ssto", "X", "subject", "aaa"))
+ .add(sdoc("id", "44", "newid", "440", "val_i", "4", "ssto", "X", "subject", "aaa"))
.getStatus());
assertEquals(
0,
CLOUD_CLIENT
- .add(sdoc("id", "45", "val_i", "6", "ssto", "X", "subject", "aaa"))
+ .add(sdoc("id", "45", "newid", "450", "val_i", "6", "ssto", "X", "subject", "aaa"))
.getStatus());
assertEquals(
0,
CLOUD_CLIENT
- .add(sdoc("id", "46", "val_i", "3", "ssto", "X", "subject", "ggg"))
+ .add(sdoc("id", "46", "newid", "460", "val_i", "3", "ssto", "X", "subject", "ggg"))
.getStatus());
assertEquals(0, CLOUD_CLIENT.commit().getStatus());
}
@@ -124,7 +127,18 @@ public class TestCloudPseudoReturnFields extends SolrCloudTestCase {
assertEquals(
0,
CLOUD_CLIENT
- .add(sdoc("id", "99", "val_i", "1", "ssto", "X", "subject", "uncommitted"))
+ .add(
+ sdoc(
+ "id",
+ "99",
+ "newid",
+ "990",
+ "val_i",
+ "1",
+ "ssto",
+ "X",
+ "subject",
+ "uncommitted"))
.getStatus());
}
@@ -234,7 +248,7 @@ public class TestCloudPseudoReturnFields extends SolrCloudTestCase {
SolrDocumentList docs = assertSearch(params("q", "*:*", "rows", "10", "fl", fl));
// shouldn't matter what doc we pick...
for (SolrDocument doc : docs) {
- assertEquals(fl + " => " + doc, 5, doc.size());
+ assertEquals(fl + " => " + doc, 5 + 1, doc.size());
assertTrue(fl + " => " + doc, doc.getFieldValue("id") instanceof String);
assertTrue(fl + " => " + doc, doc.getFieldValue("val_i") instanceof Integer);
assertTrue(fl + " => " + doc, doc.getFieldValue("subject") instanceof String);
@@ -245,12 +259,49 @@ public class TestCloudPseudoReturnFields extends SolrCloudTestCase {
}
}
+ @Test
+ public void testCopyPk() throws Exception {
+ String fl = "oldid:id,newid";
+ SolrDocumentList docs = assertSearch(params("q", "*:*", "rows", "10", "fl", fl));
+ for (SolrDocument doc : docs) {
+ assertTrue(
+ fl + " => " + doc,
+ Arrays.asList("420", "430", "440", "450", "460")
+ .indexOf((String) doc.getFieldValue("newid"))
+ >= 0);
+ assertTrue(
+ fl + " => " + doc,
+ Arrays.asList("42", "43", "44", "45", "46").indexOf((String) doc.getFieldValue("oldid"))
+ >= 0);
+ }
+ }
+
+ public void testMovePk() throws Exception {
+ try {
+ String fl = "oldid:id,id:newid"; // "id:newid";//
+ SolrDocumentList docs = assertSearch(params("q", "*:*", "rows", "10", "fl", fl));
+ fail("attempting to move PK causes 400");
+ for (SolrDocument doc : docs) {
+ assertTrue(
+ fl + " => " + doc,
+ Arrays.asList("420", "430", "440", "450", "460")
+ .indexOf((String) doc.getFieldValue("id"))
+ >= 0);
+ }
+ } catch (SolrException sse) {
+ assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, sse.code());
+ final String message = sse.getMessage().toLowerCase(Locale.ROOT);
+ assertTrue(message.contains("uniqueKey".toLowerCase(Locale.ROOT)));
+ assertTrue(message.contains("fl".toLowerCase(Locale.ROOT)));
+ }
+ }
+
public void testAllRealFieldsRTG() throws Exception {
// shouldn't matter if we use RTG (committed or otherwise)
for (String fl : TestPseudoReturnFields.ALL_REAL_FIELDS) {
for (int i : Arrays.asList(42, 43, 44, 45, 46, 99)) {
SolrDocument doc = getRandClient(random()).getById("" + i, params("fl", fl));
- assertEquals(fl + " => " + doc, 5, doc.size());
+ assertEquals(fl + " => " + doc, 5 + 1, doc.size());
assertTrue(fl + " => " + doc, doc.getFieldValue("id") instanceof String);
assertTrue(fl + " => " + doc, doc.getFieldValue("val_i") instanceof Integer);
assertTrue(fl + " => " + doc, doc.getFieldValue("subject") instanceof String);
@@ -283,7 +334,7 @@ public class TestCloudPseudoReturnFields extends SolrCloudTestCase {
SolrDocumentList docs = assertSearch(params("q", "*:*", "rows", "10", "fl", fl));
// shouldn't matter what doc we pick...
for (SolrDocument doc : docs) {
- assertEquals(fl + " => " + doc, 6, doc.size());
+ assertEquals(fl + " => " + doc, 6 + 1, doc.size());
assertTrue(fl + " => " + doc, doc.getFieldValue("id") instanceof String);
assertTrue(fl + " => " + doc, doc.getFieldValue("score") instanceof Float);
assertTrue(fl + " => " + doc, doc.getFieldValue("val_i") instanceof Integer);
@@ -300,7 +351,7 @@ public class TestCloudPseudoReturnFields extends SolrCloudTestCase {
for (String fl : TestPseudoReturnFields.SCORE_AND_REAL_FIELDS) {
for (int i : Arrays.asList(42, 43, 44, 45, 46, 99)) {
SolrDocument doc = getRandClient(random()).getById("" + i, params("fl", fl));
- assertEquals(fl + " => " + doc, 5, doc.size());
+ assertEquals(fl + " => " + doc, 5 + 1, doc.size());
assertTrue(fl + " => " + doc, doc.getFieldValue("id") instanceof String);
assertTrue(fl + " => " + doc, doc.getFieldValue("val_i") instanceof Integer);
assertTrue(fl + " => " + doc, doc.getFieldValue("subject") instanceof String);
diff --git a/solr/core/src/test/org/apache/solr/search/ReturnFieldsTest.java b/solr/core/src/test/org/apache/solr/search/ReturnFieldsTest.java
index 0db966e01f3..20cda788f33 100644
--- a/solr/core/src/test/org/apache/solr/search/ReturnFieldsTest.java
+++ b/solr/core/src/test/org/apache/solr/search/ReturnFieldsTest.java
@@ -45,9 +45,9 @@ public class ReturnFieldsTest extends SolrTestCaseJ4 {
System.setProperty("enable.update.log", "false"); // schema12 doesn't support _version_
initCore("solrconfig.xml", "schema12.xml");
String v = "how now brown cow";
- assertU(adoc("id", "1", "text", v, "text_np", v, "#foo_s", v));
+ assertU(adoc("id", "1", "new_id_s", "10", "text", v, "text_np", v, "#foo_s", v));
v = "now cow";
- assertU(adoc("id", "2", "text", v, "text_np", v));
+ assertU(adoc("id", "2", "new_id_s", "20", "text", v, "text_np", v));
assertU(commit());
}
@@ -91,6 +91,13 @@ public class ReturnFieldsTest extends SolrTestCaseJ4 {
"*//doc[1]/str[2][.='1'] ");
}
+ public void testMovePk() {
+ assertQ(
+ req("q", "id:1", "fl", "old_id:id,id:new_id_s"),
+ "//*[@numFound='1'] ",
+ "*//doc[1]/arr[@name='id']/str[.='10'] ");
+ }
+
@Test
public void testToString() {
for (Method m : SolrReturnFields.class.getMethods()) {
diff --git a/solr/core/src/test/org/apache/solr/search/TestPseudoReturnFields.java b/solr/core/src/test/org/apache/solr/search/TestPseudoReturnFields.java
index c6c7c155a39..cd0836da9bc 100644
--- a/solr/core/src/test/org/apache/solr/search/TestPseudoReturnFields.java
+++ b/solr/core/src/test/org/apache/solr/search/TestPseudoReturnFields.java
@@ -45,11 +45,11 @@ public class TestPseudoReturnFields extends SolrTestCaseJ4 {
public static void beforeTests() throws Exception {
initCore("solrconfig-tlog.xml", "schema-pseudo-fields.xml");
- assertU(adoc("id", "42", "val_i", "1", "ssto", "X", "subject", "aaa"));
- assertU(adoc("id", "43", "val_i", "9", "ssto", "X", "subject", "bbb"));
- assertU(adoc("id", "44", "val_i", "4", "ssto", "X", "subject", "aaa"));
- assertU(adoc("id", "45", "val_i", "6", "ssto", "X", "subject", "aaa"));
- assertU(adoc("id", "46", "val_i", "3", "ssto", "X", "subject", "ggg"));
+ assertU(adoc("id", "42", "newid", "420", "val_i", "1", "ssto", "X", "subject", "aaa"));
+ assertU(adoc("id", "43", "newid", "430", "val_i", "9", "ssto", "X", "subject", "bbb"));
+ assertU(adoc("id", "44", "newid", "440", "val_i", "4", "ssto", "X", "subject", "aaa"));
+ assertU(adoc("id", "45", "newid", "450", "val_i", "6", "ssto", "X", "subject", "aaa"));
+ assertU(adoc("id", "46", "newid", "460", "val_i", "3", "ssto", "X", "subject", "ggg"));
assertU(commit());
}
@@ -58,7 +58,7 @@ public class TestPseudoReturnFields extends SolrTestCaseJ4 {
// uncommitted doc in transaction log at start of every test
// Even if an RTG causes ulog to re-open realtime searcher, next test method
// will get another copy of doc 99 in the ulog
- assertU(adoc("id", "99", "val_i", "1", "ssto", "X", "subject", "uncommitted"));
+ assertU(adoc("id", "99", "newid", "990", "val_i", "1", "ssto", "X", "subject", "uncommitted"));
}
public void testMultiValued() throws Exception {
@@ -110,6 +110,20 @@ public class TestPseudoReturnFields extends SolrTestCaseJ4 {
"/doc=={'val2_ss':10,'val_ss':1,'subject':'uncommitted'}");
}
+ public void testMovePk() {
+
+ for (String fl : new String[] {"oldid:id,id:newid,val_i,subject,ssto"}) {
+ assertQ(
+ "fl=" + fl + " ... all real fields",
+ req("q", "*:*", "rows", "1", "fl", fl),
+ "//result[@numFound='5']",
+ "//result/doc/str[@name='id'][.='420' or .='430' or .='440' or .='450' or .='460']",
+ "//result/doc/int[@name='val_i']",
+ "//result/doc/str[@name='ssto']",
+ "//result/doc/str[@name='subject']");
+ }
+ }
+
public void testAllRealFields() {
for (String fl : ALL_REAL_FIELDS) {
@@ -121,7 +135,7 @@ public class TestPseudoReturnFields extends SolrTestCaseJ4 {
"//result/doc/int[@name='val_i']",
"//result/doc/str[@name='ssto']",
"//result/doc/str[@name='subject']",
- "//result/doc[count(*)=5]");
+ "//result/doc[count(*)=6]");
}
}
@@ -137,7 +151,7 @@ public class TestPseudoReturnFields extends SolrTestCaseJ4 {
"//doc/int[@name='val_i']",
"//doc/str[@name='ssto']",
"//doc/str[@name='subject']",
- "//doc[count(*)=5]");
+ "//doc[count(*)=6]");
}
}
}
@@ -178,7 +192,7 @@ public class TestPseudoReturnFields extends SolrTestCaseJ4 {
"//result/doc/str[@name='ssto']",
"//result/doc/str[@name='subject']",
"//result/doc/float[@name='score']",
- "//result/doc[count(*)=6]");
+ "//result/doc[count(*)=7]");
}
}
@@ -195,7 +209,7 @@ public class TestPseudoReturnFields extends SolrTestCaseJ4 {
"//doc/int[@name='val_i']",
"//doc/str[@name='ssto']",
"//doc/str[@name='subject']",
- "//doc[count(*)=5]");
+ "//doc[count(*)=6]");
}
}
}