下面列出了怎么用org.apache.lucene.search.grouping.GroupDocs的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
protected void finish() throws IOException {
TopDocs topDocs = topCollector.topDocs();
float maxScore;
if (withinGroupSort == null || withinGroupSort.equals(Sort.RELEVANCE)) {
maxScore = topDocs.scoreDocs.length == 0 ? Float.NaN : topDocs.scoreDocs[0].score;
} else if (needScores) {
// use top-level query to populate the scores
TopFieldCollector.populateScores(topDocs.scoreDocs, searcher, Grouping.this.query);
maxScore = maxScoreCollector.getMaxScore();
} else {
maxScore = Float.NaN;
}
GroupDocs<String> groupDocs = new GroupDocs<>(Float.NaN, maxScore, topDocs.totalHits, topDocs.scoreDocs, query.toString(), null);
if (main) {
mainResult = getDocList(groupDocs);
} else {
NamedList rsp = commonResponse();
addDocList(rsp, groupDocs);
}
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public void postCollect(IndexSearcher searcher) throws IOException {
if (firstPhaseGroups.isEmpty()) {
topGroups = new TopGroups<>(groupSort.getSort(), withinGroupSort.getSort(), 0, 0, new GroupDocs[0], Float.NaN);
return;
}
FieldType fieldType = field.getType();
if (fieldType.getNumberType() != null) {
topGroups = GroupConverter.fromMutable(field, secondPassCollector.getTopGroups(0));
} else {
topGroups = secondPassCollector.getTopGroups(0);
}
if (needScores) {
for (GroupDocs<?> group : topGroups.groups) {
TopFieldCollector.populateScores(group.scoreDocs, searcher, query);
}
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
static TopGroups<BytesRef> fromMutable(SchemaField field, TopGroups<MutableValue> values) {
if (values == null) {
return null;
}
FieldType fieldType = field.getType();
GroupDocs<BytesRef> groupDocs[] = new GroupDocs[values.groups.length];
for (int i = 0; i < values.groups.length; i++) {
GroupDocs<MutableValue> original = values.groups[i];
final BytesRef groupValue;
if (original.groupValue.exists) {
BytesRefBuilder binary = new BytesRefBuilder();
fieldType.readableToIndexed(Utils.OBJECT_TO_STRING.apply(original.groupValue.toObject()), binary);
groupValue = binary.get();
} else {
groupValue = null;
}
groupDocs[i] = new GroupDocs<>(original.score, original.maxScore, original.totalHits, original.scoreDocs, groupValue, original.groupSortValues);
}
return new TopGroups<>(values.groupSort, values.withinGroupSort, values.totalHitCount, values.totalGroupedHitCount, groupDocs, values.maxScore);
}
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 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;
}
protected void populateScoresIfNecessary() throws IOException {
if (needScores) {
for (GroupDocs<?> groups : result.groups) {
TopFieldCollector.populateScores(groups.scoreDocs, searcher, query);
}
}
}
protected DocList getDocList(@SuppressWarnings({"rawtypes"})GroupDocs groups) {
assert groups.totalHits.relation == TotalHits.Relation.EQUAL_TO;
int max = Math.toIntExact(groups.totalHits.value);
int off = groupOffset;
int len = docsPerGroup;
if (format == Format.simple) {
off = offset;
len = numGroups;
}
int docsToCollect = getMax(off, len, max);
// TODO: implement a DocList impl that doesn't need to start at offset=0
int docsCollected = Math.min(docsToCollect, groups.scoreDocs.length);
int ids[] = new int[docsCollected];
float[] scores = needScores ? new float[docsCollected] : null;
for (int i = 0; i < ids.length; i++) {
ids[i] = groups.scoreDocs[i].doc;
if (scores != null)
scores[i] = groups.scoreDocs[i].score;
}
float score = groups.maxScore;
maxScore = maxAvoidNaN(score, maxScore);
DocSlice docs = new DocSlice(off, Math.max(0, ids.length - off), ids, scores, groups.totalHits.value, score, TotalHits.Relation.EQUAL_TO);
if (getDocList) {
DocIterator iter = docs.iterator();
while (iter.hasNext())
idSet.add(iter.nextDoc());
}
return docs;
}
protected DocList createSimpleResponse() {
@SuppressWarnings({"rawtypes"})
GroupDocs[] groups = result != null ? result.groups : new GroupDocs[0];
List<Integer> ids = new ArrayList<>();
List<Float> scores = new ArrayList<>();
int docsToGather = getMax(offset, numGroups, maxDoc);
int docsGathered = 0;
float maxScore = Float.NaN;
outer:
for (@SuppressWarnings({"rawtypes"})GroupDocs group : groups) {
maxScore = maxAvoidNaN(maxScore, group.maxScore);
for (ScoreDoc scoreDoc : group.scoreDocs) {
if (docsGathered >= docsToGather) {
break outer;
}
ids.add(scoreDoc.doc);
scores.add(scoreDoc.score);
docsGathered++;
}
}
int len = docsGathered > offset ? docsGathered - offset : 0;
int[] docs = ArrayUtils.toPrimitive(ids.toArray(new Integer[ids.size()]));
float[] docScores = ArrayUtils.toPrimitive(scores.toArray(new Float[scores.size()]));
DocSlice docSlice = new DocSlice(offset, len, docs, docScores, getMatches(), maxScore, TotalHits.Relation.EQUAL_TO);
if (getDocList) {
for (int i = offset; i < docs.length; i++) {
idSet.add(docs[i]);
}
}
return docSlice;
}
@Override
@SuppressWarnings({"unchecked"})
protected void finish() throws IOException {
if (secondPass != null) {
result = secondPass.getTopGroups(0);
populateScoresIfNecessary();
}
if (main) {
mainResult = createSimpleResponse();
return;
}
@SuppressWarnings({"rawtypes"})
NamedList groupResult = commonResponse();
if (format == Format.simple) {
groupResult.add("doclist", createSimpleResponse());
return;
}
@SuppressWarnings({"rawtypes"})
List groupList = new ArrayList();
groupResult.add("groups", groupList); // grouped={ key={ groups=[
if (result == null) {
return;
}
// handle case of rows=0
if (numGroups == 0) return;
for (GroupDocs<MutableValue> group : result.groups) {
@SuppressWarnings({"rawtypes"})
NamedList nl = new SimpleOrderedMap();
groupList.add(nl); // grouped={ key={ groups=[ {
nl.add("groupValue", group.groupValue.toObject());
addDocList(nl, group);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void groupedFinishStage(final ResponseBuilder rb) {
// To have same response as non-distributed request.
GroupingSpecification groupSpec = rb.getGroupingSpec();
if (rb.mergedTopGroups.isEmpty()) {
for (String field : groupSpec.getFields()) {
rb.mergedTopGroups.put(field, new TopGroups(null, null, 0, 0, new GroupDocs[]{}, Float.NaN));
}
rb.resultIds = new HashMap<>();
}
EndResultTransformer.SolrDocumentSource solrDocumentSource = doc -> {
ShardDoc solrDoc = (ShardDoc) doc;
return rb.retrievedDocuments.get(solrDoc.id);
};
EndResultTransformer endResultTransformer;
if (groupSpec.isMain()) {
endResultTransformer = MAIN_END_RESULT_TRANSFORMER;
} else if (Grouping.Format.grouped == groupSpec.getResponseFormat()) {
endResultTransformer = new GroupedEndResultTransformer(rb.req.getSearcher());
} else if (Grouping.Format.simple == groupSpec.getResponseFormat() && !groupSpec.isMain()) {
endResultTransformer = SIMPLE_END_RESULT_TRANSFORMER;
} else {
return;
}
Map<String, Object> combinedMap = new LinkedHashMap<>();
combinedMap.putAll(rb.mergedTopGroups);
combinedMap.putAll(rb.mergedQueryCommandResults);
endResultTransformer.transform(combinedMap, rb, solrDocumentSource);
}
@SuppressWarnings({"unchecked"})
protected void addDocList(@SuppressWarnings({"rawtypes"})NamedList rsp
, @SuppressWarnings({"rawtypes"})GroupDocs groups) {
rsp.add("doclist", getDocList(groups));
}
@Override
@SuppressWarnings({"unchecked"})
protected void finish() throws IOException {
if (secondPass != null) {
result = secondPass.getTopGroups(0);
populateScoresIfNecessary();
}
if (main) {
mainResult = createSimpleResponse();
return;
}
@SuppressWarnings({"rawtypes"})
NamedList groupResult = commonResponse();
if (format == Format.simple) {
groupResult.add("doclist", createSimpleResponse());
return;
}
@SuppressWarnings({"rawtypes"})
List groupList = new ArrayList();
groupResult.add("groups", groupList); // grouped={ key={ groups=[
if (result == null) {
return;
}
// handle case of rows=0
if (numGroups == 0) return;
for (GroupDocs<BytesRef> group : result.groups) {
@SuppressWarnings({"rawtypes"})
NamedList nl = new SimpleOrderedMap();
groupList.add(nl); // grouped={ key={ groups=[ {
// To keep the response format compatable with trunk.
// In trunk MutableValue can convert an indexed value to its native type. E.g. string to int
// The only option I currently see is the use the FieldType for this
if (group.groupValue != null) {
SchemaField schemaField = searcher.getSchema().getField(groupBy);
FieldType fieldType = schemaField.getType();
// use createFields so that fields having doc values are also supported
// TODO: currently, this path is called only for string field, so
// should we just use fieldType.toObject(schemaField, group.groupValue) here?
List<IndexableField> fields = schemaField.createFields(group.groupValue.utf8ToString());
if (CollectionUtils.isNotEmpty(fields)) {
nl.add("groupValue", fieldType.toObject(fields.get(0)));
} else {
throw new SolrException(ErrorCode.INVALID_STATE,
"Couldn't create schema field for grouping, group value: " + group.groupValue.utf8ToString()
+ ", field: " + schemaField);
}
} else {
nl.add("groupValue", null);
}
addDocList(nl, group);
}
}
@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);
// we need to ensure the uniqueField is included for collating docs with their return fields
if (! rb.rsp.getReturnFields().wantsField(uniqueField.getName())) {
// the user didn't ask for it, so we have to...
sreq.params.add(CommonParams.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;
}