aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/grouping/GroupingRequest.java
blob: bb46b4d21666e2e874e4cc6d56379a77c0162c46 (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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.grouping;

import com.yahoo.api.annotations.Beta;
import com.yahoo.net.URI;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.grouping.request.GroupingOperation;
import com.yahoo.search.grouping.result.Group;
import com.yahoo.search.grouping.result.RootGroup;
import com.yahoo.search.grouping.result.RootId;
import com.yahoo.search.query.Select;
import com.yahoo.search.result.Hit;

import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.TimeZone;

/**
 * An instance of this class represents one of many grouping requests that are attached to a {@link Query}. Use the
 * factory method {@link #newInstance(com.yahoo.search.Query)} to create a new instance of this, then create and set the
 * {@link GroupingOperation} using {@link #setRootOperation(GroupingOperation)}. Once the search returns, access the
 * result {@link Group} using the {@link #getResultGroup(Result)} method.
 *
 * @author Simon Thoresen Hult
 * @author bratseth
 */
public class GroupingRequest {

    private final Select parent;
    private final List<Continuation> continuations = new ArrayList<>();
    private GroupingOperation root;
    private TimeZone timeZone;
    private Integer defaultMaxHits;
    private Integer defaultMaxGroups;
    private Long globalMaxGroups;
    private Double defaultPrecisionFactor;

    private GroupingRequest(Select parent) {
        this.parent = parent;
    }

    private GroupingRequest(Select parent,
                            List<Continuation> continuations,
                            GroupingOperation root,
                            TimeZone timeZone,
                            Integer defaultMaxHits,
                            Integer defaultMaxGroups,
                            Long globalMaxGroups,
                            Double defaultPrecisionFactor) {
        this.parent = parent;
        continuations.forEach(item -> this.continuations.add(item.copy()));
        this.root = root != null ? root.copy(null) : null;
        this.timeZone = timeZone;
        this.defaultMaxHits = defaultMaxHits;
        this.defaultMaxGroups = defaultMaxGroups;
        this.globalMaxGroups = globalMaxGroups;
        this.defaultPrecisionFactor = defaultPrecisionFactor;
    }

    /** Returns a deep copy of this */
    public GroupingRequest copy(Select parentOfCopy) {
        return new GroupingRequest(parentOfCopy, continuations, root, timeZone, defaultMaxHits, defaultMaxGroups,
                globalMaxGroups, defaultPrecisionFactor);
    }

    /**
     * Returns the id of this GroupingRequest.
     * This id is injected into the {@link RootGroup} of the final result, and
     * allows tracking of per-request meta data.
     *
     * @return the id of this request, or -1 if it has been removed from the query select statement
     */
    public int getRequestId() {
        return parent.getGrouping().indexOf(this);
    }

    /**
     * Returns the root {@link GroupingOperation} that defines this request. As long as this remains unset, the request
     * is void.
     *
     * @return the root operation.
     */
    public GroupingOperation getRootOperation() {
        return root;
    }

    /**
     * Sets the root {@link GroupingOperation} that defines this request. As long as this remains unset, the request is
     * void.
     *
     * @param root the root operation to set.
     * @return this, to allow chaining.
     */
    public GroupingRequest setRootOperation(GroupingOperation root) {
        this.root = root;
        return this;
    }

    /**
     * Returns the {@link TimeZone} used when resolving time expressions such as {@link
     * com.yahoo.search.grouping.request.DayOfMonthFunction} and {@link com.yahoo.search.grouping.request.HourOfDayFunction}.
     *
     * @return the time zone in use.
     */
    public TimeZone getTimeZone() {
        return timeZone;
    }

    /**
     * Sets the {@link TimeZone} used when resolving time expressions such as {@link
     * com.yahoo.search.grouping.request.DayOfMonthFunction} and {@link com.yahoo.search.grouping.request.HourOfDayFunction}.
     *
     * @param timeZone the time zone to set.
     * @return this, to allow chaining.
     */
    public GroupingRequest setTimeZone(TimeZone timeZone) {
        this.timeZone = timeZone;
        return this;
    }

    /**
     * Returns the root result {@link RootGroup} that corresponds to this request. This is not available until the
     * search returns. Because searchers are allowed to modify both {@link Result} and {@link Hit} objects freely, this
     * method requires that you pass it the current {@link Result} object as argument.
     *
     * @param result the search result that contains the root group.
     * @return the result {@link RootGroup} of this request, or null if not found.
     */
    public RootGroup getResultGroup(Result result) {
        Hit root = result.hits().get(new URI(new RootId(getRequestId()).toString()), -1);
        if ( ! (root instanceof RootGroup)) {
            return null;
        }
        return (RootGroup)root;
    }

    /**
     * Returns the list of {@link Continuation}s of this request. This is used by the executing grouping searcher to
     * allow pagination of grouping results.
     *
     * @return the list of Continuations.
     */
    public List<Continuation> continuations() {
        return continuations;
    }

    @Beta
    public OptionalInt defaultMaxHits() {
        return defaultMaxHits != null ? OptionalInt.of(defaultMaxHits) : OptionalInt.empty();
    }

    @Beta public void setDefaultMaxHits(int v) { this.defaultMaxHits = v; }

    @Beta
    public OptionalInt defaultMaxGroups() {
        return defaultMaxGroups != null ? OptionalInt.of(defaultMaxGroups) : OptionalInt.empty();
    }

    @Beta public void setDefaultMaxGroups(int v) { this.defaultMaxGroups = v; }

    @Beta
    public OptionalLong globalMaxGroups() {
        return globalMaxGroups != null ? OptionalLong.of(globalMaxGroups) : OptionalLong.empty();
    }

    @Beta public void setGlobalMaxGroups(long v) { this.globalMaxGroups = v; }

    @Beta
    public OptionalDouble defaultPrecisionFactor() {
        return defaultPrecisionFactor != null ? OptionalDouble.of(defaultPrecisionFactor) : OptionalDouble.empty();
    }

    @Beta void setDefaultPrecisionFactor(double v) { this.defaultPrecisionFactor = v; }

    /**
     * Creates a new grouping request and adds it to the query.getSelect().getGrouping() list
     *
     * @param query the query to attach the request to.
     * @return The created request.
     */
    public static GroupingRequest newInstance(Query query) {
        GroupingRequest newRequest = new GroupingRequest(query.getSelect());
        query.getSelect().getGrouping().add(newRequest);
        return newRequest;
    }

    @Override
    public String toString() {
        return root == null ? "(empty)" : root.toString();
    }

}