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
;
8 import com
.google
.appengine
.api
.search
.checkers
.SearchApiLimits
;
10 import java
.util
.ArrayList
;
11 import java
.util
.Collections
;
12 import java
.util
.List
;
15 * Definition of how to sort documents. You may specify zero or more sort
16 * expressions and set a match scorer. If you have a large index, it is
17 * advisable to set a limit.
20 public final class SortOptions
{
23 * A builder that constructs {@link SortOptions SortOptionss}.
24 * A SortOptions will evaluate each of the
25 * {@link SortExpression SortExpressions} on each search result and apply a
26 * sort order with priority given to the sort expressions from left to right.
27 * The following code illustrates creating a SortOptions specification
28 * to sort documents based on decreasing product rating and then within
29 * rating showing cheapest products based on price plus tax,
30 * sorting at most 2000 documents.
33 * SortOptions sortOptions = SortOptions.newBuilder()
34 * .addSortExpression(SortExpression.newBuilder()
35 * .setExpression("rating")
36 * .setDirection(SortExpression.SortDirection.DESCENDING)
37 * .setDefaultValueNumeric(0))
38 * .addSortExpression(SortExpression.newBuilder()
39 * .setExpression("price + tax")
40 * .setDirection(SortExpression.SortDirection.ASCENDING)
41 * .setDefaultValueNumeric(99999999.00))
46 * The following code fragment shows how the score from a {@link MatchScorer}
47 * can be used in an expression that combines the score with one thousandth of
48 * an "importance" field. At most 1000 documents are scored and sorted.
50 * SortOptions sortOptions = SortOptions.newBuilder()
51 * .setMatchScorer(MatchScorer.newBuilder())
52 * .addSortExpression(SortExpression.newBuilder()
53 * .setExpression(String.format(
54 * "%s + (importance * .001)", SortExpression.SCORE_FIELD_NAME))
55 * .setDirection(SortExpression.SortDirection.DESCENDING)
56 * .setDefaultValueNumeric(0))
61 public static final class Builder
{ private MatchScorer matchScorer
; private Integer limit
;
63 private final List
<SortExpression
> sortExpressions
= new ArrayList
<SortExpression
>();
69 * Sets the limit on the number of documents to score or sort.
71 * @param limit the maximum number of documents to score or sort
72 * @return this builder
73 * @throws IllegalArgumentException if the limit is out of range
75 public Builder
setLimit(int limit
) {
76 this.limit
= SortOptionsChecker
.checkLimit(limit
);
81 * Sets a {@link MatchScorer} or {@link RescoringMatchScorer} to base some
82 * {@link SortExpression SortExpressions} on. The value of the matchScorer can
83 * be accessed by using the field name "_score".
85 * @param matchScorer the rescoring/match matchScorer to use in an expression built
87 * @return this builder
89 public Builder
setMatchScorer(MatchScorer matchScorer
) {
90 this.matchScorer
= matchScorer
;
95 * Sets the matchScorer to the {@link MatchScorer} built from the builder.
97 * @see {@link #setMatchScorer(MatchScorer)}
98 * @param builder a builder of a MatchScorer
99 * @return this builder
101 public Builder
setMatchScorer(MatchScorer
.Builder builder
) {
102 this.matchScorer
= builder
.build();
107 * Sets the matchScorer to the {@link RescoringMatchScorer} built from the
110 * @see {@link #setMatchScorer(MatchScorer)}
111 * @param builder a builder of a RescoringMatchScorer
112 * @return this builder
114 public Builder
setMatchScorer(RescoringMatchScorer
.Builder builder
) {
115 this.matchScorer
= builder
.build();
120 * Adds a {@link SortExpression} to the list of sort expressions.
122 * @param sortExpression an expression to sort documents by
123 * @return this Builder
125 public Builder
addSortExpression(SortExpression sortExpression
) {
126 this.sortExpressions
.add(Preconditions
.checkNotNull(sortExpression
,
127 "sort expression cannot be null"));
132 * Adds a {@link SortExpression} built from the builder to the list of sort
135 * @param builder a builder of SortExpression to sort documents by
136 * @return this Builder
138 public Builder
addSortExpression(SortExpression
.Builder builder
) {
139 Preconditions
.checkNotNull(builder
, "sort expression builder cannot be null");
140 this.sortExpressions
.add(builder
.build());
145 * Builds a {@link SortOptions} from the set values.
147 * @return a {@link SortOptions} built from the set values
149 public SortOptions
build() {
150 return new SortOptions(this);
154 private final List
<SortExpression
> sortExpressions
;
155 private final MatchScorer matchScorer
; private final int limit
;
158 * Constructs a text sort specification using the values from the
161 private SortOptions(Builder builder
) {
162 matchScorer
= builder
.matchScorer
;
163 limit
= Util
.defaultIfNull(builder
.limit
, SearchApiLimits
.SEARCH_DEFAULT_SORTED_LIMIT
);
164 sortExpressions
= new ArrayList
<SortExpression
>(builder
.sortExpressions
);
168 * @return a list of sort expressions representing a multi-dimensional sort
170 public List
<SortExpression
> getSortExpressions() {
171 return Collections
.unmodifiableList(sortExpressions
);
175 * @return a {@link MatchScorer} used to score the documents
177 public MatchScorer
getMatchScorer() {
182 * @return the limit on the number of documents to score or sort
184 public int getLimit() {
189 * Creates and returns a SortOptions Builder.
191 * @return a new {@link SortOptions.Builder}. Set the parameters for
192 * SortOptions on the Builder, and use the {@link Builder#build()} method
193 * to create a concrete instance of SortOptions
195 public static Builder
newBuilder() {
196 return new Builder();
199 public SearchParams
.Builder
copyToProtocolBuffer(SearchParams
.Builder builder
) {
200 SearchServicePb
.ScorerSpec
.Builder scorerSpecBuilder
= null;
201 if (matchScorer
!= null) {
202 scorerSpecBuilder
= matchScorer
.copyToScorerSpecProtocolBuffer();
204 scorerSpecBuilder
= SearchServicePb
.ScorerSpec
.newBuilder();
206 scorerSpecBuilder
.setLimit(limit
);
207 builder
.setScorerSpec(scorerSpecBuilder
);
208 for (SortExpression expression
: sortExpressions
) {
209 builder
.addSortSpec(expression
.copyToProtocolBuffer());
215 public String
toString() {
216 return String
.format("SortOptions(limit=%d, matchScorer=%s, sortExpressions=%s)",