mirror of https://github.com/apache/lucene.git
SOLR-9309: Fix SolrCloud RTG response structure when multi ids requested but only 1 found
This commit is contained in:
parent
08019f4288
commit
9aa639d45e
|
@ -159,6 +159,8 @@ Bug Fixes
|
||||||
|
|
||||||
* SOLR-9288: Fix [docid] transformer to return -1 when used in RTG with uncommitted doc (hossman)
|
* SOLR-9288: Fix [docid] transformer to return -1 when used in RTG with uncommitted doc (hossman)
|
||||||
|
|
||||||
|
* SOLR-9309: Fix SolrCloud RTG response structure when multi ids requested but only 1 found (hossman)
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -143,10 +143,9 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String id[] = params.getParams("id");
|
final IdsRequsted reqIds = IdsRequsted.parseParams(req);
|
||||||
String ids[] = params.getParams("ids");
|
|
||||||
|
|
||||||
if (id == null && ids == null) {
|
if (reqIds.allIds.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,20 +170,6 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
|
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String[] allIds = id==null ? new String[0] : id;
|
|
||||||
|
|
||||||
if (ids != null) {
|
|
||||||
List<String> lst = new ArrayList<>();
|
|
||||||
for (String s : allIds) {
|
|
||||||
lst.add(s);
|
|
||||||
}
|
|
||||||
for (String idList : ids) {
|
|
||||||
lst.addAll( StrUtils.splitSmart(idList, ",", true) );
|
|
||||||
}
|
|
||||||
allIds = lst.toArray(new String[lst.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SolrCore core = req.getCore();
|
SolrCore core = req.getCore();
|
||||||
SchemaField idField = core.getLatestSchema().getUniqueKeyField();
|
SchemaField idField = core.getLatestSchema().getUniqueKeyField();
|
||||||
FieldType fieldType = idField.getType();
|
FieldType fieldType = idField.getType();
|
||||||
|
@ -209,7 +194,7 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
SolrIndexSearcher searcher = null;
|
SolrIndexSearcher searcher = null;
|
||||||
|
|
||||||
BytesRefBuilder idBytes = new BytesRefBuilder();
|
BytesRefBuilder idBytes = new BytesRefBuilder();
|
||||||
for (String idStr : allIds) {
|
for (String idStr : reqIds.allIds) {
|
||||||
fieldType.readableToIndexed(idStr, idBytes);
|
fieldType.readableToIndexed(idStr, idBytes);
|
||||||
if (ulog != null) {
|
if (ulog != null) {
|
||||||
Object o = ulog.lookup(idBytes.get());
|
Object o = ulog.lookup(idBytes.get());
|
||||||
|
@ -297,18 +282,7 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addDocListToResponse(rb, docList);
|
||||||
// if the client specified a single id=foo, then use "doc":{
|
|
||||||
// otherwise use a standard doclist
|
|
||||||
|
|
||||||
if (ids == null && allIds.length <= 1) {
|
|
||||||
// if the doc was not found, then use a value of null.
|
|
||||||
rsp.add("doc", docList.size() > 0 ? docList.get(0) : null);
|
|
||||||
} else {
|
|
||||||
docList.setNumFound(docList.size());
|
|
||||||
rsp.addResponse(docList);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -461,25 +435,13 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
public int createSubRequests(ResponseBuilder rb) throws IOException {
|
public int createSubRequests(ResponseBuilder rb) throws IOException {
|
||||||
SolrParams params = rb.req.getParams();
|
|
||||||
String id1[] = params.getParams("id");
|
|
||||||
String ids[] = params.getParams("ids");
|
|
||||||
|
|
||||||
if (id1 == null && ids == null) {
|
final IdsRequsted reqIds = IdsRequsted.parseParams(rb.req);
|
||||||
|
if (reqIds.allIds.isEmpty()) {
|
||||||
return ResponseBuilder.STAGE_DONE;
|
return ResponseBuilder.STAGE_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> allIds = new ArrayList<>();
|
SolrParams params = rb.req.getParams();
|
||||||
if (id1 != null) {
|
|
||||||
for (String s : id1) {
|
|
||||||
allIds.add(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ids != null) {
|
|
||||||
for (String s : ids) {
|
|
||||||
allIds.addAll( StrUtils.splitSmart(s, ",", true) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle collection=...?
|
// TODO: handle collection=...?
|
||||||
|
|
||||||
|
@ -495,7 +457,7 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
|
|
||||||
|
|
||||||
Map<String, List<String>> sliceToId = new HashMap<>();
|
Map<String, List<String>> sliceToId = new HashMap<>();
|
||||||
for (String id : allIds) {
|
for (String id : reqIds.allIds) {
|
||||||
Slice slice = coll.getRouter().getTargetSlice(id, null, null, params, coll);
|
Slice slice = coll.getRouter().getTargetSlice(id, null, null, params, coll);
|
||||||
|
|
||||||
List<String> idsForShard = sliceToId.get(slice.getName());
|
List<String> idsForShard = sliceToId.get(slice.getName());
|
||||||
|
@ -524,7 +486,7 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
rb.addRequest(this, sreq);
|
rb.addRequest(this, sreq);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String shardIdList = StrUtils.join(allIds, ',');
|
String shardIdList = StrUtils.join(reqIds.allIds, ',');
|
||||||
ShardRequest sreq = new ShardRequest();
|
ShardRequest sreq = new ShardRequest();
|
||||||
|
|
||||||
sreq.purpose = 1;
|
sreq.purpose = 1;
|
||||||
|
@ -587,12 +549,26 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (docList.size() <= 1 && rb.req.getParams().getParams("ids")==null) {
|
addDocListToResponse(rb, docList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates logic for how a {@link SolrDocumentList} should be added to the response
|
||||||
|
* based on the request params used
|
||||||
|
*/
|
||||||
|
private void addDocListToResponse(final ResponseBuilder rb, final SolrDocumentList docList) {
|
||||||
|
assert null != docList;
|
||||||
|
|
||||||
|
final SolrQueryResponse rsp = rb.rsp;
|
||||||
|
final IdsRequsted reqIds = IdsRequsted.parseParams(rb.req);
|
||||||
|
|
||||||
|
if (reqIds.useSingleDocResponse) {
|
||||||
|
assert docList.size() <= 1;
|
||||||
// if the doc was not found, then use a value of null.
|
// if the doc was not found, then use a value of null.
|
||||||
rb.rsp.add("doc", docList.size() > 0 ? docList.get(0) : null);
|
rsp.add("doc", docList.size() > 0 ? docList.get(0) : null);
|
||||||
} else {
|
} else {
|
||||||
docList.setNumFound(docList.size());
|
docList.setNumFound(docList.size());
|
||||||
rb.rsp.addResponse(docList);
|
rsp.addResponse(docList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,6 +744,66 @@ public class RealTimeGetComponent extends SearchComponent
|
||||||
return new ArrayList<>(versionsToRet);
|
return new ArrayList<>(versionsToRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple struct for tracking what ids were requested and what response format is expected
|
||||||
|
* acording to the request params
|
||||||
|
*/
|
||||||
|
private final static class IdsRequsted {
|
||||||
|
/** An List (which may be empty but will never be null) of the uniqueKeys requested. */
|
||||||
|
public final List<String> allIds;
|
||||||
|
/**
|
||||||
|
* true if the params provided by the user indicate that a single doc response structure
|
||||||
|
* should be used.
|
||||||
|
* Value is meaninless if <code>ids</code> is empty.
|
||||||
|
*/
|
||||||
|
public final boolean useSingleDocResponse;
|
||||||
|
private IdsRequsted(List<String> allIds, boolean useSingleDocResponse) {
|
||||||
|
assert null != allIds;
|
||||||
|
this.allIds = allIds;
|
||||||
|
this.useSingleDocResponse = useSingleDocResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsers the <code>id</code> and <code>ids</code> params attached to the specified request object,
|
||||||
|
* and returns an <code>IdsRequsted</code> struct to use for this request.
|
||||||
|
* The <code>IdsRequsted</code> is cached in the {@link SolrQueryRequest#getContext} so subsequent
|
||||||
|
* method calls on the same request will not re-parse the params.
|
||||||
|
*/
|
||||||
|
public static IdsRequsted parseParams(SolrQueryRequest req) {
|
||||||
|
final String contextKey = IdsRequsted.class.toString() + "_PARSED_ID_PARAMS";
|
||||||
|
if (req.getContext().containsKey(contextKey)) {
|
||||||
|
return (IdsRequsted)req.getContext().get(contextKey);
|
||||||
|
}
|
||||||
|
final SolrParams params = req.getParams();
|
||||||
|
final String id[] = params.getParams("id");
|
||||||
|
final String ids[] = params.getParams("ids");
|
||||||
|
|
||||||
|
if (id == null && ids == null) {
|
||||||
|
IdsRequsted result = new IdsRequsted(Collections.<String>emptyList(), true);
|
||||||
|
req.getContext().put(contextKey, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
final List<String> allIds = new ArrayList<>((null == id ? 0 : id.length)
|
||||||
|
+ (null == ids ? 0 : (2 * ids.length)));
|
||||||
|
if (null != id) {
|
||||||
|
for (String singleId : id) {
|
||||||
|
allIds.add(singleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (null != ids) {
|
||||||
|
for (String idList : ids) {
|
||||||
|
allIds.addAll( StrUtils.splitSmart(idList, ",", true) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if the client specified a single id=foo, then use "doc":{
|
||||||
|
// otherwise use a standard doclist
|
||||||
|
IdsRequsted result = new IdsRequsted(allIds, (ids == null && allIds.size() <= 1));
|
||||||
|
req.getContext().put(contextKey, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lite weight ResultContext for use with RTG requests that can point at Realtime Searchers
|
* A lite weight ResultContext for use with RTG requests that can point at Realtime Searchers
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -387,16 +387,11 @@ public class TestRandomFlRTGCloud extends SolrCloudTestCase {
|
||||||
* trivial helper method to deal with diff response structure between using a single 'id' param vs
|
* trivial helper method to deal with diff response structure between using a single 'id' param vs
|
||||||
* 2 or more 'id' params (or 1 or more 'ids' params).
|
* 2 or more 'id' params (or 1 or more 'ids' params).
|
||||||
*
|
*
|
||||||
* NOTE: <code>expectList</code> is currently ignored due to SOLR-9309 -- instead best efforst are made to
|
|
||||||
* return a synthetic list based on whatever can be found in the response.
|
|
||||||
*
|
|
||||||
* @return List from response, or a synthetic one created from single response doc if
|
* @return List from response, or a synthetic one created from single response doc if
|
||||||
* <code>expectList</code> was false; May be empty; May be null if response included null list.
|
* <code>expectList</code> was false; May be empty; May be null if response included null list.
|
||||||
*/
|
*/
|
||||||
private static SolrDocumentList getDocsFromRTGResponse(final boolean expectList, final QueryResponse rsp) {
|
private static SolrDocumentList getDocsFromRTGResponse(final boolean expectList, final QueryResponse rsp) {
|
||||||
// TODO: blocked by SOLR-9309 (once this can be fixed, update jdocs)
|
if (expectList) {
|
||||||
if (null != rsp.getResults()) { // TODO: replace this..
|
|
||||||
// if (expectList) { // TODO: ...with this tighter check.
|
|
||||||
return rsp.getResults();
|
return rsp.getResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue