1 // Copyright 2012 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.api
.search
;
5 import com
.google
.appengine
.api
.search
.SearchServicePb
.SearchParams
;
6 import com
.google
.appengine
.api
.search
.checkers
.Preconditions
;
7 import com
.google
.appengine
.api
.search
.checkers
.SortOptionsChecker
;
9 import java
.util
.ArrayList
;
10 import java
.util
.Collections
;
11 import java
.util
.List
;
14 * Definition of how to sort documents. You may specify zero or more sort
15 * expressions and set a match scorer. If you have a large index, it is
16 * advisable to set a limit.
19 public final class SortOptions
{
22 * A builder that constructs {@link SortOptions SortOptionss}.
23 * A SortOptions will evaluate each of the
24 * {@link SortExpression SortExpressions} on each search result and apply a
25 * sort order with priority given to the sort expressions from left to right.
26 * The following code illustrates creating a SortOptions specification
27 * to score documents based on decreasing product rating and then within
28 * rating scores showing cheapest products based on price plus tax,
29 * scoring at most 2000 documents.
32 * SortOptions sortOptions = SortOptions.newBuilder()
33 * .addSortExpression(SortExpression.newBuilder()
34 * .setExpression("rating")
35 * .setDirection(SortExpression.SortDirection.DESCENDING)
36 * .setDefaultValueNumeric(0))
37 * .addSortExpression(SortExpression.newBuilder()
38 * .setExpression("price + tax")
39 * .setDirection(SortExpression.SortDirection.ASCENDING)
40 * .setDefaultValueNumeric(99999999.00))
45 * The following code fragment shows how the score from a {@link MatchScorer}
46 * can be used in an expression that combines the score with one thousandth of
47 * an "importance" field. At most 1000 documents are scored.
49 * SortOptions sortOptions = SortOptions.newBuilder()
50 * .setMatchScorer(MatchScorer.newBuilder())
51 * .addSortExpression(SortExpression.newBuilder()
52 * .setExpression(String.format(
53 * "%s + (importance * .001)", SortExpression.SCORE_FIELD_NAME))
54 * .setDirection(SortExpression.SortDirection.DESCENDING)
55 * .setDefaultValueNumeric(0))
60 public static final class Builder
{ private MatchScorer matchScorer
; private Integer limit
;
62 private final List
<SortExpression
> sortExpressions
= new ArrayList
<SortExpression
>();
68 * Sets the limit on the number of documents to score.
70 * @param limit the maximum number of documents to score
71 * @return this builder
72 * @throws IllegalArgumentException if the limit is out of range
74 public Builder
setLimit(int limit
) {
75 this.limit
= SortOptionsChecker
.checkLimit(limit
);
80 * Sets a {@link MatchScorer} or {@link RescoringMatchScorer} to base some
81 * {@link SortExpression SortExpressions} on. The value of the matchScorer can
82 * be accessed by using the field name "_score".
84 * @param matchScorer the rescoring/match matchScorer to use in an expression built
86 * @return this builder
88 public Builder
setMatchScorer(MatchScorer matchScorer
) {
89 this.matchScorer
= matchScorer
;
94 * Sets the matchScorer to the {@link MatchScorer} built from the builder.
96 * @see {@link #setMatchScorer(MatchScorer)}
97 * @param builder a builder of a MatchScorer
98 * @return this builder
100 public Builder
setMatchScorer(MatchScorer
.Builder builder
) {
101 this.matchScorer
= builder
.build();
106 * Sets the matchScorer to the {@link RescoringMatchScorer} built from the
109 * @see {@link #setMatchScorer(MatchScorer)}
110 * @param builder a builder of a RescoringMatchScorer
111 * @return this builder
113 public Builder
setMatchScorer(RescoringMatchScorer
.Builder builder
) {
114 this.matchScorer
= builder
.build();
119 * Adds a {@link SortExpression} to the list of sort expressions.
121 * @param sortExpression an expression to sort documents by
122 * @return this Builder
124 public Builder
addSortExpression(SortExpression sortExpression
) {
125 this.sortExpressions
.add(Preconditions
.checkNotNull(sortExpression
,
126 "sort expression cannot be null"));
131 * Adds a {@link SortExpression} built from the builder to the list of sort
134 * @param builder a builder of SortExpression to sort documents by
135 * @return this Builder
137 public Builder
addSortExpression(SortExpression
.Builder builder
) {
138 Preconditions
.checkNotNull(builder
, "sort expression builder cannot be null");
139 this.sortExpressions
.add(builder
.build());
144 * Builds a {@link SortOptions} from the set values.
146 * @return a {@link SortOptions} built from the set values
148 public SortOptions
build() {
149 return new SortOptions(this);
153 private final List
<SortExpression
> sortExpressions
;
154 private final MatchScorer matchScorer
; private final int limit
;
157 * Constructs a text sort specification using the values from the
160 private SortOptions(Builder builder
) {
161 matchScorer
= builder
.matchScorer
;
162 limit
= Util
.defaultIfNull(builder
.limit
, SortOptionsChecker
.DEFAULT_LIMIT
);
163 sortExpressions
= new ArrayList
<SortExpression
>(builder
.sortExpressions
);
167 * @return a list of sort expressions representing a multi-dimensional sort
169 public List
<SortExpression
> getSortExpressions() {
170 return Collections
.unmodifiableList(sortExpressions
);
174 * @return a {@link MatchScorer} used to score the documents
176 public MatchScorer
getMatchScorer() {
181 * @return the limit on the number of documents to sort
183 public int getLimit() {
188 * Creates and returns a SortOptions Builder.
190 * @return a new {@link SortOptions.Builder}. Set the parameters for
191 * SortOptions on the Builder, and use the {@link Builder#build()} method
192 * to create a concrete instance of SortOptions
194 public static Builder
newBuilder() {
195 return new Builder();
198 public SearchParams
.Builder
copyToProtocolBuffer(SearchParams
.Builder builder
) {
199 SearchServicePb
.ScorerSpec
.Builder scorerSpecBuilder
= null;
200 if (matchScorer
!= null) {
201 scorerSpecBuilder
= matchScorer
.copyToScorerSpecProtocolBuffer();
203 scorerSpecBuilder
= SearchServicePb
.ScorerSpec
.newBuilder();
205 scorerSpecBuilder
.setLimit(limit
);
206 builder
.setScorerSpec(scorerSpecBuilder
);
207 for (SortExpression expression
: sortExpressions
) {
208 builder
.addSortSpec(expression
.copyToProtocolBuffer());
214 public String
toString() {
215 return String
.format("SortOptions(limit=%d, matchScorer=%s, sortExpressions=%s)",