aboutsummaryrefslogtreecommitdiffstats
path: root/searchcore/src/vespa/searchcore/grouping/groupingcontext.h
blob: c29b5122f74281fb7dd358d050db5fe4cc4e9cb6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include <vespa/searchlib/aggregation/grouping.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/clock.h>
#include <vector>

namespace search::grouping {

/**
 * A Grouping Context contains all grouping expressions that should be evaluated
 * for a particular pass, together with the ability to serialize and deserialize
 * the data from/to a byte buffer.
 **/
class GroupingContext
{
public:
    using UP = std::unique_ptr<GroupingContext>;
    using Grouping = search::aggregation::Grouping;
    using GroupingList = std::vector<std::shared_ptr<Grouping>>;

    /**
     * Deserialize a grouping spec into this context.
     *
     * @param groupSpec The grouping specification to use for initialization.
     * @param groupSpecLen The length of the grouping specification, in bytes.
     **/
    void deserialize(const char *groupSpec, uint32_t groupSpecLen);

    /**
     * Create a new grouping context from a byte buffer.
     * @param groupSpec The grouping specification to use for initialization.
     * @param groupSpecLen The length of the grouping specification, in bytes.
     **/
    GroupingContext(const BitVector & validLids, const vespalib::Clock & clock, vespalib::steady_time timeOfDoom,
                    const char *groupSpec, uint32_t groupSpecLen, bool enableNestedMultivalueGrouping);

    /**
     * Create a new grouping context from a byte buffer.
     * @param groupSpec The grouping specification to use for initialization.
     * @param groupSpecLen The length of the grouping specification, in bytes.
     **/
    GroupingContext(const BitVector & validLids, const vespalib::Clock & clock, vespalib::steady_time timeOfDoom);

    /**
     * Shallow copy of references
     **/
    GroupingContext(const GroupingContext & rhs);

    GroupingContext &operator=(const GroupingContext &) = delete;

    /**
     * Add another grouping to this context.
     * @param g Pointer to the grouping object to become part of this context.
     **/
    void addGrouping(std::shared_ptr<Grouping> g);

    /**
     * Reset the context to an empty state.
     **/
    void reset() { _groupingList.clear(); }

    /**
     * Return the internal list of grouping expressions in this context.
     * @return a list of groupings.
     **/
    GroupingList &getGroupingList() noexcept { return _groupingList; }

    /**
     * Serialize the grouping expressions in this context.
     **/
    void serialize();

    /**
     * Check whether this context contains any groupings.
     **/
    bool empty() const noexcept { return _groupingList.empty(); }

    /**
     * Obtain the grouping result.
     *
     * @return grouping result
     **/
    vespalib::nbostream & getResult() { return _os; }

    /**
     * Count number of fs4hits
     *
     * @return number of fs4 hits.
     */
    size_t countFS4Hits();
    /**
     * Will inject the distribution key in the FS4Hits aggregated so far.
     *
     * @param the distribution key.
     */
    void setDistributionKey(uint32_t distributionKey);
    /**
     * Obtain the time of doom.
     */
    vespalib::steady_time getTimeOfDoom() const noexcept { return _timeOfDoom; }
    bool hasExpired() const noexcept { return _clock.getTimeNS() > _timeOfDoom; }
    /**
     * Figure out if ranking is necessary for any of the grouping requests here.
     * @return true if ranking is required.
     */
    bool needRanking() const;
    bool enableNestedMultivalueGrouping() const noexcept { return _enableNestedMultivalueGrouping; }
    const search::BitVector & getValidLids() const { return _validLids; }

    void groupUnordered(const RankedHit *searchResults, uint32_t binSize, const search::BitVector * overflow);
    void groupInRelevanceOrder(const RankedHit *searchResults, uint32_t binSize);
private:
    void aggregate(Grouping & grouping, const RankedHit * rankedHit, unsigned int len, const BitVector * bv) const;
    void aggregate(Grouping & grouping, const RankedHit * rankedHit, unsigned int len) const;
    void aggregate(Grouping & grouping, uint32_t docId, HitRank rank) const;
    unsigned int aggregateRanked(Grouping & grouping, const RankedHit * rankedHit, unsigned int len) const;
    void aggregate(Grouping & grouping, const BitVector * bv, unsigned int lidLimit) const;
    void aggregate(Grouping & grouping, const BitVector * bv, unsigned int , unsigned int topN) const;
    const BitVector       & _validLids;
    const vespalib::Clock & _clock;
    vespalib::steady_time   _timeOfDoom;
    vespalib::nbostream     _os;
    GroupingList            _groupingList;
    bool                    _enableNestedMultivalueGrouping;
};

}