// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.result;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.yahoo.collections.ListenableArrayList;
import com.yahoo.net.URI;
import com.yahoo.prelude.fastsearch.SortDataHitSorter;
import com.yahoo.processing.response.ArrayDataList;
import com.yahoo.processing.response.DataList;
import com.yahoo.processing.response.DefaultIncomingData;
import com.yahoo.processing.response.IncomingData;
import com.yahoo.search.query.Sorting;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
*
A group of ordered hits. Since hitGroup is itself a kind of Hit,
* this can compose hierarchies of grouped hits.
*
*
Group hits has a relevancy just as other hits - they can be ordered
* between each other and in comparison to other hits.
*
*
Note that a group is by default a meta hit, but it can also contain its own content
* in addition to subgroup content, in which case it should be set to non-meta.
*
* @author bratseth
*/
public class HitGroup extends Hit implements DataList, Cloneable, Iterable {
// This does its own book-keeping of its various state variables
// (see methods towards the end). For state variables which are recursive
// (depending on the state of hits in subgroups), the strategy is to do
// book-keeping on only this immediate level, but not do recursive calls to
// find the true recursive state when queried. This is sort of a middle ground
// between handling the complexity of recursive state book-keeping and the
// query cost of not doing any book-keeping.
// There is also a method, analyse which recursively updates the recursive
// state of the group and all subgroups. This should be called if the hits
// may have changed their own state in a way that may impact the recursive
// state of this.
private ListenableArrayList hits = new ListenableArrayList<>(16);
transient private List unmodifiableHits = Collections.unmodifiableList(hits);
/** Whether or not the hits are sorted */
private boolean hitsSorted = true;
/** Whether or not deletion of hits breaks the sorted ordering */
private boolean deletionBreaksOrdering = false;
/** Whether the hits should be sorted (again) */
private boolean orderedHits = false;
/** The current number of concrete (non-meta) hits in the result */
private int concreteHitCount = 0;
/** Number of hits known to have sort data */
private int hitsWithSortData = 0;
/** The class used to determine the ordering of the hits of this */
transient private HitOrderer hitOrderer = null;
/** Accounting the number of subgroups to allow some early returns when the number is 0 */
private int subgroupCount = 0;
/**
* The number of hits not cached at this level, not counting hits in subgroups or
* any nested hitgroups themselves
*/
private int notCachedCount = 0;
/**
* A direct reference to the errors of this result, or null if there are no errors.
* The error hit will also be listed in the set of this of this result
*/
private DefaultErrorHit errorHit = null;
private final CompletableFuture