PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java

http://github.com/apache/lucene-solr
Java | 511 lines | 357 code | 87 blank | 67 comment | 39 complexity | a29f6743158a31c91d5e6a1d260b1dee MD5 | raw file
Possible License(s): LGPL-2.1, CPL-1.0, MPL-2.0-no-copyleft-exception, JSON, Apache-2.0, AGPL-1.0, GPL-2.0, GPL-3.0, MIT, BSD-3-Clause
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.solr.handler.component;
  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import org.apache.lucene.search.Query;
  25. import org.apache.lucene.search.TotalHits;
  26. import org.apache.lucene.search.grouping.SearchGroup;
  27. import org.apache.lucene.search.grouping.TopGroups;
  28. import org.apache.lucene.util.BytesRef;
  29. import org.apache.solr.common.SolrDocument;
  30. import org.apache.solr.common.SolrDocumentList;
  31. import org.apache.solr.common.util.NamedList;
  32. import org.apache.solr.common.util.SimpleOrderedMap;
  33. import org.apache.solr.request.SolrQueryRequest;
  34. import org.apache.solr.request.SolrRequestInfo;
  35. import org.apache.solr.response.SolrQueryResponse;
  36. import org.apache.solr.search.CursorMark;
  37. import org.apache.solr.search.DocListAndSet;
  38. import org.apache.solr.search.DocSlice;
  39. import org.apache.solr.search.QParser;
  40. import org.apache.solr.search.QueryCommand;
  41. import org.apache.solr.search.QueryResult;
  42. import org.apache.solr.search.RankQuery;
  43. import org.apache.solr.search.SortSpec;
  44. import org.apache.solr.search.grouping.GroupingSpecification;
  45. import org.apache.solr.search.grouping.distributed.command.QueryCommandResult;
  46. import org.apache.solr.util.RTimer;
  47. /**
  48. * This class is experimental and will be changing in the future.
  49. *
  50. *
  51. * @since solr 1.3
  52. */
  53. public class ResponseBuilder
  54. {
  55. public SolrQueryRequest req;
  56. public SolrQueryResponse rsp;
  57. public boolean doHighlights;
  58. public boolean doFacets;
  59. public boolean doExpand;
  60. public boolean doStats;
  61. public boolean doTerms;
  62. public boolean doAnalytics;
  63. public MergeStrategy mergeFieldHandler;
  64. private boolean needDocList = false;
  65. private boolean needDocSet = false;
  66. private int fieldFlags = 0;
  67. //private boolean debug = false;
  68. private boolean debugTimings, debugQuery, debugResults, debugTrack;
  69. private QParser qparser = null;
  70. private String queryString = null;
  71. private Query query = null;
  72. private List<Query> filters = null;
  73. private SortSpec sortSpec = null;
  74. private GroupingSpecification groupingSpec;
  75. private CursorMark cursorMark;
  76. private CursorMark nextCursorMark;
  77. private List<MergeStrategy> mergeStrategies;
  78. private RankQuery rankQuery;
  79. private DocListAndSet results = null;
  80. private NamedList<Object> debugInfo = null;
  81. private RTimer timer = null;
  82. private Query highlightQuery = null;
  83. public List<SearchComponent> components;
  84. SolrRequestInfo requestInfo;
  85. public ResponseBuilder(SolrQueryRequest req, SolrQueryResponse rsp, List<SearchComponent> components)
  86. {
  87. this.req = req;
  88. this.rsp = rsp;
  89. this.components = components;
  90. this.requestInfo = SolrRequestInfo.getRequestInfo();
  91. }
  92. //////////////////////////////////////////////////////////
  93. //////////////////////////////////////////////////////////
  94. //// Distributed Search section
  95. //////////////////////////////////////////////////////////
  96. //////////////////////////////////////////////////////////
  97. public static final String FIELD_SORT_VALUES = "fsv";
  98. public static final String SHARDS = "shards";
  99. public static final String IDS = "ids";
  100. /**
  101. * public static final String NUMDOCS = "nd";
  102. * public static final String DOCFREQS = "tdf";
  103. * public static final String TERMS = "terms";
  104. * public static final String EXTRACT_QUERY_TERMS = "eqt";
  105. * public static final String LOCAL_SHARD = "local";
  106. * public static final String DOC_QUERY = "dq";
  107. * *
  108. */
  109. public static int STAGE_START = 0;
  110. public static int STAGE_PARSE_QUERY = 1000;
  111. public static int STAGE_TOP_GROUPS = 1500;
  112. public static int STAGE_EXECUTE_QUERY = 2000;
  113. public static int STAGE_GET_FIELDS = 3000;
  114. public static int STAGE_DONE = Integer.MAX_VALUE;
  115. public int stage; // What stage is this current request at?
  116. //The address of the Shard
  117. boolean isDistrib; // is this a distributed search?
  118. public String[] shards;
  119. public String[] slices; // the optional logical ids of the shards
  120. public int shards_rows = -1;
  121. public int shards_start = -1;
  122. public List<ShardRequest> outgoing; // requests to be sent
  123. public List<ShardRequest> finished; // requests that have received responses from all shards
  124. public String shortCircuitedURL;
  125. /**
  126. * This function will return true if this was a distributed search request.
  127. */
  128. public boolean isDistributed() {
  129. return this.isDistrib;
  130. }
  131. public int getShardNum(String shard) {
  132. for (int i = 0; i < shards.length; i++) {
  133. if (shards[i] == shard || shards[i].equals(shard)) return i;
  134. }
  135. return -1;
  136. }
  137. public void addRequest(SearchComponent me, ShardRequest sreq) {
  138. outgoing.add(sreq);
  139. if ((sreq.purpose & ShardRequest.PURPOSE_PRIVATE) == 0) {
  140. // if this isn't a private request, let other components modify it.
  141. for (SearchComponent component : components) {
  142. if (component != me) {
  143. component.modifyRequest(this, me, sreq);
  144. }
  145. }
  146. }
  147. }
  148. public Map<Object, ShardDoc> resultIds;
  149. // Maps uniqueKeyValue to ShardDoc, which may be used to
  150. // determine order of the doc or uniqueKey in the final
  151. // returned sequence.
  152. // Only valid after STAGE_EXECUTE_QUERY has completed.
  153. public boolean onePassDistributedQuery;
  154. public FacetComponent.FacetInfo _facetInfo;
  155. /* private... components that don't own these shouldn't use them */
  156. SolrDocumentList _responseDocs;
  157. StatsInfo _statsInfo;
  158. TermsComponent.TermsHelper _termsHelper;
  159. SimpleOrderedMap<List<NamedList<Object>>> _pivots;
  160. Object _analyticsRequestManager;
  161. boolean _isOlapAnalytics;
  162. // Context fields for grouping
  163. public final Map<String, Collection<SearchGroup<BytesRef>>> mergedSearchGroups = new HashMap<>();
  164. public final Map<String, Integer> mergedGroupCounts = new HashMap<>();
  165. public final Map<String, Map<SearchGroup<BytesRef>, Set<String>>> searchGroupToShards = new HashMap<>();
  166. public final Map<String, TopGroups<BytesRef>> mergedTopGroups = new HashMap<>();
  167. public final Map<String, QueryCommandResult> mergedQueryCommandResults = new HashMap<>();
  168. public final Map<Object, SolrDocument> retrievedDocuments = new HashMap<>();
  169. public int totalHitCount; // Hit count used when distributed grouping is performed.
  170. // Used for timeAllowed parameter. First phase elapsed time is subtracted from the time allowed for the second phase.
  171. public int firstPhaseElapsedTime;
  172. /**
  173. * Utility function to add debugging info. This will make sure a valid
  174. * debugInfo exists before adding to it.
  175. */
  176. public void addDebugInfo( String name, Object val )
  177. {
  178. if( debugInfo == null ) {
  179. debugInfo = new SimpleOrderedMap<>();
  180. }
  181. debugInfo.add( name, val );
  182. }
  183. public void addDebug(Object val, String... path) {
  184. if( debugInfo == null ) {
  185. debugInfo = new SimpleOrderedMap<>();
  186. }
  187. NamedList<Object> target = debugInfo;
  188. for (int i=0; i<path.length-1; i++) {
  189. String elem = path[i];
  190. NamedList<Object> newTarget = (NamedList<Object>)debugInfo.get(elem);
  191. if (newTarget == null) {
  192. newTarget = new SimpleOrderedMap<>();
  193. target.add(elem, newTarget);
  194. }
  195. target = newTarget;
  196. }
  197. target.add(path[path.length-1], val);
  198. }
  199. //-------------------------------------------------------------------------
  200. //-------------------------------------------------------------------------
  201. public boolean isDebug() {
  202. return debugQuery || debugTimings || debugResults || debugTrack;
  203. }
  204. /**
  205. *
  206. * @return true if all debugging options are on
  207. */
  208. public boolean isDebugAll(){
  209. return debugQuery && debugTimings && debugResults && debugTrack;
  210. }
  211. public void setDebug(boolean dbg){
  212. debugQuery = dbg;
  213. debugTimings = dbg;
  214. debugResults = dbg;
  215. debugTrack = dbg;
  216. }
  217. public void addMergeStrategy(MergeStrategy mergeStrategy) {
  218. if(mergeStrategies == null) {
  219. mergeStrategies = new ArrayList();
  220. }
  221. mergeStrategies.add(mergeStrategy);
  222. }
  223. public List<MergeStrategy> getMergeStrategies() {
  224. return this.mergeStrategies;
  225. }
  226. public RankQuery getRankQuery() {
  227. return rankQuery;
  228. }
  229. public void setRankQuery(RankQuery rankQuery) {
  230. this.rankQuery = rankQuery;
  231. }
  232. public void setResponseDocs(SolrDocumentList _responseDocs) {
  233. this._responseDocs = _responseDocs;
  234. }
  235. public SolrDocumentList getResponseDocs() {
  236. return this._responseDocs;
  237. }
  238. public boolean isDebugTrack() {
  239. return debugTrack;
  240. }
  241. public void setDebugTrack(boolean debugTrack) {
  242. this.debugTrack = debugTrack;
  243. }
  244. public boolean isDebugTimings() {
  245. return debugTimings;
  246. }
  247. public void setDebugTimings(boolean debugTimings) {
  248. this.debugTimings = debugTimings;
  249. }
  250. public boolean isDebugQuery() {
  251. return debugQuery;
  252. }
  253. public void setDebugQuery(boolean debugQuery) {
  254. this.debugQuery = debugQuery;
  255. }
  256. public boolean isDebugResults() {
  257. return debugResults;
  258. }
  259. public void setDebugResults(boolean debugResults) {
  260. this.debugResults = debugResults;
  261. }
  262. public NamedList<Object> getDebugInfo() {
  263. return debugInfo;
  264. }
  265. public void setDebugInfo(NamedList<Object> debugInfo) {
  266. this.debugInfo = debugInfo;
  267. }
  268. public int getFieldFlags() {
  269. return fieldFlags;
  270. }
  271. public void setFieldFlags(int fieldFlags) {
  272. this.fieldFlags = fieldFlags;
  273. }
  274. public List<Query> getFilters() {
  275. return filters;
  276. }
  277. public void setFilters(List<Query> filters) {
  278. this.filters = filters;
  279. }
  280. public Query getHighlightQuery() {
  281. return highlightQuery;
  282. }
  283. public void setHighlightQuery(Query highlightQuery) {
  284. this.highlightQuery = highlightQuery;
  285. }
  286. public boolean isNeedDocList() {
  287. return needDocList;
  288. }
  289. public void setNeedDocList(boolean needDocList) {
  290. this.needDocList = needDocList;
  291. }
  292. public boolean isNeedDocSet() {
  293. return needDocSet;
  294. }
  295. public void setNeedDocSet(boolean needDocSet) {
  296. this.needDocSet = needDocSet;
  297. }
  298. public QParser getQparser() {
  299. return qparser;
  300. }
  301. public void setQparser(QParser qparser) {
  302. this.qparser = qparser;
  303. }
  304. public String getQueryString() {
  305. return queryString;
  306. }
  307. public void setQueryString(String qstr) {
  308. this.queryString = qstr;
  309. }
  310. public Query getQuery() {
  311. return query;
  312. }
  313. public void setQuery(Query query) {
  314. this.query = query;
  315. }
  316. public DocListAndSet getResults() {
  317. return results;
  318. }
  319. public void setResults(DocListAndSet results) {
  320. this.results = results;
  321. }
  322. public SortSpec getSortSpec() {
  323. return sortSpec;
  324. }
  325. public void setSortSpec(SortSpec sortSpec) {
  326. this.sortSpec = sortSpec;
  327. }
  328. public GroupingSpecification getGroupingSpec() {
  329. return groupingSpec;
  330. }
  331. public void setGroupingSpec(GroupingSpecification groupingSpec) {
  332. this.groupingSpec = groupingSpec;
  333. }
  334. public boolean grouping() {
  335. return groupingSpec != null;
  336. }
  337. public RTimer getTimer() {
  338. return timer;
  339. }
  340. public void setTimer(RTimer timer) {
  341. this.timer = timer;
  342. }
  343. /**
  344. * Creates a SolrIndexSearcher.QueryCommand from this
  345. * ResponseBuilder. TimeAllowed is left unset.
  346. */
  347. public QueryCommand createQueryCommand() {
  348. QueryCommand cmd = new QueryCommand();
  349. cmd.setQuery(wrap(getQuery()))
  350. .setFilterList(getFilters())
  351. .setSort(getSortSpec().getSort())
  352. .setOffset(getSortSpec().getOffset())
  353. .setLen(getSortSpec().getCount())
  354. .setFlags(getFieldFlags())
  355. .setNeedDocSet(isNeedDocSet())
  356. .setCursorMark(getCursorMark());
  357. return cmd;
  358. }
  359. /** Calls {@link RankQuery#wrap(Query)} if there's a rank query, otherwise just returns the query. */
  360. public Query wrap(Query q) {
  361. if(this.rankQuery != null) {
  362. return this.rankQuery.wrap(q);
  363. } else {
  364. return q;
  365. }
  366. }
  367. /**
  368. * Sets results from a SolrIndexSearcher.QueryResult.
  369. */
  370. public void setResult(QueryResult result) {
  371. setResults(result.getDocListAndSet());
  372. if (result.isPartialResults()) {
  373. rsp.getResponseHeader().asShallowMap()
  374. .put(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY, Boolean.TRUE);
  375. if(getResults() != null && getResults().docList==null) {
  376. getResults().docList = new DocSlice(0, 0, new int[] {}, new float[] {}, 0, 0, TotalHits.Relation.EQUAL_TO);
  377. }
  378. }
  379. final Boolean segmentTerminatedEarly = result.getSegmentTerminatedEarly();
  380. if (segmentTerminatedEarly != null) {
  381. rsp.getResponseHeader().add(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY, segmentTerminatedEarly);
  382. }
  383. if (null != cursorMark) {
  384. assert null != result.getNextCursorMark() : "using cursor but no next cursor set";
  385. this.setNextCursorMark(result.getNextCursorMark());
  386. }
  387. }
  388. public long getNumberDocumentsFound() {
  389. if (_responseDocs == null) {
  390. return 0;
  391. }
  392. return _responseDocs.getNumFound();
  393. }
  394. public CursorMark getCursorMark() {
  395. return cursorMark;
  396. }
  397. public void setCursorMark(CursorMark cursorMark) {
  398. this.cursorMark = cursorMark;
  399. }
  400. public CursorMark getNextCursorMark() {
  401. return nextCursorMark;
  402. }
  403. public void setNextCursorMark(CursorMark nextCursorMark) {
  404. this.nextCursorMark = nextCursorMark;
  405. }
  406. public void setAnalytics(boolean doAnalytics) {
  407. this.doAnalytics = doAnalytics;
  408. }
  409. public boolean isAnalytics() {
  410. return this.doAnalytics;
  411. }
  412. public void setAnalyticsRequestManager(Object analyticsRequestManager) {
  413. this._analyticsRequestManager = analyticsRequestManager;
  414. }
  415. public Object getAnalyticsRequestManager() {
  416. return this._analyticsRequestManager;
  417. }
  418. public void setOlapAnalytics(boolean isOlapAnalytics) {
  419. this._isOlapAnalytics = isOlapAnalytics;
  420. }
  421. public boolean isOlapAnalytics() {
  422. return this._isOlapAnalytics;
  423. }
  424. }