Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / search / SortOptions.java
blobfbc49bf2c5bb07bcd8283c97e0783b13c5a0e8e8
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;
14 /**
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 {
22 /**
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.
31 * <p>
32 * <pre>
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))
42 * .setLimit(1000)
43 * .build();
44 * </pre>
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.
49 * <pre>
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))
57 * .setLimit(1000)
58 * .build();
59 * </pre>
61 public static final class Builder { private MatchScorer matchScorer; private Integer limit;
63 private final List<SortExpression> sortExpressions = new ArrayList<SortExpression>();
65 private Builder() {
68 /**
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);
77 return this;
80 /**
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
86 * on "_score"
87 * @return this builder
89 public Builder setMatchScorer(MatchScorer matchScorer) {
90 this.matchScorer = matchScorer;
91 return this;
94 /**
95 * Sets the matchScorer to the {@link MatchScorer} built from the builder.
97 * @see #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();
103 return this;
107 * Sets the matchScorer to the {@link RescoringMatchScorer} built from the
108 * builder.
110 * @see #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();
116 return this;
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"));
128 return this;
132 * Adds a {@link SortExpression} built from the builder to the list of sort
133 * expressions.
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());
141 return this;
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
159 * {@link Builder}.
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() {
178 return matchScorer;
182 * @return the limit on the number of documents to score or sort
184 public int getLimit() {
185 return limit;
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 SearchParams.Builder copyToProtocolBuffer(SearchParams.Builder builder) {
200 SearchServicePb.ScorerSpec.Builder scorerSpecBuilder = null;
201 if (matchScorer != null) {
202 scorerSpecBuilder = matchScorer.copyToScorerSpecProtocolBuffer();
203 } else {
204 scorerSpecBuilder = SearchServicePb.ScorerSpec.newBuilder();
206 scorerSpecBuilder.setLimit(limit);
207 builder.setScorerSpec(scorerSpecBuilder);
208 for (SortExpression expression : sortExpressions) {
209 builder.addSortSpec(expression.copyToProtocolBuffer());
211 return builder;
214 @Override
215 public String toString() {
216 return String.format("SortOptions(limit=%d, matchScorer=%s, sortExpressions=%s)",
217 limit,
218 matchScorer,
219 sortExpressions);