org.apache.solr.response.transform.SubQueryAugmenterFactory Maven / Gradle / Ivy
Show all versions of solr-core Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.response.transform;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TotalHits;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.ResultContext;
import org.apache.solr.search.DocList;
import org.apache.solr.search.DocSlice;
import org.apache.solr.search.JoinQParserPlugin;
import org.apache.solr.search.ReturnFields;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SolrReturnFields;
import org.apache.solr.search.TermsQParserPlugin;
/**
* This transformer executes subquery per every result document. It must be given an unique name.
* There might be a few of them, eg fl=*,foo:[subquery],bar:[subquery]
. Every
* [subquery] occurrence adds a field into a result document with the given name, the value of this
* field is a document list, which is a result of executing subquery using document fields as an
* input.
*
* Subquery Parameters Shift
*
* if subquery is declared as fl=*,foo:[subquery]
, subquery parameters are prefixed
* with the given name and period. eg
*
* q=*:*&fl=*,foo:[subquery]&foo.q=to be continued&foo.rows=10&foo.sort=id desc
*
*
* Document Field As An Input For Subquery Parameters
*
* It's necessary to pass some document field value as a parameter for subquery. It's supported via
* implicit row.fieldname
parameters, and can be (but might not only) referred
* via Local Parameters syntax.
*
* q=name:john&fl=name,id,depts:[subquery]&depts.q={!terms f=id v=$row.dept_id}&depts.rows=10
*
Here departments are retrieved per every employee in search result. We can say that it's
* like SQL join ON emp.dept_id=dept.id
* Note, when document field has multiple values they are concatenated with comma by default, it can
* be changed by foo:[subquery separator=' ']
local parameter, this mimics {@link
* TermsQParserPlugin} to work smoothly with.
*
* Cores And Collections In SolrCloud
*
* use foo:[subquery fromIndex=departments]
invoke subquery on another core on the same
* node, it's like {@link JoinQParserPlugin} for non SolrCloud mode. But for SolrCloud just
* (and only) explicitly specify its' native parameters like collection, shards
* for subquery, eg
* q=*:*&fl=*,foo:[subquery]&foo.q=cloud&foo.collection=departments
*
* When used in Real Time Get
*
* When used in the context of a Real Time Get, the values from each document that are
* used in the subquery are the "real time" values (possibly from the transaction log), but the
* query itself is still executed against the currently open searcher. Note that this means if a
* document is updated but not yet committed, an RTG request for that document that uses
* [subquery]
could include the older (committed) version of that document, with different
* field values, in the subquery results.
*/
public class SubQueryAugmenterFactory extends TransformerFactory {
@Override
public DocTransformer create(String field, SolrParams params, SolrQueryRequest req) {
if (field.contains("[") || field.contains("]")) {
throw new SolrException(
SolrException.ErrorCode.BAD_REQUEST,
"please give an explicit name for [subquery] column ie fl=relation:[subquery ..]");
}
checkThereIsNoDupe(field, req.getContext());
String fromIndex = params.get("fromIndex");
final SolrClient solrClient;
solrClient = new EmbeddedSolrServer(req.getCore());
SolrParams subParams = retainAndShiftPrefix(req.getParams(), field + ".");
return new SubQueryAugmenter(
solrClient,
fromIndex,
field,
field,
subParams,
params.get(TermsQParserPlugin.SEPARATOR, ","));
}
@SuppressWarnings("unchecked")
private void checkThereIsNoDupe(String field, Map