/** * Executes the given {@link Query} and groups the found {@link Document}s by the given groupField. * @param groupField the field to group the {@link Document}s with. * @param query the query to execute * @param options the additional options to execute the query. * @return {@link TopGroups} or null if an error occurred. */ public TopGroups<BytesRef> getGroupedDocs(final String groupField, final Query query, final SearchOptions options) { final Index index = IndexManager.getInstance().getIndex(); final IndexReader reader = index.getIndexReader(); final IndexSearcher searcher = new IndexSearcher(reader); final GroupingSearch groupingSearch = new GroupingSearch(groupField); if(options.getSort() != null) { groupingSearch.setSortWithinGroup(options.getSort()); } TopGroups<BytesRef> topGroups = null; try { topGroups = groupingSearch.search(searcher, query, 0, options.getMaxResults()); } catch (final IOException e) { LOGGER.error("Can't execute group search because of an IOException.", e); } return topGroups; }
/** Returns the TopGroups for the specified * BlockJoinQuery. The groupValue of each GroupDocs will * be the parent docID for that group. * The number of documents within each group is calculated as minimum of <code>maxDocsPerGroup</code> * and number of matched child documents for that group. * Returns null if no groups matched. * * @param query Search query * @param withinGroupSort Sort criteria within groups * @param offset Parent docs offset * @param maxDocsPerGroup Upper bound of documents per group number * @param withinGroupOffset Offset within each group of child docs * @param fillSortFields Specifies whether to add sort fields or not * @return TopGroups for specified query * @throws IOException if there is a low-level I/O error */ public TopGroups<Integer> getTopGroups(ToParentBlockJoinQuery query, Sort withinGroupSort, int offset, int maxDocsPerGroup, int withinGroupOffset, boolean fillSortFields) throws IOException { final Integer _slot = joinQueryID.get(query); if (_slot == null && totalHitCount == 0) { return null; } if (sortedGroups == null) { if (offset >= queue.size()) { return null; } sortQueue(); } else if (offset > sortedGroups.length) { return null; } return accumulateGroups(_slot == null ? -1 : _slot.intValue(), offset, maxDocsPerGroup, withinGroupOffset, withinGroupSort, fillSortFields); }
/** * {@inheritDoc} */ @Override public void transform(Map<String, ?> result, ResponseBuilder rb, SolrDocumentSource solrDocumentSource) { Object value = result.get(rb.getGroupingSpec().getFields()[0]); if (TopGroups.class.isInstance(value)) { @SuppressWarnings("unchecked") TopGroups<BytesRef> topGroups = (TopGroups<BytesRef>) value; SolrDocumentList docList = new SolrDocumentList(); docList.setStart(rb.getGroupingSpec().getOffset()); docList.setNumFound(rb.totalHitCount); Float maxScore = Float.NEGATIVE_INFINITY; for (GroupDocs<BytesRef> group : topGroups.groups) { for (ScoreDoc scoreDoc : group.scoreDocs) { if (maxScore < scoreDoc.score) { maxScore = scoreDoc.score; } docList.add(solrDocumentSource.retrieve(scoreDoc)); } } if (maxScore != Float.NEGATIVE_INFINITY) { docList.setMaxScore(maxScore); } rb.rsp.add("response", docList); } }
public Map<DocumentType, List<SearchResult>> search(String searchString) throws ParseException { Map<DocumentType, List<SearchResult>> resultMap = new TreeMap<DocumentType, List<SearchResult>>(); try { Query query = parser.parse(searchString); final SecondPassGroupingCollector collector = new SecondPassGroupingCollector("documentType", searchGroups, Sort.RELEVANCE, null, 5, true, false, true); searcher.search(query, collector); final TopGroups groups = collector.getTopGroups(0); for (GroupDocs groupDocs : groups.groups) { DocumentType docType = DocumentType.valueOf(groupDocs.groupValue); List<SearchResult> results = new ArrayList<SearchResult>(); for (ScoreDoc scoreDoc : groupDocs.scoreDocs) { Document doc = searcher.doc(scoreDoc.doc); SearchResult result = new SearchResult( docType, doc.get("name"), doc.get("url"), doc.get("className"), doc.get("package"), doc.get("ensemblePath"), doc.get("shortDescription") ); results.add(result); } resultMap.put(docType, results); } } catch (IOException e) { e.printStackTrace(); } return resultMap; }
public LindenResult parse(TopDocs topDocs, TopGroups<TopDocs> topGroupedDocs, Facets facets, FacetsCollector facetsCollector) throws IOException { LindenResult result = new LindenResult(); List<LindenHit> lindenHits; int totalHits = 0; if (topDocs != null) { totalHits = topDocs.totalHits; lindenHits = parseLindenHits(topDocs.scoreDocs); } else if (topGroupedDocs != null) { lindenHits = new ArrayList<>(); totalHits = topGroupedDocs.totalHitCount; for (GroupDocs<TopDocs> group : topGroupedDocs.groups) { List<LindenHit> groupHits = parseLindenHits(group.scoreDocs); LindenHit hitGroup = new LindenHit(groupHits.get(0)).setGroupHits(groupHits); String groupField = request.getGroupParam().getGroupField(); String groupValue = LindenUtil.getFieldStringValue(leaves, group.scoreDocs[0].doc, groupField); if (!hitGroup.isSetFields()) { hitGroup.setFields(new HashMap<String, String>()); } hitGroup.getFields().put(groupField, groupValue); lindenHits.add(hitGroup); } int groupTotal = topGroupedDocs.totalGroupCount == null ? 0 : topGroupedDocs.totalGroupCount; result.setTotalGroups(groupTotal); result.setTotalGroupHits(topGroupedDocs.totalGroupedHitCount); } else { lindenHits = new ArrayList<>(); } result.setTotalHits(totalHits); result.setHits(lindenHits); parseFacets(result, facets, facetsCollector); result.setQueryInfo(new QueryInfo().setQuery(query.toString())); if (filter != null) { result.getQueryInfo().setFilter(filter.toString()); } if (sort != null) { result.getQueryInfo().setSort(sort.toString()); } return result; }
private void compareHits(IndexReader r, IndexReader joinR, TopDocs results, TopGroups<Integer> joinResults) throws Exception { // results is 'complete'; joinResults is a subset int resultUpto = 0; int joinGroupUpto = 0; final ScoreDoc[] hits = results.scoreDocs; final GroupDocs<Integer>[] groupDocs = joinResults.groups; while(joinGroupUpto < groupDocs.length) { final GroupDocs<Integer> group = groupDocs[joinGroupUpto++]; final ScoreDoc[] groupHits = group.scoreDocs; assertNotNull(group.groupValue); final Document parentDoc = joinR.document(group.groupValue); final String parentID = parentDoc.get("parentID"); //System.out.println("GROUP groupDoc=" + group.groupDoc + " parent=" + parentDoc); assertNotNull(parentID); assertTrue(groupHits.length > 0); for(int hitIDX=0;hitIDX<groupHits.length;hitIDX++) { final Document nonJoinHit = r.document(hits[resultUpto++].doc); final Document joinHit = joinR.document(groupHits[hitIDX].doc); assertEquals(parentID, nonJoinHit.get("parentID")); assertEquals(joinHit.get("childID"), nonJoinHit.get("childID")); } if (joinGroupUpto < groupDocs.length) { // Advance non-join hit to the next parentID: //System.out.println(" next joingroupUpto=" + joinGroupUpto + " gd.length=" + groupDocs.length + " parentID=" + parentID); while(true) { assertTrue(resultUpto < hits.length); if (!parentID.equals(r.document(hits[resultUpto].doc).get("parentID"))) { break; } resultUpto++; } } } }
/** * {@inheritDoc} */ @Override public void transform(Map<String, ?> result, ResponseBuilder rb, SolrDocumentSource solrDocumentSource) { NamedList<Object> commands = new SimpleOrderedMap<>(); for (Map.Entry<String, ?> entry : result.entrySet()) { Object value = entry.getValue(); if (TopGroups.class.isInstance(value)) { @SuppressWarnings("unchecked") TopGroups<BytesRef> topGroups = (TopGroups<BytesRef>) value; NamedList<Object> command = new SimpleOrderedMap<>(); command.add("matches", rb.totalHitCount); if (topGroups.totalGroupCount != null) { command.add("ngroups", topGroups.totalGroupCount); } SolrDocumentList docList = new SolrDocumentList(); docList.setStart(rb.getGroupingSpec().getOffset()); docList.setNumFound(topGroups.totalHitCount); Float maxScore = Float.NEGATIVE_INFINITY; for (GroupDocs<BytesRef> group : topGroups.groups) { for (ScoreDoc scoreDoc : group.scoreDocs) { if (maxScore < scoreDoc.score) { maxScore = scoreDoc.score; } docList.add(solrDocumentSource.retrieve(scoreDoc)); } } if (maxScore != Float.NEGATIVE_INFINITY) { docList.setMaxScore(maxScore); } command.add("doclist", docList); commands.add(entry.getKey(), command); } } rb.rsp.add("grouped", commands); }
@Override @SuppressWarnings("unchecked") public TopGroups<BytesRef> result() { if (firstPhaseGroups.isEmpty()) { return new TopGroups<>(groupSort.getSort(), sortWithinGroup.getSort(), 0, 0, new GroupDocs[0], Float.NaN); } return secondPassCollector.getTopGroups(0); }
@Test public void testGrouping() throws IOException { Document doc1 = buildLuceneDoc("field1", "value1", true); Document doc2 = buildLuceneDoc("field1", "value1", true); Document doc3 = buildLuceneDoc("field1", "value2", true); index(doc1, doc2, doc3); GroupingSearch groupingSearch = new GroupingSearch("field1"); TopGroups<Object> topGroups = groupingSearch.search(openSearcher(), new MatchAllDocsQuery(), 0, 10); assertEquals(3, topGroups.totalHitCount); assertEquals(2, topGroups.groups.length); }
/** * {@inheritDoc} */ @Override public void transform(Map<String, ?> result, ResponseBuilder rb, SolrDocumentSource solrDocumentSource) { NamedList<Object> commands = new SimpleOrderedMap<Object>(); for (Map.Entry<String, ?> entry : result.entrySet()) { Object value = entry.getValue(); if (TopGroups.class.isInstance(value)) { @SuppressWarnings("unchecked") TopGroups<BytesRef> topGroups = (TopGroups<BytesRef>) value; NamedList<Object> command = new SimpleOrderedMap<Object>(); command.add("matches", rb.totalHitCount); if (topGroups.totalGroupCount != null) { command.add("ngroups", topGroups.totalGroupCount); } SolrDocumentList docList = new SolrDocumentList(); docList.setStart(rb.getGroupingSpec().getOffset()); docList.setNumFound(topGroups.totalHitCount); Float maxScore = Float.NEGATIVE_INFINITY; for (GroupDocs<BytesRef> group : topGroups.groups) { for (ScoreDoc scoreDoc : group.scoreDocs) { if (maxScore < scoreDoc.score) { maxScore = scoreDoc.score; } docList.add(solrDocumentSource.retrieve(scoreDoc)); } } if (maxScore != Float.NEGATIVE_INFINITY) { docList.setMaxScore(maxScore); } command.add("doclist", docList); commands.add(entry.getKey(), command); } } rb.rsp.add("grouped", commands); }
@Override @SuppressWarnings("unchecked") public TopGroups<BytesRef> result() { if (firstPhaseGroups.isEmpty()) { return new TopGroups<BytesRef>(groupSort.getSort(), sortWithinGroup.getSort(), 0, 0, new GroupDocs[0], Float.NaN); } return secondPassCollector.getTopGroups(0); }
/** * Queries a feature index of a list of files, returning specified page of specified size. * If no paging parameters are passed, returns all results * * @param files a {@link List} of {@link FeatureFile}, which indexes to search * @param query a query to search in index * @param vcfInfoFields list of info fields to retrieve * @param page number of a page to display * @param pageSize number of entries per page * @param orderBy object, that specifies sorting * @return a {List} of {@code FeatureIndexEntry} objects that satisfy index query * @throws IOException if something is wrong in the filesystem */ public <T extends FeatureIndexEntry> IndexSearchResult<T> searchFileIndexesPaging(List<? extends FeatureFile> files, Query query, List<String> vcfInfoFields, Integer page, Integer pageSize, List<VcfFilterForm.OrderBy> orderBy) throws IOException { if (CollectionUtils.isEmpty(files)) { return new IndexSearchResult<>(Collections.emptyList(), false, 0); } List<FeatureIndexEntry> entries; int totalHits = 0; SimpleFSDirectory[] indexes = fileManager.getIndexesForFiles(files); try (MultiReader reader = openMultiReader(indexes)) { if (reader.numDocs() == 0) { return new IndexSearchResult<>(Collections.emptyList(), false, 0); } IndexSearcher searcher = new IndexSearcher(reader); GroupingSearch groupingSearch = new GroupingSearch(FeatureIndexFields.UID.fieldName); setSorting(orderBy, groupingSearch, files); TopGroups<String> topGroups = groupingSearch.search(searcher, query, page == null ? 0 : (page - 1) * pageSize, page == null ? reader.numDocs() : pageSize); final ScoreDoc[] hits = new ScoreDoc[topGroups.groups.length]; for (int i = 0; i < topGroups.groups.length; i++) { hits[i] = topGroups.groups[i].scoreDocs[0]; } entries = new ArrayList<>(hits.length); for (ScoreDoc hit : hits) { entries.add(createIndexEntry(hit, new HashMap<>(), searcher, vcfInfoFields)); } } finally { for (SimpleFSDirectory index : indexes) { IOUtils.closeQuietly(index); } } return new IndexSearchResult<>((List<T>) entries, false, totalHits); }
public void testEmptyChildFilter() throws Exception { final Directory dir = newDirectory(); final IndexWriterConfig config = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())); config.setMergePolicy(NoMergePolicy.INSTANCE); // we don't want to merge - since we rely on certain segment setup final IndexWriter w = new IndexWriter(dir, config); final List<Document> docs = new ArrayList<>(); docs.add(makeJob("java", 2007)); docs.add(makeJob("python", 2010)); docs.add(makeResume("Lisa", "United Kingdom")); w.addDocuments(docs); docs.clear(); docs.add(makeJob("ruby", 2005)); docs.add(makeJob("java", 2006)); docs.add(makeResume("Frank", "United States")); w.addDocuments(docs); w.commit(); int num = atLeast(10); // produce a segment that doesn't have a value in the docType field for (int i = 0; i < num; i++) { docs.clear(); docs.add(makeJob("java", 2007)); w.addDocuments(docs); } IndexReader r = DirectoryReader.open(w, random().nextBoolean()); w.close(); assertTrue(r.leaves().size() > 1); IndexSearcher s = new IndexSearcher(r); Filter parentsFilter = new FixedBitSetCachingWrapperFilter(new QueryWrapperFilter(new TermQuery(new Term("docType", "resume")))); BooleanQuery childQuery = new BooleanQuery(); childQuery.add(new BooleanClause(new TermQuery(new Term("skill", "java")), Occur.MUST)); childQuery.add(new BooleanClause(NumericRangeQuery.newIntRange("year", 2006, 2011, true, true), Occur.MUST)); ToParentBlockJoinQuery childJoinQuery = new ToParentBlockJoinQuery(childQuery, parentsFilter, ScoreMode.Avg); BooleanQuery fullQuery = new BooleanQuery(); fullQuery.add(new BooleanClause(childJoinQuery, Occur.MUST)); fullQuery.add(new BooleanClause(new MatchAllDocsQuery(), Occur.MUST)); ToParentBlockJoinCollector c = new ToParentBlockJoinCollector(Sort.RELEVANCE, 1, true, true); s.search(fullQuery, c); TopGroups<Integer> results = c.getTopGroups(childJoinQuery, null, 0, 10, 0, true); assertFalse(Float.isNaN(results.maxScore)); assertEquals(1, results.totalGroupedHitCount); assertEquals(1, results.groups.length); final GroupDocs<Integer> group = results.groups[0]; Document childDoc = s.doc(group.scoreDocs[0].doc); assertEquals("java", childDoc.get("skill")); assertNotNull(group.groupValue); Document parentDoc = s.doc(group.groupValue); assertEquals("Lisa", parentDoc.get("name")); r.close(); dir.close(); }
public void testBugCausedByRewritingTwice() throws IOException { final Directory dir = newDirectory(); final RandomIndexWriter w = new RandomIndexWriter(random(), dir); final List<Document> docs = new ArrayList<>(); for (int i=0;i<10;i++) { docs.clear(); docs.add(makeJob("ruby", i)); docs.add(makeJob("java", 2007)); docs.add(makeResume("Frank", "United States")); w.addDocuments(docs); } IndexReader r = w.getReader(); w.close(); IndexSearcher s = newSearcher(r); MultiTermQuery qc = NumericRangeQuery.newIntRange("year", 2007, 2007, true, true); // Hacky: this causes the query to need 2 rewrite // iterations: qc.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE); Filter parentsFilter = new FixedBitSetCachingWrapperFilter(new QueryWrapperFilter(new TermQuery(new Term("docType", "resume")))); int h1 = qc.hashCode(); Query qw1 = qc.rewrite(r); int h2 = qw1.hashCode(); Query qw2 = qw1.rewrite(r); int h3 = qw2.hashCode(); assertTrue(h1 != h2); assertTrue(h2 != h3); assertTrue(h3 != h1); ToParentBlockJoinQuery qp = new ToParentBlockJoinQuery(qc, parentsFilter, ScoreMode.Max); ToParentBlockJoinCollector c = new ToParentBlockJoinCollector(Sort.RELEVANCE, 10, true, true); s.search(qp, c); TopGroups<Integer> groups = c.getTopGroups(qp, Sort.INDEXORDER, 0, 10, 0, true); for (GroupDocs<Integer> group : groups.groups) { assertEquals(1, group.totalHits); } r.close(); dir.close(); }
public void testSometimesParentOnlyMatches() throws Exception { Directory d = newDirectory(); RandomIndexWriter w = new RandomIndexWriter(random(), d); Document parent = new Document(); parent.add(new StoredField("parentID", "0")); parent.add(newTextField("parentText", "text", Field.Store.NO)); parent.add(newStringField("isParent", "yes", Field.Store.NO)); List<Document> docs = new ArrayList<>(); Document child = new Document(); docs.add(child); child.add(new StoredField("childID", "0")); child.add(newTextField("childText", "text", Field.Store.NO)); // parent last: docs.add(parent); w.addDocuments(docs); docs.clear(); parent = new Document(); parent.add(newTextField("parentText", "text", Field.Store.NO)); parent.add(newStringField("isParent", "yes", Field.Store.NO)); parent.add(new StoredField("parentID", "1")); // parent last: docs.add(parent); w.addDocuments(docs); IndexReader r = w.getReader(); w.close(); Query childQuery = new TermQuery(new Term("childText", "text")); Filter parentsFilter = new FixedBitSetCachingWrapperFilter(new QueryWrapperFilter(new TermQuery(new Term("isParent", "yes")))); ToParentBlockJoinQuery childJoinQuery = new ToParentBlockJoinQuery(childQuery, parentsFilter, ScoreMode.Avg); BooleanQuery parentQuery = new BooleanQuery(); parentQuery.add(childJoinQuery, Occur.SHOULD); parentQuery.add(new TermQuery(new Term("parentText", "text")), Occur.SHOULD); ToParentBlockJoinCollector c = new ToParentBlockJoinCollector(new Sort(new SortField("parentID", SortField.Type.STRING)), 10, true, true); newSearcher(r).search(parentQuery, c); TopGroups<Integer> groups = c.getTopGroups(childJoinQuery, null, 0, 10, 0, false); // Two parents: assertEquals(2, groups.totalGroupCount.intValue()); // One child docs: assertEquals(1, groups.totalGroupedHitCount); GroupDocs<Integer> group = groups.groups[0]; Document doc = r.document(group.groupValue.intValue()); assertEquals("0", doc.get("parentID")); group = groups.groups[1]; doc = r.document(group.groupValue.intValue()); assertEquals("1", doc.get("parentID")); r.close(); d.close(); }
public void testChildQueryNeverMatches() throws Exception { Directory d = newDirectory(); RandomIndexWriter w = new RandomIndexWriter(random(), d); Document parent = new Document(); parent.add(new StoredField("parentID", "0")); parent.add(newTextField("parentText", "text", Field.Store.NO)); parent.add(newStringField("isParent", "yes", Field.Store.NO)); List<Document> docs = new ArrayList<>(); Document child = new Document(); docs.add(child); child.add(new StoredField("childID", "0")); child.add(newTextField("childText", "text", Field.Store.NO)); // parent last: docs.add(parent); w.addDocuments(docs); docs.clear(); parent = new Document(); parent.add(newTextField("parentText", "text", Field.Store.NO)); parent.add(newStringField("isParent", "yes", Field.Store.NO)); parent.add(new StoredField("parentID", "1")); // parent last: docs.add(parent); w.addDocuments(docs); IndexReader r = w.getReader(); w.close(); // never matches: Query childQuery = new TermQuery(new Term("childText", "bogus")); Filter parentsFilter = new FixedBitSetCachingWrapperFilter(new QueryWrapperFilter(new TermQuery(new Term("isParent", "yes")))); ToParentBlockJoinQuery childJoinQuery = new ToParentBlockJoinQuery(childQuery, parentsFilter, ScoreMode.Avg); BooleanQuery parentQuery = new BooleanQuery(); parentQuery.add(childJoinQuery, Occur.SHOULD); parentQuery.add(new TermQuery(new Term("parentText", "text")), Occur.SHOULD); ToParentBlockJoinCollector c = new ToParentBlockJoinCollector(new Sort(new SortField("parentID", SortField.Type.STRING)), 10, true, true); newSearcher(r).search(parentQuery, c); TopGroups<Integer> groups = c.getTopGroups(childJoinQuery, null, 0, 10, 0, false); // Two parents: assertEquals(2, groups.totalGroupCount.intValue()); // One child docs: assertEquals(0, groups.totalGroupedHitCount); GroupDocs<Integer> group = groups.groups[0]; Document doc = r.document(group.groupValue.intValue()); assertEquals("0", doc.get("parentID")); group = groups.groups[1]; doc = r.document(group.groupValue.intValue()); assertEquals("1", doc.get("parentID")); r.close(); d.close(); }
protected NamedList serializeTopGroups(TopGroups<BytesRef> data, SchemaField groupField) throws IOException { NamedList<Object> result = new NamedList<>(); result.add("totalGroupedHitCount", data.totalGroupedHitCount); result.add("totalHitCount", data.totalHitCount); if (data.totalGroupCount != null) { result.add("totalGroupCount", data.totalGroupCount); } CharsRef spare = new CharsRef(); final IndexSchema schema = rb.req.getSearcher().getSchema(); SchemaField uniqueField = schema.getUniqueKeyField(); for (GroupDocs<BytesRef> searchGroup : data.groups) { NamedList<Object> groupResult = new NamedList<>(); groupResult.add("totalHits", searchGroup.totalHits); if (!Float.isNaN(searchGroup.maxScore)) { groupResult.add("maxScore", searchGroup.maxScore); } List<NamedList<Object>> documents = new ArrayList<>(); for (int i = 0; i < searchGroup.scoreDocs.length; i++) { NamedList<Object> document = new NamedList<>(); documents.add(document); Document doc = retrieveDocument(uniqueField, searchGroup.scoreDocs[i].doc); document.add("id", uniqueField.getType().toExternal(doc.getField(uniqueField.getName()))); if (!Float.isNaN(searchGroup.scoreDocs[i].score)) { document.add("score", searchGroup.scoreDocs[i].score); } if (!(searchGroup.scoreDocs[i] instanceof FieldDoc)) { continue; } FieldDoc fieldDoc = (FieldDoc) searchGroup.scoreDocs[i]; Object[] convertedSortValues = new Object[fieldDoc.fields.length]; for (int j = 0; j < fieldDoc.fields.length; j++) { Object sortValue = fieldDoc.fields[j]; Sort sortWithinGroup = rb.getGroupingSpec().getSortWithinGroup(); SchemaField field = sortWithinGroup.getSort()[j].getField() != null ? schema.getFieldOrNull(sortWithinGroup.getSort()[j].getField()) : null; if (field != null) { FieldType fieldType = field.getType(); if (sortValue != null) { sortValue = fieldType.marshalSortValue(sortValue); } } convertedSortValues[j] = sortValue; } document.add("sortValues", convertedSortValues); } groupResult.add("documents", documents); String groupValue = searchGroup.groupValue != null ? groupField.getType().indexedToReadable(searchGroup.groupValue.utf8ToString()): null; result.add(groupValue, groupResult); } return result; }
@Override public ShardRequest[] constructRequest(ResponseBuilder rb) { HashMap<String, Set<ShardDoc>> shardMap = new HashMap<>(); for (TopGroups<BytesRef> topGroups : rb.mergedTopGroups.values()) { for (GroupDocs<BytesRef> group : topGroups.groups) { mapShardToDocs(shardMap, group.scoreDocs); } } for (QueryCommandResult queryCommandResult : rb.mergedQueryCommandResults.values()) { mapShardToDocs(shardMap, queryCommandResult.getTopDocs().scoreDocs); } ShardRequest[] shardRequests = new ShardRequest[shardMap.size()]; SchemaField uniqueField = rb.req.getSchema().getUniqueKeyField(); int i = 0; for (Collection<ShardDoc> shardDocs : shardMap.values()) { ShardRequest sreq = new ShardRequest(); sreq.purpose = ShardRequest.PURPOSE_GET_FIELDS; sreq.shards = new String[] {shardDocs.iterator().next().shard}; sreq.params = new ModifiableSolrParams(); sreq.params.add( rb.req.getParams()); sreq.params.remove(GroupParams.GROUP); sreq.params.remove(CommonParams.SORT); sreq.params.remove(ResponseBuilder.FIELD_SORT_VALUES); String fl = sreq.params.get(CommonParams.FL); if (fl != null) { fl = fl.trim(); // currently, "score" is synonymous with "*,score" so // don't add "id" if the fl is empty or "score" or it would change the meaning. if (fl.length()!=0 && !"score".equals(fl) && !"*".equals(fl)) { sreq.params.set(CommonParams.FL, fl+','+uniqueField.getName()); } } List<String> ids = new ArrayList<>(shardDocs.size()); for (ShardDoc shardDoc : shardDocs) { ids.add(shardDoc.id.toString()); } sreq.params.add(ShardParams.IDS, StrUtils.join(ids, ',')); shardRequests[i++] = sreq; } return shardRequests; }
protected NamedList serializeTopGroups(TopGroups<BytesRef> data, SchemaField groupField) throws IOException { NamedList<Object> result = new NamedList<Object>(); result.add("totalGroupedHitCount", data.totalGroupedHitCount); result.add("totalHitCount", data.totalHitCount); if (data.totalGroupCount != null) { result.add("totalGroupCount", data.totalGroupCount); } CharsRef spare = new CharsRef(); SchemaField uniqueField = rb.req.getSearcher().getSchema().getUniqueKeyField(); for (GroupDocs<BytesRef> searchGroup : data.groups) { NamedList<Object> groupResult = new NamedList<Object>(); groupResult.add("totalHits", searchGroup.totalHits); if (!Float.isNaN(searchGroup.maxScore)) { groupResult.add("maxScore", searchGroup.maxScore); } List<NamedList<Object>> documents = new ArrayList<NamedList<Object>>(); for (int i = 0; i < searchGroup.scoreDocs.length; i++) { NamedList<Object> document = new NamedList<Object>(); documents.add(document); Document doc = retrieveDocument(uniqueField, searchGroup.scoreDocs[i].doc); document.add("id", uniqueField.getType().toExternal(doc.getField(uniqueField.getName()))); if (!Float.isNaN(searchGroup.scoreDocs[i].score)) { document.add("score", searchGroup.scoreDocs[i].score); } if (!(searchGroup.scoreDocs[i] instanceof FieldDoc)) { continue; } FieldDoc fieldDoc = (FieldDoc) searchGroup.scoreDocs[i]; Object[] convertedSortValues = new Object[fieldDoc.fields.length]; for (int j = 0; j < fieldDoc.fields.length; j++) { Object sortValue = fieldDoc.fields[j]; Sort sortWithinGroup = rb.getGroupingSpec().getSortWithinGroup(); SchemaField field = sortWithinGroup.getSort()[j].getField() != null ? rb.req.getSearcher().getSchema().getFieldOrNull(sortWithinGroup.getSort()[j].getField()) : null; if (field != null) { FieldType fieldType = field.getType(); if (sortValue instanceof BytesRef) { UnicodeUtil.UTF8toUTF16((BytesRef)sortValue, spare); String indexedValue = spare.toString(); sortValue = fieldType.toObject(field.createField(fieldType.indexedToReadable(indexedValue), 1.0f)); } else if (sortValue instanceof String) { sortValue = fieldType.toObject(field.createField(fieldType.indexedToReadable((String) sortValue), 1.0f)); } } convertedSortValues[j] = sortValue; } document.add("sortValues", convertedSortValues); } groupResult.add("documents", documents); String groupValue = searchGroup.groupValue != null ? groupField.getType().indexedToReadable(searchGroup.groupValue.utf8ToString()): null; result.add(groupValue, groupResult); } return result; }
@Override public ShardRequest[] constructRequest(ResponseBuilder rb) { HashMap<String, Set<ShardDoc>> shardMap = new HashMap<String,Set<ShardDoc>>(); for (TopGroups<BytesRef> topGroups : rb.mergedTopGroups.values()) { for (GroupDocs<BytesRef> group : topGroups.groups) { mapShardToDocs(shardMap, group.scoreDocs); } } for (QueryCommandResult queryCommandResult : rb.mergedQueryCommandResults.values()) { mapShardToDocs(shardMap, queryCommandResult.getTopDocs().scoreDocs); } ShardRequest[] shardRequests = new ShardRequest[shardMap.size()]; SchemaField uniqueField = rb.req.getSchema().getUniqueKeyField(); int i = 0; for (Collection<ShardDoc> shardDocs : shardMap.values()) { ShardRequest sreq = new ShardRequest(); sreq.purpose = ShardRequest.PURPOSE_GET_FIELDS; sreq.shards = new String[] {shardDocs.iterator().next().shard}; sreq.params = new ModifiableSolrParams(); sreq.params.add( rb.req.getParams()); sreq.params.remove(GroupParams.GROUP); sreq.params.remove(CommonParams.SORT); sreq.params.remove(ResponseBuilder.FIELD_SORT_VALUES); String fl = sreq.params.get(CommonParams.FL); if (fl != null) { fl = fl.trim(); // currently, "score" is synonymous with "*,score" so // don't add "id" if the fl is empty or "score" or it would change the meaning. if (fl.length()!=0 && !"score".equals(fl) && !"*".equals(fl)) { sreq.params.set(CommonParams.FL, fl+','+uniqueField.getName()); } } List<String> ids = new ArrayList<String>(shardDocs.size()); for (ShardDoc shardDoc : shardDocs) { ids.add(shardDoc.id.toString()); } sreq.params.add(ShardParams.IDS, StrUtils.join(ids, ',')); shardRequests[i++] = sreq; } return shardRequests; }